From eb882569862bf3d149b5b86e32a882b3b554f5af Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sat, 18 Jun 2022 13:29:50 +0800 Subject: [PATCH 001/497] Revert "Codegen: preserve comments (#2297)" (#2324) This reverts commit 5375d2912d6ef26333cdc98de1c1819488a23066. --- codegen/bin/newcoin | 2 +- codegen/lib/entity_decl.rb | 5 +- codegen/lib/enum_decl.rb | 5 +- codegen/lib/function_decl.rb | 5 +- codegen/lib/parser.rb | 73 +++++++------------ codegen/lib/templates/java/class.erb | 11 --- codegen/lib/templates/java/enum.erb | 1 - codegen/lib/templates/java/header.erb | 2 +- codegen/lib/templates/java/struct.erb | 11 --- codegen/lib/templates/swift/class.erb | 2 - .../lib/templates/swift/class_properties.erb | 1 - codegen/lib/templates/swift/enum.erb | 1 - .../lib/templates/swift/enum_extension.erb | 2 +- codegen/lib/templates/swift/method.erb | 1 - codegen/lib/templates/swift/static_method.erb | 1 - codegen/lib/templates/swift/struct.erb | 2 - .../lib/templates/swift/struct_properties.erb | 1 - codegen/test/test_jni_helper.rb | 2 +- codegen/test/test_parser.rb | 6 +- include/TrustWalletCore/TWAES.h | 1 - 20 files changed, 38 insertions(+), 97 deletions(-) diff --git a/codegen/bin/newcoin b/codegen/bin/newcoin index 92ffef39977..e88e688cf35 100755 --- a/codegen/bin/newcoin +++ b/codegen/bin/newcoin @@ -104,7 +104,7 @@ puts "New coin template for coin '#{coin_id}' requested" json_string = File.read('registry.json') coins = JSON.parse(json_string).sort_by { |x| x['name'] } -entity = EntityDecl.new(name: "New" + coin_id, is_struct: false, comment: '') +entity = EntityDecl.new(name: "New" + coin_id, is_struct: false) file = "new"+ coin_id generator = CodeGenerator.new(entities: [entity], files: [file], output_folder: ".") diff --git a/codegen/lib/entity_decl.rb b/codegen/lib/entity_decl.rb index aee285ef97b..f22a0ea6587 100644 --- a/codegen/lib/entity_decl.rb +++ b/codegen/lib/entity_decl.rb @@ -2,17 +2,16 @@ # Class or struct declaration class EntityDecl - attr_reader :name, :comment + attr_reader :name attr_accessor :is_struct, :methods, :properties, :static_methods, :static_properties - def initialize(name:, is_struct:, comment:) + def initialize(name:, is_struct:) @name = name @is_struct = is_struct @methods = [] @properties = [] @static_methods = [] @static_properties = [] - @comment = comment end def struct? diff --git a/codegen/lib/enum_decl.rb b/codegen/lib/enum_decl.rb index 0fae5774f50..303909dec82 100644 --- a/codegen/lib/enum_decl.rb +++ b/codegen/lib/enum_decl.rb @@ -2,11 +2,11 @@ # Enum declaration. class EnumDecl - attr_reader :name, :comment + attr_reader :name attr_accessor :cases, :raw_type attr_accessor :methods, :properties, :static_methods, :static_properties - def initialize(name:, raw_type:, comment:) + def initialize(name:, raw_type:) @name = name @cases = [] @raw_type = raw_type @@ -14,7 +14,6 @@ def initialize(name:, raw_type:, comment:) @properties = [] @static_methods = [] @static_properties = [] - @comment = comment end def struct? diff --git a/codegen/lib/function_decl.rb b/codegen/lib/function_decl.rb index fd0a5c8311a..cd5135f1231 100644 --- a/codegen/lib/function_decl.rb +++ b/codegen/lib/function_decl.rb @@ -3,9 +3,9 @@ # Function or method declaration class FunctionDecl attr_reader :name, :entity - attr_accessor :is_method, :return_type, :parameters, :static, :discardable_result, :comment + attr_accessor :is_method, :return_type, :parameters, :static, :discardable_result - def initialize(name:, entity:, is_method:, return_type: :void, parameters: [], static: false, discardable_result: false, comment: '') + def initialize(name:, entity:, is_method:, return_type: :void, parameters: [], static: false, discardable_result: false) @name = name @entity = entity @is_method = is_method @@ -13,7 +13,6 @@ def initialize(name:, entity:, is_method:, return_type: :void, parameters: [], s @parameters = parameters @static = static @discardable_result = discardable_result - @comment = comment end end diff --git a/codegen/lib/parser.rb b/codegen/lib/parser.rb index afa2acfe1c4..fab69837507 100644 --- a/codegen/lib/parser.rb +++ b/codegen/lib/parser.rb @@ -9,7 +9,7 @@ # C header parser class Parser - attr_reader :path, :entity, :entity_comment + attr_reader :path, :entity def initialize(path:, string: nil) @path = path @@ -19,47 +19,32 @@ def initialize(path:, string: nil) # Parses a C header file for class/struct declarations def parse - clear_comment until @buffer.eos? - @buffer.skip(/\s*/) - - if !@buffer.scan(/\/\//).nil? - @entity_comment = @entity_comment + '//' + @buffer.scan_until(/(\r\n|\r|\n)/) - next - end + break if @buffer.skip_until(/\n/).nil? - if !@buffer.scan(/TW_EXTERN_C_BEGIN/).nil? - # This is to ignore very first comments from the file - clear_comment - next - end - # Look for TW_EXPORT statements - if !@buffer.scan(/TW_EXPORT_[A-Z_]+/).nil? - # Handle statements - case @buffer[0] - when 'TW_EXPORT_CLASS' - handle_class - when 'TW_EXPORT_STRUCT' - handle_struct - when 'TW_EXPORT_ENUM' - handle_enum - when 'TW_EXPORT_FUNC' - handle_func - when 'TW_EXPORT_METHOD' - handle_method - when 'TW_EXPORT_PROPERTY' - handle_property - when 'TW_EXPORT_STATIC_METHOD' - handle_static_method - when 'TW_EXPORT_STATIC_PROPERTY' - handle_static_property - end - - clear_comment + @buffer.skip(/\s*/) + next if @buffer.scan(/TW_EXPORT_[A-Z_]+/).nil? + + # Handle statements + case @buffer[0] + when 'TW_EXPORT_CLASS' + handle_class + when 'TW_EXPORT_STRUCT' + handle_struct + when 'TW_EXPORT_ENUM' + handle_enum + when 'TW_EXPORT_FUNC' + handle_func + when 'TW_EXPORT_METHOD' + handle_method + when 'TW_EXPORT_PROPERTY' + handle_property + when 'TW_EXPORT_STATIC_METHOD' + handle_static_method + when 'TW_EXPORT_STATIC_PROPERTY' + handle_static_property end - - break if @buffer.skip_until(/\n/).nil? end @entity @@ -95,7 +80,7 @@ def parse_func @buffer.skip(/\s*/) scan_or_fail(/\w+/, 'Invalid function name') - func = FunctionDecl.new(name: @buffer[0], entity: @entity, is_method: true, return_type: return_type, comment: @entity_comment) + func = FunctionDecl.new(name: @buffer[0], entity: @entity, is_method: true, return_type: return_type) @buffer.skip(/\s*/) scan_or_fail(/\(/, 'Invalid function declaration. Expected (') @@ -132,7 +117,7 @@ def handle_class @buffer.skip(/\s*/) report_error 'Invalid type name' if @buffer.scan(/struct TW(\w+)\s*;/).nil? report_error 'Found more than one class/struct in the same file' unless @entity.nil? - @entity = EntityDecl.new(name: @buffer[1], is_struct: false, comment: @entity_comment) + @entity = EntityDecl.new(name: @buffer[1], is_struct: false) puts "Found a class #{@entity.name}" end @@ -140,7 +125,7 @@ def handle_struct @buffer.skip(/\s*/) report_error 'Invalid type name at' if @buffer.scan(/struct TW(\w+)\s*\{?/).nil? report_error 'Found more than one class/struct in the same file' unless @entity.nil? - @entity = EntityDecl.new(name: @buffer[1], is_struct: true, comment: @entity_comment) + @entity = EntityDecl.new(name: @buffer[1], is_struct: true) puts "Found a struct #{@buffer[1]}" end @@ -151,7 +136,7 @@ def handle_enum @buffer.skip(/\s*/) report_error 'Invalid enum' if @buffer.scan(/enum TW(\w+)\s*\{/).nil? - @entity = EnumDecl.new(name: @buffer[1], raw_type: TypeDecl.fromPrimitive(type), comment: @entity_comment) + @entity = EnumDecl.new(name: @buffer[1], raw_type: TypeDecl.fromPrimitive(type)) incremental_value = 0 until @buffer.eos? @@ -292,8 +277,4 @@ def report_error(message) def current_line_number @buffer.string[0..@buffer.pos].count("\n") + 1 end - - def clear_comment - @entity_comment = '' - end end diff --git a/codegen/lib/templates/java/class.erb b/codegen/lib/templates/java/class.erb index b6e44d0d7d0..8f9d3367739 100644 --- a/codegen/lib/templates/java/class.erb +++ b/codegen/lib/templates/java/class.erb @@ -3,7 +3,6 @@ import java.util.HashSet; <% less = entity.static_methods.detect{ |i| i.name == 'Less' } -%> <% equal = entity.static_methods.detect{ |i| i.name == 'Equal' } -%> -<%= entity.comment %> <% if !less.nil? && !equal.nil? -%> public class <%= entity.name %> implements Comparable<<%= entity.name %>> { <% else -%> @@ -29,10 +28,8 @@ public class <%= entity.name %> { <%# Constructor declarations -%> <% entity.static_methods.each do |method| -%> <% next unless method.name.start_with?('Create') -%> - <%= method.comment %> static native long native<%= method.name %>(<%= JavaHelper.parameters(method.parameters) %>); <% end -%> - <%# Destructor declarations -%> <% entity.methods.each do |method| -%> <% next unless method.name.start_with?('Delete') -%> @@ -41,7 +38,6 @@ public class <%= entity.name %> { <%# Static property declarations -%> <% entity.static_properties.each do |property| -%> - <%= property.comment %> <% if should_return_data(property) -%> public static native byte[] <%= JavaHelper.format_name(property.name) %>(<%= JavaHelper.parameters(property.parameters) %>); <% elsif should_return_string(property) -%> @@ -50,11 +46,9 @@ public class <%= entity.name %> { public static native <%= JavaHelper.type(property.return_type) %> <%= JavaHelper.format_name(property.name) %>(<%= JavaHelper.parameters(property.parameters) %>); <% end -%> <% end -%> - <%# Static method declarations -%> <% entity.static_methods.each do |method| -%> <% next if method.name.start_with?('Create') -%> - <%= method.comment %> <% if should_return_data(method) -%> public static native byte[] <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters) %>); <% elsif should_return_string(method) -%> @@ -63,10 +57,8 @@ public class <%= entity.name %> { public static native <%= JavaHelper.type(method.return_type) %> <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters) %>); <% end -%> <% end -%> - <%# Property declarations -%> <% entity.properties.each do |property| -%> - <%= property.comment %> <% if should_return_data(property) -%> public native byte[] <%= JavaHelper.format_name(property.name) %>(<%= JavaHelper.parameters(property.parameters.drop(1)) %>); <% elsif should_return_string(property) -%> @@ -75,11 +67,9 @@ public class <%= entity.name %> { public native <%= JavaHelper.type(property.return_type) %> <%= JavaHelper.format_name(property.name) %>(<%= JavaHelper.parameters(property.parameters.drop(1)) %>); <% end -%> <% end -%> - <%# Method declarations -%> <% entity.methods.each do |method| -%> <% next if method.name.start_with?('Delete') -%> - <%= method.comment %> <% if should_return_data(method) -%> public native byte[] <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters.drop(1)) %>); <% elsif should_return_string(method) -%> @@ -96,7 +86,6 @@ public class <%= entity.name %> { <%# Constructors -%> <%- entity.static_methods.each do |method| -%> <%- next unless method.name.start_with?('Create') -%> - <%= method.comment %> public <%= entity.name %>(<%= JavaHelper.parameters(method.parameters) %>) { nativeHandle = native<%= method.name %>(<%= JavaHelper.arguments(method.parameters) %>); if (nativeHandle == 0) { diff --git a/codegen/lib/templates/java/enum.erb b/codegen/lib/templates/java/enum.erb index 354b7c145a3..27947182cc8 100644 --- a/codegen/lib/templates/java/enum.erb +++ b/codegen/lib/templates/java/enum.erb @@ -1,5 +1,4 @@ <% has_string = entity.cases.all? { |c| !c.string.nil? } -%> -<%= entity.comment %> <% type = entity.raw_type ? JavaHelper.type(entity.raw_type) : 'int' -%> public enum <%= entity.name %> { <%# Cases -%> diff --git a/codegen/lib/templates/java/header.erb b/codegen/lib/templates/java/header.erb index b1b1aeabc86..e596ae5e9fe 100644 --- a/codegen/lib/templates/java/header.erb +++ b/codegen/lib/templates/java/header.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2022 Trust Wallet. +// Copyright © 2017-2021 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/codegen/lib/templates/java/struct.erb b/codegen/lib/templates/java/struct.erb index 7c8b234d33b..5499705670d 100644 --- a/codegen/lib/templates/java/struct.erb +++ b/codegen/lib/templates/java/struct.erb @@ -2,7 +2,6 @@ import java.security.InvalidParameterException; <% less = entity.static_methods.detect{ |i| i.name == 'Less' } -%> <% equal = entity.static_methods.detect{ |i| i.name == 'Equal' } -%> -<%= entity.comment %> <% if !less.nil? && !equal.nil? -%> public class <%= entity.name %> implements Comparable<<%= entity.name %>> { <% else -%> @@ -22,52 +21,43 @@ public class <%= entity.name %> { <%# Constructor declarations -%> <%- entity.static_methods.each do |method| -%> <%- next unless method.name.start_with?('Init') -%> - <%= method.comment %> static native byte[] <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters.drop(1)) %>); <%- end -%> <%# Static property declarations -%> <%- entity.static_properties.each do |property| -%> - <%= property.comment %> <%- if should_return_data(property) -%> public static native byte[] <%= JavaHelper.format_name(property.name) %>(<%= JavaHelper.parameters(property.parameters) %>); <%- else -%> public static native <%= JavaHelper.type(property.return_type) %> <%= JavaHelper.format_name(property.name) %>(<%= JavaHelper.parameters(property.parameters) %>); <%- end -%> <%- end -%> - <%# Static method declarations -%> <%- entity.static_methods.each do |method| -%> <%- next if method.name.start_with?('Init') -%> - <%= method.comment %> <%- if should_return_data(method) -%> public static native byte[] <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters) %>); <%- else -%> public static native <%= JavaHelper.type(method.return_type) %> <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters) %>); <%- end -%> <%- end -%> - <%# Property declarations -%> <%- entity.properties.each do |property| -%> - <%= property.comment %> <%- if should_return_data(property) -%> public native byte[] <%= JavaHelper.format_name(property.name) %>(<%= JavaHelper.parameters(property.parameters.drop(1)) %>); <%- else -%> public native <%= JavaHelper.type(property.return_type) %> <%= JavaHelper.format_name(property.name) %>(<%= JavaHelper.parameters(property.parameters.drop(1)) %>); <%- end -%> <%- end -%> - <%# Method declarations -%> <%- entity.methods.each do |method| -%> <%- next if method.name.start_with?('Delete') -%> - <%= method.comment %> <%- if should_return_data(method) -%> public native byte[] <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters.drop(1)) %>); <%- else -%> public native <%= JavaHelper.type(method.return_type) %> <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters.drop(1)) %>); <%- end -%> <%- end -%> - <% if !less.nil? && !equal.nil? -%> <% compareMethod = JNIHelper.compareMethod(entity) -%> public native <%= JavaHelper.type(compareMethod.return_type) %> <%= JavaHelper.format_name(compareMethod.name) %>(<%= JavaHelper.parameters(compareMethod.parameters.drop(1)) %>); @@ -76,7 +66,6 @@ public class <%= entity.name %> { <%# Constructors -%> <%- entity.static_methods.each do |method| -%> <%- next unless method.name.start_with?('Init') -%> - <%= method.comment %> public <%= entity.name %>(<%= JavaHelper.parameters(method.parameters.drop(1)) %>) { bytes = <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.arguments(method.parameters.drop(1)) %>); if (bytes == null) { diff --git a/codegen/lib/templates/swift/class.erb b/codegen/lib/templates/swift/class.erb index 93b375de287..4d090e7bc70 100644 --- a/codegen/lib/templates/swift/class.erb +++ b/codegen/lib/templates/swift/class.erb @@ -1,11 +1,9 @@ import Foundation <% protocols = SwiftHelper.protocol(entity) -%> - <%= entity.comment %> public final class <%= entity.name %><% unless protocols.empty? %>: <%= protocols.join(', ') %><% end %> { <%# Static properties -%> <% entity.static_properties.each do |property| -%> - <%= property.comment %> public static var <%= SwiftHelper.format_name(property.name) %>: <%= SwiftHelper.type(property.return_type) %> { <%- if property.return_type.is_class || property.return_type.is_struct -%> return <%= SwiftHelper.type(property.return_type) %>(rawValue: TW<%= entity.name %><%= property.name %>()) diff --git a/codegen/lib/templates/swift/class_properties.erb b/codegen/lib/templates/swift/class_properties.erb index f68ff3fd0fa..c36feb40cb7 100644 --- a/codegen/lib/templates/swift/class_properties.erb +++ b/codegen/lib/templates/swift/class_properties.erb @@ -1,6 +1,5 @@ <%# Properties -%> <%- entity.properties.each do |property| -%> - <%= property.comment %> public var <%= SwiftHelper.format_name(property.name) %>: <%= SwiftHelper.type(property.return_type) %> { <%= render('swift/method_forward.erb', { method: property }) -%> } diff --git a/codegen/lib/templates/swift/enum.erb b/codegen/lib/templates/swift/enum.erb index 9b9f9ccdaf3..e54c283f148 100644 --- a/codegen/lib/templates/swift/enum.erb +++ b/codegen/lib/templates/swift/enum.erb @@ -1,5 +1,4 @@ <% has_string = entity.cases.all? { |c| !c.string.nil? } -%> - <%= entity.comment %> <% type = entity.raw_type ? SwiftHelper.type(entity.raw_type) : 'UInt32' -%> public enum <%= entity.name %>: <%= type %>, CaseIterable<% if has_string %>, CustomStringConvertible <% end %> { <%# Cases -%> diff --git a/codegen/lib/templates/swift/enum_extension.erb b/codegen/lib/templates/swift/enum_extension.erb index be672bb0e3b..133a6028953 100644 --- a/codegen/lib/templates/swift/enum_extension.erb +++ b/codegen/lib/templates/swift/enum_extension.erb @@ -1,7 +1,7 @@ extension <%= entity.name %> { <%# Properties -%> <%- entity.properties.each do |property| -%> - <%= property.comment %> + public var <%= SwiftHelper.format_name(property.name) %>: <%= SwiftHelper.type(property.return_type) %> { <%= render('swift/method_forward.erb', { method: property, arguments: ["TW#{entity.name}(rawValue: rawValue)"] }) -%> } diff --git a/codegen/lib/templates/swift/method.erb b/codegen/lib/templates/swift/method.erb index 75c63813259..d50b6a0629a 100644 --- a/codegen/lib/templates/swift/method.erb +++ b/codegen/lib/templates/swift/method.erb @@ -1,5 +1,4 @@ <% method = locals[:method] -%> - <%= method.comment %> <% arguments = locals[:arguments] || ['rawValue'] + SwiftHelper.arguments(method.parameters.drop(1)) -%> <% if method.discardable_result -%> @discardableResult diff --git a/codegen/lib/templates/swift/static_method.erb b/codegen/lib/templates/swift/static_method.erb index f0e04488d62..5a9638220cf 100644 --- a/codegen/lib/templates/swift/static_method.erb +++ b/codegen/lib/templates/swift/static_method.erb @@ -1,5 +1,4 @@ <% method = locals[:method] -%> - <%= method.comment %> <% arguments = SwiftHelper.arguments(method.parameters) -%> <% if method.discardable_result -%> @discardableResult diff --git a/codegen/lib/templates/swift/struct.erb b/codegen/lib/templates/swift/struct.erb index 27ab3a20462..e7c3b2ca7ea 100644 --- a/codegen/lib/templates/swift/struct.erb +++ b/codegen/lib/templates/swift/struct.erb @@ -1,11 +1,9 @@ import Foundation <% protocols = SwiftHelper.protocol(entity) -%> -<%= entity.comment %> public struct <%= entity.name %><% unless protocols.empty? %>: <%= protocols.join(', ') %><% end %> { <%# Static properties -%> <% entity.static_properties.each do |property| -%> - <%= property.comment %> public static var <%= SwiftHelper.format_name(property.name) %>: <%= SwiftHelper.type(property.return_type) %> { <%- if property.return_type.is_class || property.return_type.is_struct -%> return <%= SwiftHelper.type(property.return_type) %>(rawValue: TW<%= entity.name %><%= property.name %>()) diff --git a/codegen/lib/templates/swift/struct_properties.erb b/codegen/lib/templates/swift/struct_properties.erb index b20f49fc60d..ebd50de5629 100644 --- a/codegen/lib/templates/swift/struct_properties.erb +++ b/codegen/lib/templates/swift/struct_properties.erb @@ -1,7 +1,6 @@ <%# Properties -%> <%- entity.properties.each do |property| -%> - <%= property.comment %> public var <%= SwiftHelper.format_name(property.name) %>: <%= SwiftHelper.type(property.return_type) %> { <%= render('swift/method_forward.erb', { method: property }) -%> } diff --git a/codegen/test/test_jni_helper.rb b/codegen/test/test_jni_helper.rb index 595ff1e53e2..766c8dfdcf7 100644 --- a/codegen/test/test_jni_helper.rb +++ b/codegen/test/test_jni_helper.rb @@ -8,7 +8,7 @@ def test_format_name end def test_function_name - entity = EntityDecl.new(name: 'Test', is_struct: false, comment: '') + entity = EntityDecl.new(name: 'Test', is_struct: false) method = FunctionDecl.new(name: 'Function', entity: entity, is_method: true) name = JNIHelper.function_name(entity: entity, function: method) assert_equal(name, 'Java_wallet_core_jni_Test_function') diff --git a/codegen/test/test_parser.rb b/codegen/test/test_parser.rb index ba9677c2c5a..6f51a726695 100644 --- a/codegen/test/test_parser.rb +++ b/codegen/test/test_parser.rb @@ -44,26 +44,22 @@ def test_parse_invalid_method def test_parse_method_discardable_result parser = Parser.new(path: '', string: ' - // This is a sample file TW_EXTERN_C_BEGIN struct TWEthereumAbiFunction; - // Ethereuem ABI helpers TW_EXPORT_CLASS struct TWEthereumAbiEncoder; - // Encode function to Eth ABI binary + /// Encode function to Eth ABI binary TW_EXPORT_STATIC_METHOD TW_METHOD_DISCARDABLE_RESULT TWData*_Nonnull TWEthereumAbiEncoderEncode(struct TWEthereumAbiFunction *_Nonnull func_in); TW_EXTERN_C_END ') parser.parse - assert_equal(parser.entity.name, 'EthereumAbiEncoder') method = parser.entity.static_methods[0] assert_equal(method.return_type.name, :data) assert_equal(method.name, 'Encode') assert_equal(method.discardable_result, true) - assert_equal(method.comment, '// Encode function to Eth ABI binary' + "\n") end def test_init diff --git a/include/TrustWalletCore/TWAES.h b/include/TrustWalletCore/TWAES.h index 4b860df1a6e..510d2f32291 100644 --- a/include/TrustWalletCore/TWAES.h +++ b/include/TrustWalletCore/TWAES.h @@ -12,7 +12,6 @@ TW_EXTERN_C_BEGIN -/// AES encryption/decryption methods. TW_EXPORT_STRUCT struct TWAES { uint8_t unused; // C doesn't allow zero-sized struct From ee12d1f5d85d02f6ecafc86c8c37ba39b322331b Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sat, 18 Jun 2022 13:31:14 +0800 Subject: [PATCH 002/497] Fix encode type order (#2325) --- src/Ethereum/ABI/ParamFactory.cpp | 17 ++++ src/Ethereum/ABI/ParamFactory.h | 8 +- src/Ethereum/ABI/ParamStruct.cpp | 23 ++++- .../Tests/Blockchains/EthereumAbiTests.swift | 8 ++ tests/Ethereum/Data/seaport_712.json | 84 +++++++++++++++++++ 5 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 tests/Ethereum/Data/seaport_712.json diff --git a/src/Ethereum/ABI/ParamFactory.cpp b/src/Ethereum/ABI/ParamFactory.cpp index 49f98bdf63d..fbed6ce5f45 100644 --- a/src/Ethereum/ABI/ParamFactory.cpp +++ b/src/Ethereum/ABI/ParamFactory.cpp @@ -117,6 +117,23 @@ std::shared_ptr ParamFactory::makeNamed(const std::string& name, con return std::make_shared(name, param); } +bool ParamFactory::isPrimitive(const std::string& type) { + if (starts_with(type, "address")) { + return true; + } else if (starts_with(type, "uint")) { + return true; + } else if (starts_with(type, "int")) { + return true; + } else if (starts_with(type, "bool")) { + return true; + } else if (starts_with(type, "bytes")) { + return true; + } else if (starts_with(type, "string")) { + return true; + } + return false; +} + std::string ParamFactory::getValue(const std::shared_ptr& param, const std::string& type) { std::string result = ""; if (isArrayType(type)) { diff --git a/src/Ethereum/ABI/ParamFactory.h b/src/Ethereum/ABI/ParamFactory.h index 0133b6f1c8e..7ccdb948684 100644 --- a/src/Ethereum/ABI/ParamFactory.h +++ b/src/Ethereum/ABI/ParamFactory.h @@ -19,16 +19,18 @@ namespace TW::Ethereum::ABI { /// Factory creates concrete ParamBase class from string type. -class ParamFactory -{ +class ParamFactory { public: /// Create a param of given type static std::shared_ptr make(const std::string& type); /// Create a named param, with given name and type static std::shared_ptr makeNamed(const std::string& name, const std::string& type); + /// Check if given type is a primitive type + static bool isPrimitive(const std::string& type); static std::string getValue(const std::shared_ptr& param, const std::string& type); - static std::vector getArrayValue(const std::shared_ptr& param, const std::string& type); + static std::vector getArrayValue(const std::shared_ptr& param, + const std::string& type); }; } // namespace TW::Ethereum::ABI diff --git a/src/Ethereum/ABI/ParamStruct.cpp b/src/Ethereum/ABI/ParamStruct.cpp index c8d76d36029..124f7ec0e38 100644 --- a/src/Ethereum/ABI/ParamStruct.cpp +++ b/src/Ethereum/ABI/ParamStruct.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -71,8 +72,23 @@ Data ParamSetNamed::encodeHashes() const { std::string ParamSetNamed::getExtraTypes(std::vector& ignoreList) const { std::string types; - for (auto& p: _params) { - auto pType = p->_param->getType(); + + auto params = _params; + /// referenced struct type should be sorted by name see: https://eips.ethereum.org/EIPS/eip-712#definition-of-encodetype + std::stable_sort(params.begin(), params.end(), [](auto& a, auto& b) { + auto lhs = a->getType(); + auto rhs = b->getType(); + if (ParamFactory::isPrimitive(lhs)) { + return true; + } + if (ParamFactory::isPrimitive(rhs)) { + return true; + } + return lhs.compare(rhs) < 0; + }); + + for (auto& p: params) { + auto pType = p->_param->getType(); if (std::find(ignoreList.begin(), ignoreList.end(), pType) == ignoreList.end()) { types += p->getExtraTypes(ignoreList); ignoreList.push_back(pType); @@ -160,7 +176,8 @@ Data ParamStruct::hashStructJson(const std::string& messageJson) { message["message"].dump(), message["types"].dump()); if (messageStruct) { - TW::append(hashes, messageStruct->hashStruct()); + const auto messageHash = messageStruct->hashStruct(); + TW::append(hashes, messageHash); return Hash::keccak256(hashes); } } diff --git a/swift/Tests/Blockchains/EthereumAbiTests.swift b/swift/Tests/Blockchains/EthereumAbiTests.swift index 3edc89d55c2..a6a18430e5b 100644 --- a/swift/Tests/Blockchains/EthereumAbiTests.swift +++ b/swift/Tests/Blockchains/EthereumAbiTests.swift @@ -213,4 +213,12 @@ class EthereumAbiTests: XCTestCase { let hash = EthereumAbi.encodeTyped(messageJson: message) XCTAssertEqual(hash.hexString, "a85c2e2b118698e88db68a8105b794a8cc7cec074e89ef991cb4f5f533819cc2") } + + func testEncodeSeaportMessage() throws { + let url = Bundle(for: EthereumAbiTests.self).url(forResource: "seaport_712", withExtension: "json")! + let json = try String(contentsOf: url) + let hash = EthereumAbi.encodeTyped(messageJson: json) + + XCTAssertEqual(hash.hexString, "54140d99a864932cbc40fd8a2d1d1706c3923a79c183a3b151e929ac468064db") + } } diff --git a/tests/Ethereum/Data/seaport_712.json b/tests/Ethereum/Data/seaport_712.json new file mode 100644 index 00000000000..3a427db3584 --- /dev/null +++ b/tests/Ethereum/Data/seaport_712.json @@ -0,0 +1,84 @@ +{ + "types": { + "EIP712Domain": [ + { "name": "name", "type": "string" }, + { "name": "version", "type": "string" }, + { "name": "chainId", "type": "uint256" }, + { "name": "verifyingContract", "type": "address" } + ], + "OrderComponents": [ + { "name": "offerer", "type": "address" }, + { "name": "zone", "type": "address" }, + { "name": "offer", "type": "OfferItem[]" }, + { "name": "consideration", "type": "ConsiderationItem[]" }, + { "name": "orderType", "type": "uint8" }, + { "name": "startTime", "type": "uint256" }, + { "name": "endTime", "type": "uint256" }, + { "name": "zoneHash", "type": "bytes32" }, + { "name": "salt", "type": "uint256" }, + { "name": "conduitKey", "type": "bytes32" }, + { "name": "counter", "type": "uint256" } + ], + "OfferItem": [ + { "name": "itemType", "type": "uint8" }, + { "name": "token", "type": "address" }, + { "name": "identifierOrCriteria", "type": "uint256" }, + { "name": "startAmount", "type": "uint256" }, + { "name": "endAmount", "type": "uint256" } + ], + "ConsiderationItem": [ + { "name": "itemType", "type": "uint8" }, + { "name": "token", "type": "address" }, + { "name": "identifierOrCriteria", "type": "uint256" }, + { "name": "startAmount", "type": "uint256" }, + { "name": "endAmount", "type": "uint256" }, + { "name": "recipient", "type": "address" } + ] + }, + "primaryType": "OrderComponents", + "domain": { + "name": "Seaport", + "version": "1.1", + "chainId": "1", + "verifyingContract": "0x00000000006c3852cbEf3e08E8dF289169EdE581" + }, + "message": { + "offerer": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "offer": [ + { + "itemType": "2", + "token": "0x3F53082981815Ed8142384EDB1311025cA750Ef1", + "identifierOrCriteria": "134", + "startAmount": "1", + "endAmount": "1" + } + ], + "orderType": "2", + "consideration": [ + { + "itemType": "0", + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "975000000000000000", + "endAmount": "975000000000000000", + "recipient": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" + }, + { + "itemType": "0", + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "25000000000000000", + "endAmount": "25000000000000000", + "recipient": "0x8De9C5A032463C561423387a9648c5C7BCC5BC90" + } + ], + "startTime": "1655450129", + "endTime": "1658042129", + "zone": "0x004C00500000aD104D7DBd00e3ae0A5C00560C00", + "zoneHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "795459960395409", + "conduitKey": "0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000", + "totalOriginalConsiderationItems": "2", + "counter": "0" + } +} From 4938d2ec0dddf8a983d2906175ebbd5588a4b5bf Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sat, 18 Jun 2022 18:43:57 +0800 Subject: [PATCH 003/497] revert Gemfile for fastlane plugin (#2327) --- swift/Gemfile | 10 +++ swift/Gemfile.lock | 220 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 swift/Gemfile create mode 100644 swift/Gemfile.lock diff --git a/swift/Gemfile b/swift/Gemfile new file mode 100644 index 00000000000..b734015f820 --- /dev/null +++ b/swift/Gemfile @@ -0,0 +1,10 @@ +# Autogenerated by fastlane +# +# Ensure this file is checked in to source control! + +source "https://rubygems.org" + +gem 'fastlane' + +plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') +eval_gemfile(plugins_path) if File.exist?(plugins_path) diff --git a/swift/Gemfile.lock b/swift/Gemfile.lock new file mode 100644 index 00000000000..6005b99e515 --- /dev/null +++ b/swift/Gemfile.lock @@ -0,0 +1,220 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.5) + rexml + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + artifactory (3.0.15) + atomos (0.1.3) + aws-eventstream (1.2.0) + aws-partitions (1.600.0) + aws-sdk-core (3.131.1) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.525.0) + aws-sigv4 (~> 1.1) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.57.0) + aws-sdk-core (~> 3, >= 3.127.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.114.0) + aws-sdk-core (~> 3, >= 3.127.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.4) + aws-sigv4 (1.5.0) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + claide (1.1.0) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + declarative (0.0.20) + digest-crc (0.6.4) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.7.6) + emoji_regex (3.2.3) + excon (0.92.3) + faraday (1.10.0) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) + http-cookie (~> 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) + faraday (~> 1.0) + fastimage (2.2.6) + fastlane (2.206.2) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander (~> 4.6) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + json (< 3.0.0) + jwt (>= 2.1.0, < 3) + mini_magick (>= 4.9.4, < 5.0.0) + multipart-post (~> 2.0.0) + naturally (~> 2.2) + optparse (~> 0.1.1) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (>= 1.4.5, < 2.0.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + fastlane-plugin-create_xcframework (1.1.2) + gh_inspector (1.1.3) + google-apis-androidpublisher_v3 (0.22.0) + google-apis-core (>= 0.5, < 2.a) + google-apis-core (0.6.0) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.11.0) + google-apis-core (>= 0.5, < 2.a) + google-apis-playcustomapp_v1 (0.8.0) + google-apis-core (>= 0.5, < 2.a) + google-apis-storage_v1 (0.15.0) + google-apis-core (>= 0.5, < 2.a) + google-cloud-core (1.6.0) + google-cloud-env (~> 1.0) + google-cloud-errors (~> 1.0) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.2.0) + google-cloud-storage (1.36.2) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.1) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) + mini_mime (~> 1.0) + googleauth (1.1.3) + faraday (>= 0.17.3, < 3.a) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.5) + domain_name (~> 0.5) + httpclient (2.8.3) + jmespath (1.6.1) + json (2.6.2) + jwt (2.4.1) + memoist (0.16.2) + mini_magick (4.11.0) + mini_mime (1.1.2) + multi_json (1.15.0) + multipart-post (2.0.0) + nanaimo (0.3.0) + naturally (2.2.1) + optparse (0.1.1) + os (1.1.4) + plist (3.6.0) + public_suffix (4.0.7) + rake (13.0.6) + representable (3.2.0) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rexml (3.2.5) + rouge (2.0.7) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + security (0.1.3) + signet (0.16.1) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.0) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.8) + CFPropertyList + naturally + terminal-notifier (2.0.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.1) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.8.2) + unicode-display_width (1.8.0) + webrick (1.7.0) + word_wrap (1.0.0) + xcodeproj (1.21.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + ruby + +DEPENDENCIES + fastlane + fastlane-plugin-create_xcframework + +BUNDLED WITH + 2.1.4 From 7658ecb189824879701f69c7b339ff95bc98c0f0 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 21 Jun 2022 00:51:31 +0200 Subject: [PATCH 004/497] feat(btc_outpoint_format): apply clang fmt (#2317) --- src/Bitcoin/OutPoint.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Bitcoin/OutPoint.h b/src/Bitcoin/OutPoint.h index eb5e61f496d..8225eb9b4f9 100644 --- a/src/Bitcoin/OutPoint.h +++ b/src/Bitcoin/OutPoint.h @@ -17,21 +17,22 @@ namespace TW::Bitcoin { /// Bitcoin transaction out-point reference. class OutPoint { - public: +public: /// The hash of the referenced transaction. std::array hash; /// The index of the specific output in the transaction. uint32_t index; - /// Sequence number, matches sequence from Proto::OutPoint (not always used, see also TransactionInput.sequence) + /// Sequence number, matches sequence from Proto::OutPoint (not always used, see also + /// TransactionInput.sequence) uint32_t sequence; OutPoint() = default; /// Initializes an out-point reference with hash, index. template - OutPoint(const T& h, uint32_t index, uint32_t sequence = 0 ) { + OutPoint(const T& h, uint32_t index, uint32_t sequence = 0) { std::copy(std::begin(h), std::end(h), hash.begin()); this->index = index; this->sequence = sequence; From 9a4b4f9874dbcdfc9b3d83c3075d1fa7bd713678 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 21 Jun 2022 07:45:59 +0800 Subject: [PATCH 005/497] Fix binding symbol typo (#2330) --- wasm/src/AnySigner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wasm/src/AnySigner.cpp b/wasm/src/AnySigner.cpp index 557ce3494ea..cbddc1a8bf1 100644 --- a/wasm/src/AnySigner.cpp +++ b/wasm/src/AnySigner.cpp @@ -34,7 +34,7 @@ class AnySigner { } }; -EMSCRIPTEN_BINDINGS(Wasm_TWAnyAddress) { +EMSCRIPTEN_BINDINGS(Wasm_TWAnySigner) { class_("AnySigner") .class_function("sign", &AnySigner::sign) .class_function("plan", &AnySigner::plan) From 1a7084b54243dfe271db70856044600d4113ed46 Mon Sep 17 00:00:00 2001 From: wh Date: Tue, 21 Jun 2022 19:30:53 +0800 Subject: [PATCH 006/497] fix btg addressToData not correct (#2333) --- src/Bitcoin/Entry.cpp | 1 + tests/BitcoinGold/TWSegwitAddressTests.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/Bitcoin/Entry.cpp b/src/Bitcoin/Entry.cpp index 28f25c19ed2..1dfbccc261f 100644 --- a/src/Bitcoin/Entry.cpp +++ b/src/Bitcoin/Entry.cpp @@ -112,6 +112,7 @@ inline Data cashAddressToData(const CashAddress&& addr) { Data Entry::addressToData(TWCoinType coin, const std::string& address) const { switch (coin) { case TWCoinTypeBitcoin: + case TWCoinTypeBitcoinGold: case TWCoinTypeDigiByte: case TWCoinTypeGroestlcoin: case TWCoinTypeLitecoin: diff --git a/tests/BitcoinGold/TWSegwitAddressTests.cpp b/tests/BitcoinGold/TWSegwitAddressTests.cpp index 43d8826984c..b526c21a480 100644 --- a/tests/BitcoinGold/TWSegwitAddressTests.cpp +++ b/tests/BitcoinGold/TWSegwitAddressTests.cpp @@ -7,6 +7,7 @@ #include "../interface/TWTestUtilities.h" #include "Bitcoin/SegwitAddress.h" +#include "Coin.h" #include "PrivateKey.h" #include "PublicKey.h" #include "HexCoding.h" @@ -29,6 +30,12 @@ TEST(TWBitcoinGoldSegwitAddress, WitnessProgramToAddress) { ASSERT_EQ(address.string(), "btg1qtesn92ddy8m5yvypgsdtft3zj5qldj9g2u52sk"); } +/// Get address data from a Bech32 address +TEST(TWBitcoinGoldSegwitAddress, addressToData) { + auto data = TW::addressToData(TWCoinTypeBitcoinGold, "btg1qtesn92ddy8m5yvypgsdtft3zj5qldj9g2u52sk"); + ASSERT_EQ(hex(data), "5e6132a9ad21f7423081441ab4ae229501f6c8a8"); +} + /// Initializes a Bech32 address with a public key and a HRP prefix. TEST(TWBitcoinGoldSegwitAddress, PubkeyToAddress) { const auto publicKey = PublicKey(parse_hex("02f74712b5d765a73b52a14c1e113f2ef3f9502d09d5987ee40f53828cfe68b9a6"), TWPublicKeyTypeSECP256k1); From 92db28142687703792cd575e9b8b3f2c5615ac89 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 22 Jun 2022 08:33:02 +0200 Subject: [PATCH 007/497] feat(prefix_cpp20): bunch of prefix for cpp20 upgrade (#2336) --- src/Bitcoin/InputSelector.cpp | 1 + tests/algorithm/erase_tests.cpp | 6 ++---- trezor-crypto/CMakeLists.txt | 2 +- trezor-crypto/crypto/bignum.c | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Bitcoin/InputSelector.cpp b/src/Bitcoin/InputSelector.cpp index 97b34ff8603..17bd6ea1860 100644 --- a/src/Bitcoin/InputSelector.cpp +++ b/src/Bitcoin/InputSelector.cpp @@ -13,6 +13,7 @@ #include #include +#include using namespace TW; using namespace TW::Bitcoin; diff --git a/tests/algorithm/erase_tests.cpp b/tests/algorithm/erase_tests.cpp index 39a237e375a..42645f46757 100644 --- a/tests/algorithm/erase_tests.cpp +++ b/tests/algorithm/erase_tests.cpp @@ -9,13 +9,11 @@ #include "gtest/gtest.h" #include // std::iota -using namespace TW; - TEST(Algorithm, Erase) { std::vector cnt(10); std::iota(cnt.begin(), cnt.end(), '0'); cnt.back() = '3'; - std::size_t nbElementsErased = erase(cnt, '3'); + std::size_t nbElementsErased = TW::erase(cnt, '3'); ASSERT_EQ(cnt.size(), 8); ASSERT_EQ(nbElementsErased, 2); } @@ -23,7 +21,7 @@ TEST(Algorithm, Erase) { TEST(Algorithm, EraseIf) { std::vector cnt(10); std::iota(cnt.begin(), cnt.end(), '0'); - auto erased = erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; }); + auto erased = TW::erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; }); ASSERT_EQ(cnt.size(), 5); ASSERT_EQ(erased, 5); } \ No newline at end of file diff --git a/trezor-crypto/CMakeLists.txt b/trezor-crypto/CMakeLists.txt index 25360b7fec9..be1eaa6defe 100644 --- a/trezor-crypto/CMakeLists.txt +++ b/trezor-crypto/CMakeLists.txt @@ -69,7 +69,7 @@ else () endif() endif() -target_compile_options(TrezorCrypto PRIVATE ${TW_WARNING_FLAGS} -Werror) +target_compile_options(TrezorCrypto PRIVATE ${TW_WARNING_FLAGS} -Werror PUBLIC -Wno-deprecated-volatile) target_include_directories(TrezorCrypto PUBLIC diff --git a/trezor-crypto/crypto/bignum.c b/trezor-crypto/crypto/bignum.c index 73bf79bb9c9..85b8b0172e7 100644 --- a/trezor-crypto/crypto/bignum.c +++ b/trezor-crypto/crypto/bignum.c @@ -271,7 +271,7 @@ int bn_is_equal(const bignum256 *x, const bignum256 *y) { // &truecase == &falsecase or &res == &truecase == &falsecase void bn_cmov(bignum256 *res, volatile uint32_t cond, const bignum256 *truecase, const bignum256 *falsecase) { - assert((cond == 1) | (cond == 0)); + assert((int)(cond == 1) | (cond == 0)); uint32_t tmask = -cond; // tmask = 0xFFFFFFFF if cond else 0x00000000 uint32_t fmask = ~tmask; // fmask = 0x00000000 if cond else 0xFFFFFFFF @@ -290,7 +290,7 @@ void bn_cmov(bignum256 *res, volatile uint32_t cond, const bignum256 *truecase, // Assumes prime is normalized and // 0 < prime < 2**260 == 2**(BITS_PER_LIMB * LIMBS - 1) void bn_cnegate(volatile uint32_t cond, bignum256 *x, const bignum256 *prime) { - assert((cond == 1) | (cond == 0)); + assert((int)(cond == 1) | (cond == 0)); uint32_t tmask = -cond; // tmask = 0xFFFFFFFF if cond else 0x00000000 uint32_t fmask = ~tmask; // fmask = 0x00000000 if cond else 0xFFFFFFFF From cb02d7c7eca2fdd39d69a710a6536ee7e7523cb8 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 22 Jun 2022 19:16:04 +0200 Subject: [PATCH 008/497] [Improvements]: Bitcoin OutPoint (#2319) - noexcept - add equality_comparable.h / equality_comparable_tests.cpp for CRTP relational injections - use operator == is fine for std::array because internally it use std::equal and that take cares of the size too. - use RAII constructor style by integrating to_array constexpr template function - make the copy constructor call the constructor number 1 to avoid code repetition and enjoy RAII * fix(btc_outpoint_format): constexpr * feat(btc_outpoint): add new lines for new added files Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- src/Bitcoin/OutPoint.cpp | 2 +- src/Bitcoin/OutPoint.h | 33 +++++-------------- src/algorithm/to_array.h | 27 +++++++++++++++ src/operators/equality_comparable.h | 23 +++++++++++++ tests/algorithm/to_array_tests.cpp | 23 +++++++++++++ tests/operators/equality_comparable_tests.cpp | 21 ++++++++++++ 6 files changed, 103 insertions(+), 26 deletions(-) create mode 100644 src/algorithm/to_array.h create mode 100644 src/operators/equality_comparable.h create mode 100644 tests/algorithm/to_array_tests.cpp create mode 100644 tests/operators/equality_comparable_tests.cpp diff --git a/src/Bitcoin/OutPoint.cpp b/src/Bitcoin/OutPoint.cpp index 611c837003c..66013356772 100644 --- a/src/Bitcoin/OutPoint.cpp +++ b/src/Bitcoin/OutPoint.cpp @@ -10,7 +10,7 @@ using namespace TW::Bitcoin; -void OutPoint::encode(Data& data) const { +void OutPoint::encode(Data& data) const noexcept { std::copy(std::begin(hash), std::end(hash), std::back_inserter(data)); encode32LE(index, data); // sequence is encoded in TransactionInputs diff --git a/src/Bitcoin/OutPoint.h b/src/Bitcoin/OutPoint.h index 8225eb9b4f9..30fc6159adc 100644 --- a/src/Bitcoin/OutPoint.h +++ b/src/Bitcoin/OutPoint.h @@ -6,6 +6,7 @@ #pragma once +#include "algorithm/to_array.h" #include "../Data.h" #include "../proto/Bitcoin.pb.h" @@ -16,8 +17,7 @@ namespace TW::Bitcoin { /// Bitcoin transaction out-point reference. -class OutPoint { -public: +struct OutPoint { /// The hash of the referenced transaction. std::array hash; @@ -28,38 +28,21 @@ class OutPoint { /// TransactionInput.sequence) uint32_t sequence; - OutPoint() = default; + OutPoint() noexcept = default; /// Initializes an out-point reference with hash, index. template - OutPoint(const T& h, uint32_t index, uint32_t sequence = 0) { - std::copy(std::begin(h), std::end(h), hash.begin()); - this->index = index; - this->sequence = sequence; - } + OutPoint(const T& h, uint32_t index, uint32_t sequence = 0) noexcept + : hash(to_array<32, byte>(std::begin(h))), index(index), sequence(sequence) {} /// Initializes an out-point from a Protobuf out-point. - OutPoint(const Proto::OutPoint& other) { + OutPoint(const Proto::OutPoint& other) noexcept + : OutPoint(other.hash(), other.index(), other.sequence()) { assert(other.hash().size() == 32); - std::copy(other.hash().begin(), other.hash().end(), hash.begin()); - index = other.index(); - sequence = other.sequence(); } /// Encodes the out-point into the provided buffer. - void encode(Data& data) const; - - friend bool operator<(const OutPoint& a, const OutPoint& b) { - int cmp = std::memcmp(a.hash.data(), b.hash.data(), 32); - return cmp < 0 || (cmp == 0 && a.index < b.index); - } - - friend bool operator==(const OutPoint& a, const OutPoint& b) { - int cmp = std::memcmp(a.hash.data(), b.hash.data(), 32); - return (cmp == 0 && a.index == b.index); - } - - friend bool operator!=(const OutPoint& a, const OutPoint& b) { return !(a == b); } + void encode(Data& data) const noexcept; Proto::OutPoint proto() const { auto op = Proto::OutPoint(); diff --git a/src/algorithm/to_array.h b/src/algorithm/to_array.h new file mode 100644 index 00000000000..3201b2367db --- /dev/null +++ b/src/algorithm/to_array.h @@ -0,0 +1,27 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include //< std::array +#include //< std::size_t +#include //< std::is_same + +namespace TW { + +template +constexpr auto to_array(Iter& iter, std::index_sequence) -> std::array { + return {{((void)Is, T(*iter++))...}}; +} + +template ::value_type, + typename T = std::conditional_t{}, V, U>> +constexpr auto to_array(Iter iter) -> std::array { + return to_array(iter, std::make_index_sequence{}); +} + +} // namespace TW diff --git a/src/operators/equality_comparable.h b/src/operators/equality_comparable.h new file mode 100644 index 00000000000..aa2fd02f34b --- /dev/null +++ b/src/operators/equality_comparable.h @@ -0,0 +1,23 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +namespace TW::operators::details { + +template +class empty_base {}; + +} // namespace TW::operators::details + +namespace TW { + +template > +struct equality_comparable : B { + friend bool operator!=(const T& x, const T& y) { return !(x == y); } +}; + +} // namespace TW diff --git a/tests/algorithm/to_array_tests.cpp b/tests/algorithm/to_array_tests.cpp new file mode 100644 index 00000000000..f09ab617ece --- /dev/null +++ b/tests/algorithm/to_array_tests.cpp @@ -0,0 +1,23 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "algorithm/to_array.h" + +#include "gtest/gtest.h" + +using namespace TW; + +TEST(Algorithms, ToArray) { + std::string str{"foo"}; + auto value = TW::to_array<4, std::uint8_t>(begin(str)); + auto expected = std::array{"foo"}; + ASSERT_EQ(value, expected); + + std::vector ints{0, 1, 2}; + auto another_value = TW::to_array<3, std::uint8_t>(begin(ints)); + auto expected_ints = std::array{0, 1, 2}; + ASSERT_EQ(another_value, expected_ints); +} diff --git a/tests/operators/equality_comparable_tests.cpp b/tests/operators/equality_comparable_tests.cpp new file mode 100644 index 00000000000..37605b14dfd --- /dev/null +++ b/tests/operators/equality_comparable_tests.cpp @@ -0,0 +1,21 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "operators/equality_comparable.h" + +#include "gtest/gtest.h" + +using namespace TW; + +struct Amount : equality_comparable { + int value; + friend bool operator==(const Amount& lhs, const Amount& rhs) { return lhs.value == rhs.value; } +}; + +TEST(Operators, EqualityComparable) { + ASSERT_TRUE(Amount{.value = 1} != Amount{.value = 2}); + ASSERT_TRUE(Amount{.value = 1} == Amount{.value = 1}); +} From 027ec7630b80578dab541971a0496ec1307b50f5 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 23 Jun 2022 02:08:21 +0800 Subject: [PATCH 009/497] improve wasm sample html (#2332) --- samples/wasm/.gitignore | 2 ++ samples/wasm/README.md | 24 +++++++++++++++---- samples/wasm/{wallet-core.html => index.html} | 19 ++++++++++++--- wasm/.mocharc.json | 8 +++++++ wasm/index.ts | 5 ++-- wasm/package.json | 8 ++++--- wasm/tsconfig.json | 7 ++++-- 7 files changed, 57 insertions(+), 16 deletions(-) create mode 100644 samples/wasm/.gitignore rename samples/wasm/{wallet-core.html => index.html} (99%) create mode 100644 wasm/.mocharc.json diff --git a/samples/wasm/.gitignore b/samples/wasm/.gitignore new file mode 100644 index 00000000000..8fa7eb9d5df --- /dev/null +++ b/samples/wasm/.gitignore @@ -0,0 +1,2 @@ +*.js +*.wasm diff --git a/samples/wasm/README.md b/samples/wasm/README.md index 65e074b036f..263140c29af 100644 --- a/samples/wasm/README.md +++ b/samples/wasm/README.md @@ -1,8 +1,8 @@ -# Sample Wasm +# Wasm Sample ## DISCLAIMER -> This is a sample application with demonstration purpose only, +> This is a sample html for demonstration purpose only, > do not use it with real addresses, real transactions, or real funds. > Use it at your own risk. @@ -14,14 +14,28 @@ - - cmake - - run `tools/install-dependencies` if you just cloned this repo - - run `tools/install-wasm-dependencies` +3. node.js ## Building and Running - run `tools/generate-files` - run `tools/wasm-build` +- cd `wasm` +- - run `npm install` +- - run `npm run codegen:js-browser` +- - run `npm run copy:wasm-sample` +- cd `samples/wasm` - run `python3 -m http.server 8000` -- open web browser and navigate to `http://127.0.0.1:8000/samples/wasm/wallet-core.html` +- open web browser and navigate to `http://127.0.0.1:8000` -## React sample +## Notes -- https://github.com/robot-ux/wallet-core-example \ No newline at end of file +This sample also demonstrates how to use protobuf.js models in html directly, `core_proto.js` is built by command defined in `wasm/package.json` + +```shell +npm run codegen:js-browser +``` + +For modern javaScript sample, please check out: + +- React sample: https://github.com/robot-ux/wallet-core-example diff --git a/samples/wasm/wallet-core.html b/samples/wasm/index.html similarity index 99% rename from samples/wasm/wallet-core.html rename to samples/wasm/index.html index 881cb995399..13a6298ef1c 100644 --- a/samples/wasm/wallet-core.html +++ b/samples/wasm/index.html @@ -1299,8 +1299,21 @@ }; }; - + + + + - - diff --git a/wasm/.mocharc.json b/wasm/.mocharc.json new file mode 100644 index 00000000000..6a7296561e4 --- /dev/null +++ b/wasm/.mocharc.json @@ -0,0 +1,8 @@ +{ + "require": "ts-node/register", + "extensions": ["ts", "tsx"], + "spec":[ + "tests/*.test.ts", + "tests/**/*.test.*" + ] +} diff --git a/wasm/index.ts b/wasm/index.ts index cdf8b0ae229..8a5a24c3ad6 100644 --- a/wasm/index.ts +++ b/wasm/index.ts @@ -4,6 +4,5 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -import { TW } from "./generated/core_proto"; -import * as WalletCore from "./lib/wallet-core"; -export { TW, WalletCore }; +export { TW } from "./generated/core_proto"; +export * as WalletCore from "./lib/wallet-core"; diff --git a/wasm/package.json b/wasm/package.json index 58bede92848..c6642b071db 100644 --- a/wasm/package.json +++ b/wasm/package.json @@ -5,13 +5,15 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { - "test": "mocha -r ts-node/register tests/*.test.ts tests/**/*.test.ts", + "test": "mocha", "generate": "npm run codegen:js && npm run codegen:ts", "codegen:js": "pbjs -t static-module '../src/proto/*.proto' --no-delimited --force-long -o generated/core_proto.js", + "codegen:js-browser": "pbjs -t static-module '../src/proto/*.proto' -w closure --no-delimited --force-long -o ../samples/wasm/core_proto.js", "codegen:ts": "pbts -o generated/core_proto.d.ts generated/core_proto.js", "clean": "rm -rf dist generated && mkdir -p dist/generated generated", - "build": "npm run clean && npm run generate && cp -R generated lib dist && tsc --skipLibCheck", - "copy:wasm": "mkdir -p lib && cp ../wasm-build/wasm/wallet-core.* lib" + "build": "npm run clean && npm run generate && cp -R generated lib dist && tsc", + "copy:wasm": "mkdir -p lib && cp ../wasm-build/wasm/wallet-core.* lib", + "copy:wasm-sample": "cp ../wasm-build/wasm/wallet-core.* ../samples/wasm/" }, "repository": { "type": "git", diff --git a/wasm/tsconfig.json b/wasm/tsconfig.json index 808eaf5fc74..e86a48f1020 100644 --- a/wasm/tsconfig.json +++ b/wasm/tsconfig.json @@ -1,15 +1,18 @@ { "compilerOptions": { "target": "es5", - "module": "commonjs", + "module": "umd", + "moduleResolution": "node", "declaration": true, "outDir": "./dist", "strict": true, + "skipLibCheck": true, "typeRoots": [ "./node_modules/@types" ], "types": [ - "node" + "node", + "mocha" ], "noImplicitAny": false }, From 949b1e4c60c2b807b708971faffff93ace63d3d7 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 23 Jun 2022 07:08:25 +0200 Subject: [PATCH 010/497] fix(to_array): use std::copy in implementation of to_array (#2340) - some input collection may have a different size than the size of the array --- src/Bitcoin/OutPoint.h | 2 +- src/algorithm/to_array.h | 20 +++++++------------- tests/algorithm/to_array_tests.cpp | 4 ++-- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/Bitcoin/OutPoint.h b/src/Bitcoin/OutPoint.h index 30fc6159adc..89943b7b8a4 100644 --- a/src/Bitcoin/OutPoint.h +++ b/src/Bitcoin/OutPoint.h @@ -33,7 +33,7 @@ struct OutPoint { /// Initializes an out-point reference with hash, index. template OutPoint(const T& h, uint32_t index, uint32_t sequence = 0) noexcept - : hash(to_array<32, byte>(std::begin(h))), index(index), sequence(sequence) {} + : hash(to_array(h)), index(index), sequence(sequence) {} /// Initializes an out-point from a Protobuf out-point. OutPoint(const Proto::OutPoint& other) noexcept diff --git a/src/algorithm/to_array.h b/src/algorithm/to_array.h index 3201b2367db..9946f978551 100644 --- a/src/algorithm/to_array.h +++ b/src/algorithm/to_array.h @@ -6,22 +6,16 @@ #pragma once -#include //< std::array -#include //< std::size_t -#include //< std::is_same +#include //< std::copy +#include //< std::array namespace TW { -template -constexpr auto to_array(Iter& iter, std::index_sequence) -> std::array { - return {{((void)Is, T(*iter++))...}}; -} - -template ::value_type, - typename T = std::conditional_t{}, V, U>> -constexpr auto to_array(Iter iter) -> std::array { - return to_array(iter, std::make_index_sequence{}); +template +constexpr std::array to_array(Collection&& collection) { + std::array out{}; + std::copy(begin(collection), end(collection), out.begin()); + return out; } } // namespace TW diff --git a/tests/algorithm/to_array_tests.cpp b/tests/algorithm/to_array_tests.cpp index f09ab617ece..58d181ad663 100644 --- a/tests/algorithm/to_array_tests.cpp +++ b/tests/algorithm/to_array_tests.cpp @@ -12,12 +12,12 @@ using namespace TW; TEST(Algorithms, ToArray) { std::string str{"foo"}; - auto value = TW::to_array<4, std::uint8_t>(begin(str)); + auto value = TW::to_array(str); auto expected = std::array{"foo"}; ASSERT_EQ(value, expected); std::vector ints{0, 1, 2}; - auto another_value = TW::to_array<3, std::uint8_t>(begin(ints)); + auto another_value = TW::to_array(ints); auto expected_ints = std::array{0, 1, 2}; ASSERT_EQ(another_value, expected_ints); } From 9e9f2b20306856f2c7295de2dfc0895146be8e6f Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 23 Jun 2022 18:17:20 +0800 Subject: [PATCH 011/497] update various samples (#2341) --- Package.swift | 8 +- samples/android/app/build.gradle | 6 +- .../android/app/src/main/AndroidManifest.xml | 2 +- samples/android/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- samples/node/index.js | 17 ++ samples/node/package-lock.json | 217 ++++++++++++++++++ samples/node/package.json | 14 ++ samples/osx/cocoapods/Podfile.lock | 16 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 + 10 files changed, 274 insertions(+), 18 deletions(-) create mode 100755 samples/node/index.js create mode 100644 samples/node/package-lock.json create mode 100644 samples/node/package.json create mode 100644 samples/osx/cocoapods/WalletCoreExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Package.swift b/Package.swift index 5e1d49459d7..7da39e00a9d 100644 --- a/Package.swift +++ b/Package.swift @@ -12,13 +12,13 @@ let package = Package( targets: [ .binaryTarget( name: "WalletCore", - url: "https://github.com/trustwallet/wallet-core/releases/download/2.7.8/WalletCore.xcframework.zip", - checksum: "6f37b01f92fe76b0c97e31652c1756678ff84eb42009fd39b19f534eb9dc562e" + url: "https://github.com/trustwallet/wallet-core/releases/download/2.9.5/WalletCore.xcframework.zip", + checksum: "bb3bccd29e4f03c58bfa1fd746a0f8d6fc4ffc9ec2183beb4facd7b01974a9a2" ), .binaryTarget( name: "SwiftProtobuf", - url: "https://github.com/trustwallet/wallet-core/releases/download/2.7.8/SwiftProtobuf.xcframework.zip", - checksum: "a72a9e8191f1654114fbd2d9f6af3e777c5e3dffa06b2954f047bea1ee6cd529" + url: "https://github.com/trustwallet/wallet-core/releases/download/2.9.5/SwiftProtobuf.xcframework.zip", + checksum: "7903f5e9487db4764dc57be000c384a0619a96c275993711f3a5a858d3c865bd" ) ] ) diff --git a/samples/android/app/build.gradle b/samples/android/app/build.gradle index abe39291f50..f25cde25f75 100644 --- a/samples/android/app/build.gradle +++ b/samples/android/app/build.gradle @@ -5,11 +5,11 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' android { - compileSdkVersion 29 + compileSdkVersion 32 defaultConfig { applicationId "com.trust.walletcore.example" minSdkVersion 23 - targetSdkVersion 29 + targetSdkVersion 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -23,7 +23,7 @@ android { } project.ext { - walletcore_version = "2.6.16" + walletcore_version = "2.9.5" } dependencies { diff --git a/samples/android/app/src/main/AndroidManifest.xml b/samples/android/app/src/main/AndroidManifest.xml index 8cb737a9b5d..a198932f7df 100644 --- a/samples/android/app/src/main/AndroidManifest.xml +++ b/samples/android/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ android:supportsRtl="true" android:theme="@style/AppTheme" tools:ignore="GoogleAppIndexingWarning"> - + diff --git a/samples/android/build.gradle b/samples/android/build.gradle index ce4fc31295f..2ed2d65a3db 100644 --- a/samples/android/build.gradle +++ b/samples/android/build.gradle @@ -7,7 +7,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.2.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/samples/android/gradle/wrapper/gradle-wrapper.properties b/samples/android/gradle/wrapper/gradle-wrapper.properties index 98e52a713b4..87163a3434d 100644 --- a/samples/android/gradle/wrapper/gradle-wrapper.properties +++ b/samples/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip diff --git a/samples/node/index.js b/samples/node/index.js new file mode 100755 index 00000000000..c97ae2fb6a0 --- /dev/null +++ b/samples/node/index.js @@ -0,0 +1,17 @@ +#!/usr/bin/env node + +const { TW, WalletCore } = require('@trustwallet/wallet-core'); + +const sleep = async (milliseconds) => { + await new Promise(resolve => setTimeout(resolve, milliseconds)); +} + +(async function() { + await sleep(1000); + const { CoinType, HexCoding } = WalletCore; + + console.log(HexCoding.decode("0xce2fd7544e0b2cc94692d4a704debef7bcb61328")); + console.log(CoinType.ethereum.value); + console.log(TW); +})(); + diff --git a/samples/node/package-lock.json b/samples/node/package-lock.json new file mode 100644 index 00000000000..319d198c9f5 --- /dev/null +++ b/samples/node/package-lock.json @@ -0,0 +1,217 @@ +{ + "name": "node-sample", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "node-sample", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@trustwallet/wallet-core": "^2.9.5" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@trustwallet/wallet-core": { + "version": "2.9.5", + "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-2.9.5.tgz", + "integrity": "sha512-pb0huJUP34DqyxWslTrTW1SX0CZzpSINVonykwVvCk2Lc1pCJvbUPvrH+tMAkBGb5ytMuceuQ/KcvJ6KzmudBw==", + "dependencies": { + "protobufjs": ">=6.11.3" + } + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, + "node_modules/@types/node": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", + "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==" + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + } + }, + "dependencies": { + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "@trustwallet/wallet-core": { + "version": "2.9.5", + "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-2.9.5.tgz", + "integrity": "sha512-pb0huJUP34DqyxWslTrTW1SX0CZzpSINVonykwVvCk2Lc1pCJvbUPvrH+tMAkBGb5ytMuceuQ/KcvJ6KzmudBw==", + "requires": { + "protobufjs": ">=6.11.3" + } + }, + "@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, + "@types/node": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", + "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + } + } + } +} diff --git a/samples/node/package.json b/samples/node/package.json new file mode 100644 index 00000000000..38dbfdc1ca6 --- /dev/null +++ b/samples/node/package.json @@ -0,0 +1,14 @@ +{ + "name": "node-sample", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@trustwallet/wallet-core": "^2.9.5" + } +} diff --git a/samples/osx/cocoapods/Podfile.lock b/samples/osx/cocoapods/Podfile.lock index 796e8f34d88..6c8fa80e818 100644 --- a/samples/osx/cocoapods/Podfile.lock +++ b/samples/osx/cocoapods/Podfile.lock @@ -1,10 +1,10 @@ PODS: - - SwiftProtobuf (1.16.0) - - TrustWalletCore (2.6.7): - - TrustWalletCore/Core (= 2.6.7) - - TrustWalletCore/Core (2.6.7): + - SwiftProtobuf (1.19.0) + - TrustWalletCore (2.9.5): + - TrustWalletCore/Core (= 2.9.5) + - TrustWalletCore/Core (2.9.5): - TrustWalletCore/Types - - TrustWalletCore/Types (2.6.7): + - TrustWalletCore/Types (2.9.5): - SwiftProtobuf DEPENDENCIES: @@ -16,9 +16,9 @@ SPEC REPOS: - TrustWalletCore SPEC CHECKSUMS: - SwiftProtobuf: 4e16842b83c6fda06b10fac50d73b3f1fce8ab7b - TrustWalletCore: 1409475008901d761effd92fe6c3d6be6c83ae3a + SwiftProtobuf: 6ef3f0e422ef90d6605ca20b21a94f6c1324d6b3 + TrustWalletCore: 52ec9b10c17c8d7443e848ff0e6adac4d39be9f0 PODFILE CHECKSUM: 68848e868fc9571d319a35d139d7901079a7fe36 -COCOAPODS: 1.10.1 +COCOAPODS: 1.11.3 diff --git a/samples/osx/cocoapods/WalletCoreExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/samples/osx/cocoapods/WalletCoreExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000000..18d981003d6 --- /dev/null +++ b/samples/osx/cocoapods/WalletCoreExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 361642d7f7c10279852f34e21533759ef7070202 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 24 Jun 2022 13:01:18 +0800 Subject: [PATCH 012/497] Fix building derivationPath for xpub (#2339) * get uint32 coin from derivation, might be different for evm chains * cleanup --- include/TrustWalletCore/TWHDWallet.h | 29 +++++++++++++------- src/HDWallet.cpp | 10 ++++--- src/HDWallet.h | 22 ++++++++++++--- src/interface/TWHDWallet.cpp | 16 ++++++++--- swift/Tests/Blockchains/AvalancheTests.swift | 16 +++++++++++ tests/HDWallet/HDWalletTests.cpp | 9 +++--- tests/interface/TWHDWalletTests.cpp | 8 +++--- 7 files changed, 80 insertions(+), 30 deletions(-) diff --git a/include/TrustWalletCore/TWHDWallet.h b/include/TrustWalletCore/TWHDWallet.h index 35e4a87a069..1e52859422d 100644 --- a/include/TrustWalletCore/TWHDWallet.h +++ b/include/TrustWalletCore/TWHDWallet.h @@ -11,6 +11,7 @@ #include "TWCurve.h" #include "TWData.h" #include "TWHDVersion.h" +#include "TWDerivation.h" #include "TWPrivateKey.h" #include "TWPublicKey.h" #include "TWPurpose.h" @@ -59,11 +60,11 @@ TWString *_Nonnull TWHDWalletMnemonic(struct TWHDWallet *_Nonnull wallet); TW_EXPORT_PROPERTY TWData *_Nonnull TWHDWalletEntropy(struct TWHDWallet *_Nonnull wallet); -/// Returns master key. Returned object needs to be deleted. +/// Returns master key. Returned object needs to be deleted. TW_EXPORT_METHOD struct TWPrivateKey *_Nonnull TWHDWalletGetMasterKey(struct TWHDWallet *_Nonnull wallet, enum TWCurve curve); -/// Generates the default private key for the specified coin. Returned object needs to be deleted. +/// Generates the default private key for the specified coin. Returned object needs to be deleted. TW_EXPORT_METHOD struct TWPrivateKey *_Nonnull TWHDWalletGetKeyForCoin(struct TWHDWallet *_Nonnull wallet, enum TWCoinType coin); @@ -71,7 +72,7 @@ struct TWPrivateKey *_Nonnull TWHDWalletGetKeyForCoin(struct TWHDWallet *_Nonnul TW_EXPORT_METHOD TWString *_Nonnull TWHDWalletGetAddressForCoin(struct TWHDWallet *_Nonnull wallet, enum TWCoinType coin); -/// Generates the private key for the specified derivation path. Returned object needs to be deleted. +/// Generates the private key for the specified derivation path. Returned object needs to be deleted. TW_EXPORT_METHOD struct TWPrivateKey *_Nonnull TWHDWalletGetKey(struct TWHDWallet *_Nonnull wallet, enum TWCoinType coin, TWString *_Nonnull derivationPath); @@ -81,23 +82,31 @@ struct TWPrivateKey *_Nonnull TWHDWalletGetKey(struct TWHDWallet *_Nonnull walle TW_EXPORT_METHOD struct TWPrivateKey *_Nonnull TWHDWalletGetDerivedKey(struct TWHDWallet *_Nonnull wallet, enum TWCoinType coin, uint32_t account, uint32_t change, uint32_t address); -/// Returns the extended private key (for default 0 account). Returned object needs to be deleted. +/// Returns the extended private key (for default 0 account). Returned object needs to be deleted. TW_EXPORT_METHOD TWString *_Nonnull TWHDWalletGetExtendedPrivateKey(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWHDVersion version); -/// Returns the exteded public key (for default 0 account). Returned object needs to be deleted. +/// Returns the exteded public key (for default 0 account). Returned object needs to be deleted. TW_EXPORT_METHOD TWString *_Nonnull TWHDWalletGetExtendedPublicKey(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWHDVersion version); -/// Returns the extended private key, for custom account. Returned object needs to be deleted. +/// Returns the extended private key, for custom account. Returned object needs to be deleted. TW_EXPORT_METHOD -TWString *_Nonnull TWHDWalletGetExtendedPrivateKeyAccount(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWHDVersion version, uint32_t account); +TWString *_Nonnull TWHDWalletGetExtendedPrivateKeyAccount(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWDerivation derivation, enum TWHDVersion version, uint32_t account); -/// Returns the exteded public key, for custom account. Returned object needs to be deleted. +/// Returns the exteded public key, for custom account. Returned object needs to be deleted. TW_EXPORT_METHOD -TWString *_Nonnull TWHDWalletGetExtendedPublicKeyAccount(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWHDVersion version, uint32_t account); +TWString *_Nonnull TWHDWalletGetExtendedPublicKeyAccount(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWDerivation derivation, enum TWHDVersion version, uint32_t account); -/// Computes the public key from an exteded public key representation. Returned object needs to be deleted. +/// Returns the extended private key (for default 0 account with derivation). Returned object needs to be deleted. +TW_EXPORT_METHOD +TWString *_Nonnull TWHDWalletGetExtendedPrivateKeyDerivation(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWDerivation derivation, enum TWHDVersion version); + +/// Returns the exteded public key (for default 0 account with derivation). Returned object needs to be deleted. +TW_EXPORT_METHOD +TWString *_Nonnull TWHDWalletGetExtendedPublicKeyDerivation(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWDerivation derivation, enum TWHDVersion version); + +/// Computes the public key from an exteded public key representation. Returned object needs to be deleted. TW_EXPORT_STATIC_METHOD struct TWPublicKey *_Nullable TWHDWalletGetPublicKeyFromExtended(TWString *_Nonnull extended, enum TWCoinType coin, TWString *_Nonnull derivationPath); diff --git a/src/HDWallet.cpp b/src/HDWallet.cpp index b119517f7ac..be42f46f6e9 100644 --- a/src/HDWallet.cpp +++ b/src/HDWallet.cpp @@ -166,26 +166,28 @@ std::string HDWallet::deriveAddress(TWCoinType coin, TWDerivation derivation) co return TW::deriveAddress(coin, getKey(coin, derivationPath), derivation); } -std::string HDWallet::getExtendedPrivateKeyAccount(TWPurpose purpose, TWCoinType coin, TWHDVersion version, uint32_t account) const { +std::string HDWallet::getExtendedPrivateKeyAccount(TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version, uint32_t account) const { if (version == TWHDVersionNone) { return ""; } const auto curve = TWCoinTypeCurve(coin); - auto derivationPath = TW::DerivationPath({DerivationPathIndex(purpose, true), DerivationPathIndex(coin, true)}); + const auto path = TW::derivationPath(coin, derivation); + auto derivationPath = DerivationPath({DerivationPathIndex(purpose, true), DerivationPathIndex(path.coin(), true)}); auto node = getNode(*this, curve, derivationPath); auto fingerprintValue = fingerprint(&node, publicKeyHasher(coin)); hdnode_private_ckd(&node, account + 0x80000000); return serialize(&node, fingerprintValue, version, false, base58Hasher(coin)); } -std::string HDWallet::getExtendedPublicKeyAccount(TWPurpose purpose, TWCoinType coin, TWHDVersion version, uint32_t account) const { +std::string HDWallet::getExtendedPublicKeyAccount(TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version, uint32_t account) const { if (version == TWHDVersionNone) { return ""; } const auto curve = TWCoinTypeCurve(coin); - auto derivationPath = TW::DerivationPath({DerivationPathIndex(purpose, true), DerivationPathIndex(coin, true)}); + const auto path = TW::derivationPath(coin, derivation); + auto derivationPath = DerivationPath({DerivationPathIndex(purpose, true), DerivationPathIndex(path.coin(), true)}); auto node = getNode(*this, curve, derivationPath); auto fingerprintValue = fingerprint(&node, publicKeyHasher(coin)); hdnode_private_ckd(&node, account + 0x80000000); diff --git a/src/HDWallet.h b/src/HDWallet.h index 2ef846bcace..edeba904e99 100644 --- a/src/HDWallet.h +++ b/src/HDWallet.h @@ -87,17 +87,31 @@ class HDWallet { /// Derives the address for a coin with given derivation. std::string deriveAddress(TWCoinType coin, TWDerivation derivation) const; + /// Returns the extended private key for default 0 account with the given derivation. + std::string getExtendedPrivateKeyDerivation(TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version) const { + return getExtendedPrivateKeyAccount(purpose, coin, derivation, version, 0); + } + + /// Returns the extended public key for default 0 account with the given derivation. + std::string getExtendedPublicKeyDerivation(TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version) const { + return getExtendedPublicKeyAccount(purpose, coin, derivation, version, 0); + } + /// Returns the extended private key for default 0 account; derivation path used is "m/purpose'/coin'/0'". - std::string getExtendedPrivateKey(TWPurpose purpose, TWCoinType coin, TWHDVersion version) const { return getExtendedPrivateKeyAccount(purpose, coin, version, 0); } + std::string getExtendedPrivateKey(TWPurpose purpose, TWCoinType coin, TWHDVersion version) const { + return getExtendedPrivateKeyAccount(purpose, coin, TWDerivationDefault, version, 0); + } /// Returns the extended public key for default 0 account; derivation path used is "m/purpose'/coin'/0'". - std::string getExtendedPublicKey(TWPurpose purpose, TWCoinType coin, TWHDVersion version) const { return getExtendedPublicKeyAccount(purpose, coin, version, 0); } + std::string getExtendedPublicKey(TWPurpose purpose, TWCoinType coin, TWHDVersion version) const { + return getExtendedPublicKeyAccount(purpose, coin, TWDerivationDefault, version, 0); + } /// Returns the extended private key for a custom account; derivation path used is "m/purpose'/coin'/account'". - std::string getExtendedPrivateKeyAccount(TWPurpose purpose, TWCoinType coin, TWHDVersion version, uint32_t account) const; + std::string getExtendedPrivateKeyAccount(TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version, uint32_t account) const; /// Returns the extended public key for a custom account; derivation path used is "m/purpose'/coin'/account'". - std::string getExtendedPublicKeyAccount(TWPurpose purpose, TWCoinType coin, TWHDVersion version, uint32_t account) const; + std::string getExtendedPublicKeyAccount(TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version, uint32_t account) const; /// Returns the BIP32 Root Key (private) std::string getRootKey(TWCoinType coin, TWHDVersion version) const; diff --git a/src/interface/TWHDWallet.cpp b/src/interface/TWHDWallet.cpp index 7bdc6e2f232..8b8a38b79b5 100644 --- a/src/interface/TWHDWallet.cpp +++ b/src/interface/TWHDWallet.cpp @@ -97,12 +97,20 @@ TWString *_Nonnull TWHDWalletGetExtendedPublicKey(struct TWHDWallet *wallet, TWP return new std::string(wallet->impl.getExtendedPublicKey(purpose, coin, version)); } -TWString *_Nonnull TWHDWalletGetExtendedPrivateKeyAccount(struct TWHDWallet *wallet, TWPurpose purpose, TWCoinType coin, TWHDVersion version, uint32_t account) { - return new std::string(wallet->impl.getExtendedPrivateKeyAccount(purpose, coin, version, account)); +TWString *_Nonnull TWHDWalletGetExtendedPrivateKeyAccount(struct TWHDWallet *wallet, TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version, uint32_t account) { + return new std::string(wallet->impl.getExtendedPrivateKeyAccount(purpose, coin, derivation, version, account)); } -TWString *_Nonnull TWHDWalletGetExtendedPublicKeyAccount(struct TWHDWallet *wallet, TWPurpose purpose, TWCoinType coin, TWHDVersion version, uint32_t account) { - return new std::string(wallet->impl.getExtendedPublicKeyAccount(purpose, coin, version, account)); +TWString *_Nonnull TWHDWalletGetExtendedPublicKeyAccount(struct TWHDWallet *wallet, TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version, uint32_t account) { + return new std::string(wallet->impl.getExtendedPublicKeyAccount(purpose, coin, derivation, version, account)); +} + +TWString *_Nonnull TWHDWalletGetExtendedPrivateKeyDerivation(struct TWHDWallet *wallet, TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version) { + return new std::string(wallet->impl.getExtendedPrivateKeyDerivation(purpose, coin, derivation, version)); +} + +TWString *_Nonnull TWHDWalletGetExtendedPublicKeyDerivation(struct TWHDWallet *wallet, TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version) { + return new std::string(wallet->impl.getExtendedPublicKeyDerivation(purpose, coin, derivation, version)); } TWPublicKey *TWHDWalletGetPublicKeyFromExtended(TWString *_Nonnull extended, enum TWCoinType coin, TWString *_Nonnull derivationPath) { diff --git a/swift/Tests/Blockchains/AvalancheTests.swift b/swift/Tests/Blockchains/AvalancheTests.swift index 5f6d6bb595c..6e7b1a81c1d 100644 --- a/swift/Tests/Blockchains/AvalancheTests.swift +++ b/swift/Tests/Blockchains/AvalancheTests.swift @@ -18,4 +18,20 @@ class AvalancheTests: XCTestCase { XCTAssertEqual(address.description, addressETH.description) XCTAssertEqual(address.data.hexString, addressETH.data.hexString) } + + func testXPub() { + let wallet = HDWallet(mnemonic: "liquid spider narrow follow black west cabbage intact stadium resource gentle raccoon", passphrase: "")! + + let xpub1 = wallet.getExtendedPublicKey(purpose: .bip44, coin: .ethereum, version: .xpub) + let xpub2 = wallet.getExtendedPublicKey(purpose: .bip44, coin: .avalancheCChain, version: .xpub) + + XCTAssertEqual(xpub1, xpub2) + XCTAssertEqual(xpub2, "xpub6Bmo35QfCNvffj8tZsTVRvFxA5ULv2aHDV8dDCa7q6SzkMLJffxWRNE5vSJ4hANoKpmSp3p7Nbcp1vEz5F785HV4Aq2A6jWwHoyWp3EFgYp") + + let xpri1 = wallet.getExtendedPrivateKey(purpose: .bip44, coin: .ethereum, version: .xprv) + let xpri2 = wallet.getExtendedPrivateKey(purpose: .bip44, coin: .smartChain, version: .xprv) + + XCTAssertEqual(xpri1, xpri2) + XCTAssertEqual(xpri2, "xprv9xnSdZsmN1NNTF4RTqvV4nKDc3drWZrRrGD2QpAWGkv1sZ1A88eFsZuc59vKRr4mxJELH7C18ymaHENodYzEbeLq1JmPUAy3CmpA2inVCwo") + } } diff --git a/tests/HDWallet/HDWalletTests.cpp b/tests/HDWallet/HDWalletTests.cpp index fcf85eaa5e1..0756525ab9b 100644 --- a/tests/HDWallet/HDWalletTests.cpp +++ b/tests/HDWallet/HDWalletTests.cpp @@ -297,11 +297,11 @@ TEST(HDWallet, getExtendedPrivateKey) { EXPECT_EQ(extPubKey1, "zprvAcwsTZNaY1f7rfwsy5GseSDStYBrxwtsBZDkb3iyuQUs4NF6n58BuH7Xj54RuaSCWtU5CiQzuYQgFgqr1HokgKcVAeGeXokhJUAJeP3VmvY"); // explicitly specify default account=0 - const auto extPubKey2 = wallet.getExtendedPrivateKeyAccount(purpose, coin, hdVersion, 0); + const auto extPubKey2 = wallet.getExtendedPrivateKeyAccount(purpose, coin, TWDerivationDefault, hdVersion, 0); EXPECT_EQ(extPubKey2, "zprvAcwsTZNaY1f7rfwsy5GseSDStYBrxwtsBZDkb3iyuQUs4NF6n58BuH7Xj54RuaSCWtU5CiQzuYQgFgqr1HokgKcVAeGeXokhJUAJeP3VmvY"); // custom account=1 - const auto extPubKey3 = wallet.getExtendedPrivateKeyAccount(purpose, coin, hdVersion, 1); + const auto extPubKey3 = wallet.getExtendedPrivateKeyAccount(purpose, coin, TWDerivationDefault, hdVersion, 1); EXPECT_EQ(extPubKey3, "zprvAcwsTZNaY1f7sifgNNgdNa4P9mPtyg3zRVgwkx2qF9Sn7F255MzP6Zyumn6bgV5xuoS8ZrDvjzE7APcFSacXdzFYpGvyybb1bnAoh5nHxpn"); } @@ -310,17 +310,18 @@ TEST(HDWallet, getExtendedPublicKey) { const auto purpose = TWPurposeBIP44; const auto coin = TWCoinTypeBitcoin; const auto hdVersion = TWHDVersionZPUB; + const auto derivation = TWDerivationDefault; // default const auto extPubKey1 = wallet.getExtendedPublicKey(purpose, coin, hdVersion); EXPECT_EQ(extPubKey1, "zpub6qwDs4uUNPDR5A2M56ot1aABSa2MNQciYn9MPS8bTk1qwAaFKcSST5S1aLidvPp9twqpaumG7vikR2vHhBXjp5oGgHyMvWK3AtUkfeEgyns"); // explicitly specify default account=0 - const auto extPubKey2 = wallet.getExtendedPublicKeyAccount(purpose, coin, hdVersion, 0); + const auto extPubKey2 = wallet.getExtendedPublicKeyAccount(purpose, coin, derivation, hdVersion, 0); EXPECT_EQ(extPubKey2, "zpub6qwDs4uUNPDR5A2M56ot1aABSa2MNQciYn9MPS8bTk1qwAaFKcSST5S1aLidvPp9twqpaumG7vikR2vHhBXjp5oGgHyMvWK3AtUkfeEgyns"); // custom account=1 - const auto extPubKey3 = wallet.getExtendedPublicKeyAccount(purpose, coin, hdVersion, 1); + const auto extPubKey3 = wallet.getExtendedPublicKeyAccount(purpose, coin, derivation, hdVersion, 1); EXPECT_EQ(extPubKey3, "zpub6qwDs4uUNPDR6Ck9UQDdji17hoEPP8mqnicYZLSSoUykz3MDcuJdeNJPd3BozqEafeLZkegWqzAvkgA4JZZ5tTN2rDpGKfk54essyfx1eZP"); } diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp index acf63a99a26..099b3b377cf 100644 --- a/tests/interface/TWHDWalletTests.cpp +++ b/tests/interface/TWHDWalletTests.cpp @@ -327,14 +327,14 @@ TEST(HDWallet, ExtendedKeysCustomAccount) { auto words = STRING("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"); auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), STRING("").get())); - auto zprv0 = WRAPS(TWHDWalletGetExtendedPrivateKeyAccount(wallet.get(), TWPurposeBIP84, TWCoinTypeBitcoin, TWHDVersionZPRV, 0)); + auto zprv0 = WRAPS(TWHDWalletGetExtendedPrivateKeyAccount(wallet.get(), TWPurposeBIP84, TWCoinTypeBitcoin, TWDerivationBitcoinSegwit, TWHDVersionZPRV, 0)); assertStringsEqual(zprv0, "zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE"); - auto zprv1 = WRAPS(TWHDWalletGetExtendedPrivateKeyAccount(wallet.get(), TWPurposeBIP84, TWCoinTypeBitcoin, TWHDVersionZPRV, 1)); + auto zprv1 = WRAPS(TWHDWalletGetExtendedPrivateKeyAccount(wallet.get(), TWPurposeBIP84, TWCoinTypeBitcoin, TWDerivationBitcoinSegwit, TWHDVersionZPRV, 1)); assertStringsEqual(zprv1, "zprvAdG4iTXWBoAS2cCGuaGevCvH54GCunrvLJb2hoWCSuE3D9LS42XVg3c6sPm64w6VMq3w18vJf8nF3cBA2kUMkyWHsq6enWVXivzw42UrVHG"); - auto zpub0 = WRAPS(TWHDWalletGetExtendedPublicKeyAccount(wallet.get(), TWPurposeBIP84, TWCoinTypeBitcoin, TWHDVersionZPUB, 0)); + auto zpub0 = WRAPS(TWHDWalletGetExtendedPublicKeyAccount(wallet.get(), TWPurposeBIP84, TWCoinTypeBitcoin, TWDerivationBitcoinSegwit, TWHDVersionZPUB, 0)); assertStringsEqual(zpub0, "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs"); - auto zpub1 = WRAPS(TWHDWalletGetExtendedPublicKeyAccount(wallet.get(), TWPurposeBIP84, TWCoinTypeBitcoin, TWHDVersionZPUB, 1)); + auto zpub1 = WRAPS(TWHDWalletGetExtendedPublicKeyAccount(wallet.get(), TWPurposeBIP84, TWCoinTypeBitcoin, TWDerivationBitcoinSegwit, TWHDVersionZPUB, 1)); assertStringsEqual(zpub1, "zpub6rFR7y4Q2AijF6Gk1bofHLs1d66hKFamhXWdWBup1Em25wfabZqkDqvaieV63fDQFaYmaatCG7jVNUpUiM2hAMo6SAVHcrUpSnHDpNzucB7"); } From 5c2dbd2019f2215b40d1fcaa1767bcfe5459a742 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sat, 25 Jun 2022 09:49:41 +0900 Subject: [PATCH 013/497] Update README.md --- samples/wasm/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/wasm/README.md b/samples/wasm/README.md index 263140c29af..8b07630ba64 100644 --- a/samples/wasm/README.md +++ b/samples/wasm/README.md @@ -38,4 +38,5 @@ npm run codegen:js-browser For modern javaScript sample, please check out: -- React sample: https://github.com/robot-ux/wallet-core-example +- React: https://github.com/robot-ux/wallet-core-example +- Flutter: https://github.com/iampawan/Wallet-Core-Web/tree/dev From 720d89fa3469234909014509e18e77c613029cf5 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 6 Jul 2022 08:52:33 +0200 Subject: [PATCH 014/497] Revert InputSelector.cpp until further research (#2354) * fix(high_fees): revert InputSelector.cpp until further research * typo(input_selector): fix typo * use 3.1.14 emsdk Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- src/Bitcoin/InputSelector.cpp | 212 ++++++++++++++------------------ tools/install-wasm-dependencies | 5 +- 2 files changed, 96 insertions(+), 121 deletions(-) diff --git a/src/Bitcoin/InputSelector.cpp b/src/Bitcoin/InputSelector.cpp index 17bd6ea1860..22331773c5d 100644 --- a/src/Bitcoin/InputSelector.cpp +++ b/src/Bitcoin/InputSelector.cpp @@ -6,72 +6,43 @@ #include "InputSelector.h" -#include "NumericLiteral.h" #include "UTXO.h" -#include "algorithm/erase.h" -#include "algorithm/sort_copy.h" #include #include -#include using namespace TW; using namespace TW::Bitcoin; -using MaybeDust = std::optional; -using MaybeFee = std::optional; -using Inputs = std::vector; - -namespace details { - -struct FeeCalculatorArgs { - int64_t inputs; - int64_t outputs; - int64_t byteFee; -}; - -static inline int64_t distFrom2x(int64_t doubleTargetValue, int64_t val) noexcept { - return val > doubleTargetValue ? val - doubleTargetValue : doubleTargetValue - val; -} - template -static inline std::vector -selectOutDustElement(int64_t doubleTargetValue, MaybeDust dustThreshold, - const std::vector>& slices) noexcept { - if (dustThreshold.has_value()) { - const auto minFunctor = [doubleTargetValue](auto&& lhs, auto&& rhs) noexcept { - return details::distFrom2x(doubleTargetValue, InputSelector::sum(lhs)) < - details::distFrom2x(doubleTargetValue, InputSelector::sum(rhs)); - }; - const auto min = std::min_element(cbegin(slices), cend(slices), minFunctor); - return *min; +uint64_t InputSelector::sum(const std::vector& amounts) noexcept { + uint64_t sum = 0; + for (auto& i : amounts) { + sum += i.amount; } - return slices.front(); + return sum; } -static MaybeFee calculateTargetFee(const Inputs& maxWithXInputs, const FeeCalculator& feeCalculator, - FeeCalculatorArgs feeCalculatorArgs, int64_t targetValue, - MaybeDust dust = std::nullopt) noexcept { - auto&& [numInputs, numOutputs, byteFee] = feeCalculatorArgs; - const auto fee = feeCalculator.calculate(numInputs, numOutputs, byteFee); - auto targetFee = targetValue + fee; - if (dust) { - targetFee += *dust; - } - if (maxWithXInputs[numInputs] < targetFee) { - // no way to satisfy with only numInputs inputs, skip - return std::nullopt; - } - return std::make_optional(targetFee); +template +std::vector +InputSelector::filterOutDust(const std::vector& inputs, + int64_t byteFee) noexcept { + auto inputFeeLimit = static_cast(feeCalculator.calculateSingleInput(byteFee)); + return filterThreshold(inputs, inputFeeLimit); } -// Precompute maximum amount possible to obtain with given number of inputs +// Filters utxos that are dust template -static inline Inputs collectMaxWithXInputs(const std::vector& sorted) noexcept { - Inputs maxWithXInputs(sorted.size() + 1); - std::transform_inclusive_scan(crbegin(sorted), crend(sorted), next(begin(maxWithXInputs)), - std::plus<>{}, std::mem_fn(&TypeWithAmount::amount), uint64_t{}); - return maxWithXInputs; +std::vector +InputSelector::filterThreshold(const std::vector& inputs, + uint64_t minimumAmount) noexcept { + std::vector filtered; + for (auto& i : inputs) { + if (i.amount > minimumAmount) { + filtered.push_back(i); + } + } + return filtered; } // Slice Array @@ -81,43 +52,18 @@ static inline Inputs collectMaxWithXInputs(const std::vector& so // [7, 8, 9]] template static inline std::vector> -sliding(const std::vector& inputs, size_t sliceSize) noexcept { +slice(const std::vector& inputs, size_t sliceSize) { std::vector> slices; - auto&& [from, to] = std::make_pair(cbegin(inputs), cend(inputs) - sliceSize); - slices.reserve(std::distance(from, to)); - for (auto&& it = std::move(from); it <= to; ++it) { - slices.emplace_back(it, it + sliceSize); + for (auto i = 0; i <= inputs.size() - sliceSize; ++i) { + slices.emplace_back(); + slices[i].reserve(sliceSize); + for (auto j = i; j < i + sliceSize; j++) { + slices[i].push_back(inputs[j]); + } } return slices; } -} // namespace details - -template -uint64_t InputSelector::sum(const std::vector& amounts) noexcept { - auto accumulateFunctor = [](std::size_t sum, auto&& cur) noexcept { return sum + cur.amount; }; - return std::accumulate(cbegin(amounts), cend(amounts), 0_uz, accumulateFunctor); -} - -template -std::vector -InputSelector::filterOutDust(const std::vector& inputsIn, - int64_t byteFee) noexcept { - auto inputFeeLimit = static_cast(feeCalculator.calculateSingleInput(byteFee)); - return filterThreshold(inputsIn, inputFeeLimit); -} - -// Filters utxos that are dust -template -std::vector -InputSelector::filterThreshold(const std::vector& inputsIn, - uint64_t minimumAmount) noexcept { - std::vector filtered; - auto copyFunctor = [minimumAmount](auto&& cur) noexcept { return cur.amount > minimumAmount; }; - std::copy_if(cbegin(inputsIn), cend(inputsIn), std::back_inserter(filtered), copyFunctor); - return filtered; -} - template std::vector InputSelector::select(int64_t targetValue, int64_t byteFee, int64_t numOutputs) { @@ -132,56 +78,81 @@ InputSelector::select(int64_t targetValue, int64_t byteFee, int6 } assert(inputs.size() >= 1); + // definitions for the following caluculation + const auto doubleTargetValue = targetValue * 2; + // Get all possible utxo selections up to a maximum size, sort by total amount, increasing - const auto sortFunctor = [](auto&& l, auto&& r) noexcept { return l.amount < r.amount; }; - const auto sorted = sortCopy(inputs, sortFunctor); + std::vector sorted = inputs; + std::sort(sorted.begin(), sorted.end(), + [](const TypeWithAmount& lhs, const TypeWithAmount& rhs) { + return lhs.amount < rhs.amount; + }); + + // Precompute maximum amount possible to obtain with given number of inputs const auto n = sorted.size(); - const auto maxWithXInputs = details::collectMaxWithXInputs(sorted); + std::vector maxWithXInputs = std::vector(); + maxWithXInputs.push_back(0); + int64_t maxSum = 0; + for (auto i = 0; i < n; ++i) { + maxSum += sorted[n - 1 - i].amount; + maxWithXInputs.push_back(maxSum); + } - auto sliceFunctor = [&sorted](int64_t numInputs, int64_t targetFee) noexcept { - auto slices = details::sliding(sorted, static_cast(numInputs)); - auto eraseFunctor = [targetFee](auto&& slice) noexcept { return sum(slice) < targetFee; }; - erase_if(slices, eraseFunctor); - return slices; + // difference from 2x targetValue + auto distFrom2x = [doubleTargetValue](int64_t val) -> int64_t { + if (val > doubleTargetValue) { + return val - doubleTargetValue; + } + return doubleTargetValue - val; }; - auto selectFunctor = - [numOutputs, byteFee, &maxWithXInputs, targetValue, &sliceFunctor, - this](int64_t numInputs, MaybeDust dustThreshold = std::nullopt) noexcept - -> std::optional> { - auto feeArgs = details::FeeCalculatorArgs{ - .inputs = numInputs, .outputs = numOutputs, .byteFee = byteFee}; - auto maybeTargetFee = details::calculateTargetFee(maxWithXInputs, feeCalculator, - feeArgs, targetValue, dustThreshold); - if (maybeTargetFee) { - auto slices = sliceFunctor(numInputs, *maybeTargetFee); - if (!slices.empty()) { - const auto doubleTargetValue = targetValue * 2; - const auto filteredInputs = filterOutDust( - details::selectOutDustElement(doubleTargetValue, dustThreshold, slices), - byteFee); - return std::make_optional(filteredInputs); - } - } - return std::nullopt; - }; - const int64_t dustThreshold = feeCalculator.calculateSingleInput(byteFee); // 1. Find a combination of the fewest inputs that is // (1) bigger than what we need // (2) closer to 2x the amount, // (3) and does not produce dust change. - for (int64_t numInputs = 1; numInputs <= n; ++numInputs) { - if (auto selected = selectFunctor(numInputs, dustThreshold); selected) { - return *selected; + for (size_t numInputs = 1; numInputs <= n; ++numInputs) { + const auto fee = feeCalculator.calculate(numInputs, numOutputs, byteFee); + const auto targetWithFeeAndDust = targetValue + fee + dustThreshold; + if (maxWithXInputs[numInputs] < targetWithFeeAndDust) { + // no way to satisfy with only numInputs inputs, skip + continue; + } + auto slices = slice(sorted, static_cast(numInputs)); + + slices.erase( + std::remove_if(slices.begin(), slices.end(), + [targetWithFeeAndDust](const std::vector& slice) { + return sum(slice) < targetWithFeeAndDust; + }), + slices.end()); + if (!slices.empty()) { + std::sort(slices.begin(), slices.end(), + [distFrom2x](const std::vector& lhs, + const std::vector& rhs) { + return distFrom2x(sum(lhs)) < distFrom2x(sum(rhs)); + }); + return filterOutDust(slices.front(), byteFee); } } // 2. If not, find a valid combination of outputs even if they produce dust change. - for (int64_t numInputs = 1; numInputs <= n; ++numInputs) { - if (auto selected = selectFunctor(numInputs); selected) { - return *selected; + for (size_t numInputs = 1; numInputs <= n; ++numInputs) { + const auto fee = feeCalculator.calculate(numInputs, numOutputs, byteFee); + const auto targetWithFee = targetValue + fee; + if (maxWithXInputs[numInputs] < targetWithFee) { + // no way to satisfy with only numInputs inputs, skip + continue; + } + auto slices = slice(sorted, static_cast(numInputs)); + slices.erase(std::remove_if(slices.begin(), slices.end(), + [targetWithFee](const std::vector& slice) { + return sum(slice) < targetWithFee; + }), + slices.end()); + if (!slices.empty()) { + return filterOutDust(slices.front(), byteFee); } } @@ -199,6 +170,7 @@ std::vector InputSelector::selectSimple(int64_t if (inputs.empty()) { return {}; } + assert(inputs.size() >= 1); // target value is larger that original, but not by a factor of 2 (optimized for large UTXO // cases) @@ -211,11 +183,11 @@ std::vector InputSelector::selectSimple(int64_t // Go through inputs in a single pass, in the order they appear, no optimization uint64_t sum = 0; std::vector selected; - for (auto&& input : inputs) { + for (auto& input : inputs) { if (input.amount <= dustThreshold) { continue; // skip dust } - selected.emplace_back(input); + selected.push_back(input); sum += input.amount; if (sum >= increasedTargetValue) { // we have enough diff --git a/tools/install-wasm-dependencies b/tools/install-wasm-dependencies index d70cb692d70..915f901e120 100755 --- a/tools/install-wasm-dependencies +++ b/tools/install-wasm-dependencies @@ -2,11 +2,14 @@ set -e +emsdk_version=3.1.14 + git clone https://github.com/emscripten-core/emsdk.git cd emsdk -./emsdk install latest && ./emsdk activate latest + +./emsdk install $emsdk_version && ./emsdk activate $emsdk_version curl -fSsOL https://github.com/emscripten-ports/boost/releases/download/boost-1.75.0/boost-headers-1.75.0.zip unzip boost-headers-1.75.0.zip -d upstream/emscripten/system/include From 2af3c94c4852ee623d02f156569f36cda866d2d6 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 8 Jul 2022 12:01:57 +0200 Subject: [PATCH 015/497] feat(kava_evm): add kava evm (#2358) - Update TWCoinType.h - Add tests in cpp/swift/kt --- .../blockchains/CoinAddressDerivationTests.kt | 2 +- docs/registry.md | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 28 ++++++++++++++ swift/Tests/CoinAddressDerivationTests.swift | 1 + tests/KavaEvm/TWCoinTypeTests.cpp | 37 +++++++++++++++++++ 6 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 tests/KavaEvm/TWCoinTypeTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 41cf2644572..709a4563545 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -42,7 +42,7 @@ class CoinAddressDerivationTests { DIGIBYTE -> assertEquals("dgb1qtjgmerfqwdffyf8ghcrkgy52cghsqptynmyswu", address) ETHEREUM, SMARTCHAIN, POLYGON, OPTIMISM, ARBITRUM, ECOCHAIN, AVALANCHECCHAIN, XDAI, FANTOM, CELO, CRONOSCHAIN, SMARTBITCOINCASH, KUCOINCOMMUNITYCHAIN, BOBA, METIS, - AURORA, EVMOS, MOONRIVER, MOONBEAM, KLAYTN -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address) + AURORA, EVMOS, MOONRIVER, MOONBEAM, KAVAEVM, KLAYTN -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address) RONIN -> assertEquals("ronin:8f348F300873Fd5DA36950B2aC75a26584584feE", address) ETHEREUMCLASSIC -> assertEquals("0x078bA3228F3E6C08bEEac9A005de0b7e7089aD1c", address) GOCHAIN -> assertEquals("0x5940ce4A14210d4Ccd0ac206CE92F21828016aC2", address) diff --git a/docs/registry.md b/docs/registry.md index 192cbfe7486..8af3b2df2cf 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -81,6 +81,7 @@ This list is generated from [./registry.json](../registry.json) | 10001284 | Moonbeam | GLMR | | | | 10001285 | Moonriver | MOVR | | | | 10002020 | Ronin | RON | | | +| 10002222 | KavaEvm | KAVA | | | | 10008217 | Klaytn | KLAY | | | | 10009000 | Avalanche C-Chain | AVAX | | | | 10009001 | Evmos | EVMOS | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 64d2d38f018..2e045cfc6ad 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -108,6 +108,7 @@ enum TWCoinType { TWCoinTypeNativeEvmos = 20009001, TWCoinTypeMoonriver = 10001285, TWCoinTypeMoonbeam = 10001284, + TWCoinTypeKavaEvm = 10002222, TWCoinTypeKlaytn = 10008217, }; diff --git a/registry.json b/registry.json index bfd72132808..a0186dabd4d 100644 --- a/registry.json +++ b/registry.json @@ -2277,6 +2277,34 @@ "clientDocs": "https://eth.wiki/json-rpc/API" } }, + { + "id": "kavaevm", + "name": "KavaEvm", + "coinId": 10002222, + "symbol": "KAVA", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "2222", + "addressHasher": "keccak256", + "explorer": { + "url": "https://explorer.kava.io", + "txPath": "/tx/", + "accountPath": "/address/" + }, + "info": { + "url": "https://www.kava.io/", + "client": "https://github.com/Kava-Labs/kava", + "documentation": "https://docs.kava.io/docs/ethereum/overview/", + "rpc": "https://evm.kava.io" + } + }, { "id": "smartbch", "name": "Smart Bitcoin Cash", diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 1c932aa79bd..6493c35e65b 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -89,6 +89,7 @@ class CoinAddressDerivationTests: XCTestCase { .evmos, .moonriver, .moonbeam, + .kavaEvm, .klaytn: let expectedResult = "0x8f348F300873Fd5DA36950B2aC75a26584584feE" assertCoinDerivation(coin, expectedResult, derivedAddress, address) diff --git a/tests/KavaEvm/TWCoinTypeTests.cpp b/tests/KavaEvm/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..70b1d91b97c --- /dev/null +++ b/tests/KavaEvm/TWCoinTypeTests.cpp @@ -0,0 +1,37 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "../interface/TWTestUtilities.h" +#include +#include + + +TEST(TWKavaEvmCoinType, TWCoinType) { + const auto coin = TWCoinTypeKavaEvm; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto chainId = WRAPS(TWCoinTypeChainId(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("0xa999bd5183568ba178795e6a9d1561566fbf4a9ccc813cc475168832bc4909b3")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0xF92d3DB0d9f912f285b1ec69578A6201A78487d7")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "kavaevm"); + assertStringsEqual(name, "KavaEvm"); + assertStringsEqual(symbol, "KAVA"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 18); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainEthereum); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); + assertStringsEqual(chainId, "2222"); + assertStringsEqual(txUrl, "https://explorer.kava.io/tx/0xa999bd5183568ba178795e6a9d1561566fbf4a9ccc813cc475168832bc4909b3"); + assertStringsEqual(accUrl, "https://explorer.kava.io/address/0xF92d3DB0d9f912f285b1ec69578A6201A78487d7"); +} From 19b86f09c2e0f66dcb73f64365f779c7be9c683a Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 8 Jul 2022 12:02:52 +0200 Subject: [PATCH 016/497] feat(avax_c_chain): update explorer to snowtrace (#2361) --- registry.json | 2 +- tests/Avalanche/TWCoinTypeTests.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/registry.json b/registry.json index a0186dabd4d..3797f5d8fa3 100644 --- a/registry.json +++ b/registry.json @@ -2017,7 +2017,7 @@ "chainId": "43114", "addressHasher": "keccak256", "explorer": { - "url": "https://cchain.explorer.avax.network", + "url": "https://snowtrace.io", "txPath": "/tx/", "accountPath": "/address/", "sampleTx": "0x9243890b844219accefd8798271052f5a056453ec18984a56e81c92921330d54", diff --git a/tests/Avalanche/TWCoinTypeTests.cpp b/tests/Avalanche/TWCoinTypeTests.cpp index 49220a3a60b..f9b1aa72576 100644 --- a/tests/Avalanche/TWCoinTypeTests.cpp +++ b/tests/Avalanche/TWCoinTypeTests.cpp @@ -27,8 +27,8 @@ TEST(TWAvalancheCoinType, TWCoinTypeCChain) { ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeAvalancheCChain)); ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeAvalancheCChain)); assertStringsEqual(symbol, "AVAX"); - assertStringsEqual(txUrl, "https://cchain.explorer.avax.network/tx/0x9243890b844219accefd8798271052f5a056453ec18984a56e81c92921330d54"); - assertStringsEqual(accUrl, "https://cchain.explorer.avax.network/address/0xa664325f36Ec33E66323fe2620AF3f2294b2Ef3A"); + assertStringsEqual(txUrl, "https://snowtrace.io/tx/0x9243890b844219accefd8798271052f5a056453ec18984a56e81c92921330d54"); + assertStringsEqual(accUrl, "https://snowtrace.io/address/0xa664325f36Ec33E66323fe2620AF3f2294b2Ef3A"); assertStringsEqual(id, "avalanchec"); assertStringsEqual(name, "Avalanche C-Chain"); } From 0eb8fc1b5c042896904e450351def5c743b03281 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sat, 9 Jul 2022 11:45:39 +0800 Subject: [PATCH 017/497] add set -o pipefail (#2362) --- tools/ios-xcframework-release | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ios-xcframework-release b/tools/ios-xcframework-release index 168f0c4c74c..61b41de44d5 100755 --- a/tools/ios-xcframework-release +++ b/tools/ios-xcframework-release @@ -1,5 +1,6 @@ #!/bin/bash +set -o pipefail set -e # load release library code From c91bb4ea4851dc0db4686cbcf3ea2624a53ce639 Mon Sep 17 00:00:00 2001 From: Sean Chao Date: Sat, 9 Jul 2022 11:46:20 +0800 Subject: [PATCH 018/497] add Meter chain support (#2357) * add Meter chain support * update copyright year and apply `const` in test var --- .../blockchains/CoinAddressDerivationTests.kt | 2 +- docs/registry.md | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 29 ++++++++++++++++ swift/Tests/CoinAddressDerivationTests.swift | 3 +- tests/Meter/TWCoinTypeTests.cpp | 34 +++++++++++++++++++ 6 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 tests/Meter/TWCoinTypeTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 709a4563545..59e5cf16ea6 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -42,7 +42,7 @@ class CoinAddressDerivationTests { DIGIBYTE -> assertEquals("dgb1qtjgmerfqwdffyf8ghcrkgy52cghsqptynmyswu", address) ETHEREUM, SMARTCHAIN, POLYGON, OPTIMISM, ARBITRUM, ECOCHAIN, AVALANCHECCHAIN, XDAI, FANTOM, CELO, CRONOSCHAIN, SMARTBITCOINCASH, KUCOINCOMMUNITYCHAIN, BOBA, METIS, - AURORA, EVMOS, MOONRIVER, MOONBEAM, KAVAEVM, KLAYTN -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address) + AURORA, EVMOS, MOONRIVER, MOONBEAM, KAVAEVM, KLAYTN, METER -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address) RONIN -> assertEquals("ronin:8f348F300873Fd5DA36950B2aC75a26584584feE", address) ETHEREUMCLASSIC -> assertEquals("0x078bA3228F3E6C08bEEac9A005de0b7e7089aD1c", address) GOCHAIN -> assertEquals("0x5940ce4A14210d4Ccd0ac206CE92F21828016aC2", address) diff --git a/docs/registry.md b/docs/registry.md index 8af3b2df2cf..6e4cfe5ae5d 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -64,6 +64,7 @@ This list is generated from [./registry.json](../registry.json) | 2718 | Nebulas | NAS | | | | 6060 | GoChain | GO | | | | 8964 | NULS | NULS | | | +| 18000 | Meter | MTR | | | | 19167 | Flux | FLUX | | | | 52752 | Celo | CELO | | | | 5718350 | Wanchain | WAN | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 2e045cfc6ad..6fdcea797b8 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -110,6 +110,7 @@ enum TWCoinType { TWCoinTypeMoonbeam = 10001284, TWCoinTypeKavaEvm = 10002222, TWCoinTypeKlaytn = 10008217, + TWCoinTypeMeter = 18000, }; /// Returns the blockchain for a coin type. diff --git a/registry.json b/registry.json index 3797f5d8fa3..114de52a3b7 100644 --- a/registry.json +++ b/registry.json @@ -2598,5 +2598,34 @@ "rpc": "https://public-node-api.klaytnapi.com/v1/cypress", "documentation": "https://docs.klaytn.foundation" } + }, + { + "id": "meter", + "name": "Meter", + "coinId": 18000, + "chainId": "82", + "symbol": "MTR", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "explorer": { + "url": "https://scan.meter.io", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0x8ea268d5dbb40217c763b800a75fc063cf28b56f40f2bc69dc043f5c4bbdc144", + "sampleAccount": "0xe5a273954d24eddf9ae9ea4cef2347d584cfa3dd" + }, + "info": { + "url": "https://meter.io/", + "source": "https://github.com/meterio/meter-pov", + "rpc": "https://rpc.meter.io", + "documentation": "https://docs.meter.io/" + } } ] \ No newline at end of file diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 6493c35e65b..0fed0294bc1 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -90,7 +90,8 @@ class CoinAddressDerivationTests: XCTestCase { .moonriver, .moonbeam, .kavaEvm, - .klaytn: + .klaytn, + .meter: let expectedResult = "0x8f348F300873Fd5DA36950B2aC75a26584584feE" assertCoinDerivation(coin, expectedResult, derivedAddress, address) case .ronin: diff --git a/tests/Meter/TWCoinTypeTests.cpp b/tests/Meter/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..50902798e57 --- /dev/null +++ b/tests/Meter/TWCoinTypeTests.cpp @@ -0,0 +1,34 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "../interface/TWTestUtilities.h" +#include +#include + + +TEST(TWMeterCoinType, TWCoinType) { + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeMeter)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("0x8ea268d5dbb40217c763b800a75fc063cf28b56f40f2bc69dc043f5c4bbdc144")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeMeter, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0xe5a273954d24eddf9ae9ea4cef2347d584cfa3dd")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeMeter, accId.get())); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeMeter)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeMeter)); + + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeMeter), 18); + ASSERT_EQ(TWBlockchainEthereum, TWCoinTypeBlockchain(TWCoinTypeMeter)); + ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeMeter)); + ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeMeter)); + assertStringsEqual(symbol, "MTR"); + assertStringsEqual(txUrl, "https://scan.meter.io/tx/0x8ea268d5dbb40217c763b800a75fc063cf28b56f40f2bc69dc043f5c4bbdc144"); + assertStringsEqual(accUrl, "https://scan.meter.io/address/0xe5a273954d24eddf9ae9ea4cef2347d584cfa3dd"); + assertStringsEqual(id, "meter"); + assertStringsEqual(name, "Meter"); +} From 85689efa8c0467f784c9c3dcee5cff9809c800bf Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 11 Jul 2022 05:07:08 +0200 Subject: [PATCH 019/497] Fix Non-void return type missing warnings (#2356) * format(code): apply clang format - apply clang format on Transaction.cpp, StoredKey.cpp, Extrinsic.cpp and PublicKey.cpp * fix(non_void_functions): apply fixes from #2351 * tweak ColumnLimit * add comments Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- .clang-format | 2 +- src/Bitcoin/Transaction.cpp | 29 +++-- src/Keystore/StoredKey.cpp | 132 +++++++++---------- src/Polkadot/Extrinsic.cpp | 247 +++++++++++++++++------------------- src/PublicKey.cpp | 34 ++--- 5 files changed, 215 insertions(+), 229 deletions(-) diff --git a/.clang-format b/.clang-format index 686111529a9..c3a9fa31eb5 100644 --- a/.clang-format +++ b/.clang-format @@ -3,7 +3,7 @@ AllowShortFunctionsOnASingleLine: Inline AlwaysBreakTemplateDeclarations: Yes BasedOnStyle: LLVM BreakConstructorInitializers: BeforeComma -ColumnLimit: 100 +ColumnLimit: 0 ConstructorInitializerAllOnOneLineOrOnePerLine: true IndentWidth: 4 IndentAccessModifiers: false diff --git a/src/Bitcoin/Transaction.cpp b/src/Bitcoin/Transaction.cpp index 8e9b3f5c5c3..c5fd33f1afa 100644 --- a/src/Bitcoin/Transaction.cpp +++ b/src/Bitcoin/Transaction.cpp @@ -4,12 +4,12 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "SegwitAddress.h" #include "Transaction.h" +#include "SegwitAddress.h" #include "SigHashType.h" #include "../BinaryCoding.h" -#include "../Hash.h" #include "../Data.h" +#include "../Hash.h" #include "SignatureVersion.h" @@ -36,8 +36,8 @@ Data Transaction::getPreImage(const Script& scriptCode, size_t index, } // Input nSequence (none/all, depending on flags) - if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) == 0 && - !hashTypeIsSingle(hashType) && !hashTypeIsNone(hashType)) { + if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) == 0 && !hashTypeIsSingle(hashType) && + !hashTypeIsNone(hashType)) { auto hashSequence = getSequenceHash(); std::copy(std::begin(hashSequence), std::end(hashSequence), std::back_inserter(data)); } else { @@ -106,9 +106,15 @@ Data Transaction::getOutputsHash() const { void Transaction::encode(Data& data, enum SegwitFormatMode segwitFormat) const { bool useWitnessFormat = true; switch (segwitFormat) { - case NonSegwit: useWitnessFormat = false; break; - case IfHasWitness: useWitnessFormat = hasWitness(); break; - case Segwit: useWitnessFormat = true; break; + case NonSegwit: + useWitnessFormat = false; + break; + case IfHasWitness: + useWitnessFormat = hasWitness(); + break; + case Segwit: + useWitnessFormat = true; + break; } encode32LE(version, data); @@ -145,18 +151,17 @@ void Transaction::encodeWitness(Data& data) const { } bool Transaction::hasWitness() const { - return std::any_of(inputs.begin(), inputs.end(), [](auto& input) { return !input.scriptWitness.empty(); }); + return std::any_of(inputs.begin(), inputs.end(), [](auto& input) { return !input.scriptWitness.empty(); }); } Data Transaction::getSignatureHash(const Script& scriptCode, size_t index, enum TWBitcoinSigHashType hashType, uint64_t amount, enum SignatureVersion version) const { - switch (version) { - case BASE: + if (version == BASE) { return getSignatureHashBase(scriptCode, index, hashType); - case WITNESS_V0: - return getSignatureHashWitnessV0(scriptCode, index, hashType, amount); } + // version == WITNESS_V0 + return getSignatureHashWitnessV0(scriptCode, index, hashType, amount); } /// Generates the signature hash for Witness version 0 scripts. diff --git a/src/Keystore/StoredKey.cpp b/src/Keystore/StoredKey.cpp index 11b92034efb..9546ef6c76f 100644 --- a/src/Keystore/StoredKey.cpp +++ b/src/Keystore/StoredKey.cpp @@ -19,11 +19,11 @@ #include #include +#include #include #include #include #include -#include using namespace TW; using namespace TW::Keystore; @@ -32,10 +32,9 @@ StoredKey StoredKey::createWithMnemonic(const std::string& name, const Data& pas if (!Mnemonic::isValid(mnemonic)) { throw std::invalid_argument("Invalid mnemonic"); } - + Data mnemonicData = TW::Data(mnemonic.begin(), mnemonic.end()); - StoredKey key = StoredKey(StoredKeyType::mnemonicPhrase, name, password, mnemonicData, encryptionLevel); - return key; + return StoredKey(StoredKeyType::mnemonicPhrase, name, password, mnemonicData, encryptionLevel); } StoredKey StoredKey::createWithMnemonicRandom(const std::string& name, const Data& password, TWStoredKeyEncryptionLevel encryptionLevel) { @@ -43,8 +42,7 @@ StoredKey StoredKey::createWithMnemonicRandom(const std::string& name, const Dat const auto& mnemonic = wallet.getMnemonic(); assert(Mnemonic::isValid(mnemonic)); Data mnemonicData = TW::Data(mnemonic.begin(), mnemonic.end()); - StoredKey key = StoredKey(StoredKeyType::mnemonicPhrase, name, password, mnemonicData, encryptionLevel); - return key; + return StoredKey(StoredKeyType::mnemonicPhrase, name, password, mnemonicData, encryptionLevel); } StoredKey StoredKey::createWithMnemonicAddDefaultAddress(const std::string& name, const Data& password, const std::string& mnemonic, TWCoinType coin) { @@ -55,8 +53,7 @@ StoredKey StoredKey::createWithMnemonicAddDefaultAddress(const std::string& name } StoredKey StoredKey::createWithPrivateKey(const std::string& name, const Data& password, const Data& privateKeyData) { - StoredKey key = StoredKey(StoredKeyType::privateKey, name, password, privateKeyData, TWStoredKeyEncryptionLevelDefault); - return key; + return StoredKey(StoredKeyType::privateKey, name, password, privateKeyData, TWStoredKeyEncryptionLevelDefault); } StoredKey StoredKey::createWithPrivateKeyAddDefaultAddress(const std::string& name, const Data& password, TWCoinType coin, const Data& privateKeyData) { @@ -93,7 +90,7 @@ const HDWallet StoredKey::wallet(const Data& password) const { std::vector StoredKey::getAccounts(TWCoinType coin) const { std::vector result; - for (auto& account: accounts) { + for (auto& account : accounts) { if (account.coin == coin) { result.push_back(account); } @@ -112,7 +109,7 @@ std::optional StoredKey::getDefaultAccount(TWCoinType coin, const HDWal } // no wallet or not found, rely on derivation=0 condition const auto coinAccounts = getAccounts(coin); - for (auto& account: coinAccounts) { + for (auto& account : coinAccounts) { if (account.derivation == TWDerivationDefault) { return account; } @@ -219,8 +216,7 @@ void StoredKey::addAccount( TWDerivation derivation, const DerivationPath& derivationPath, const std::string& publicKey, - const std::string& extendedPublicKey -) { + const std::string& extendedPublicKey) { if (getAccount(coin, address).has_value()) { // address already present return; @@ -229,21 +225,25 @@ void StoredKey::addAccount( } void StoredKey::removeAccount(TWCoinType coin) { - accounts.erase(std::remove_if(accounts.begin(), accounts.end(), [coin](Account& account) -> bool { - return account.coin == coin; - }), accounts.end()); + accounts.erase( + std::remove_if(accounts.begin(), accounts.end(), [coin](Account& account) -> bool { return account.coin == coin; }), + accounts.end()); } void StoredKey::removeAccount(TWCoinType coin, TWDerivation derivation) { - accounts.erase(std::remove_if(accounts.begin(), accounts.end(), [coin, derivation](Account& account) -> bool { - return account.coin == coin && account.derivation == derivation; - }), accounts.end()); + accounts.erase( + std::remove_if(accounts.begin(), accounts.end(), [coin, derivation](Account& account) -> bool { + return account.coin == coin && account.derivation == derivation; + }), + accounts.end()); } void StoredKey::removeAccount(TWCoinType coin, DerivationPath derivationPath) { - accounts.erase(std::remove_if(accounts.begin(), accounts.end(), [coin, derivationPath](Account& account) -> bool { - return account.coin == coin && account.derivationPath == derivationPath; - }), accounts.end()); + accounts.erase( + std::remove_if(accounts.begin(), accounts.end(), [coin, derivationPath](Account& account) -> bool { + return account.coin == coin && account.derivationPath == derivationPath; + }), + accounts.end()); } const PrivateKey StoredKey::privateKey(TWCoinType coin, const Data& password) { @@ -251,56 +251,47 @@ const PrivateKey StoredKey::privateKey(TWCoinType coin, const Data& password) { } const PrivateKey StoredKey::privateKey(TWCoinType coin, TWDerivation derivation, const Data& password) { - switch (type) { - case StoredKeyType::mnemonicPhrase: { + if (type == StoredKeyType::mnemonicPhrase) { const auto wallet = this->wallet(password); const auto account = this->account(coin, &wallet); return wallet.getKey(coin, account->derivationPath); } - case StoredKeyType::privateKey: - return PrivateKey(payload.decrypt(password)); - } + // type == StoredKeyType::privateKey + return PrivateKey(payload.decrypt(password)); } void StoredKey::fixAddresses(const Data& password) { switch (type) { - case StoredKeyType::mnemonicPhrase: { - const auto wallet = this->wallet(password); - for (auto& account : accounts) { - if (!account.address.empty() && - !account.publicKey.empty() && - TW::validateAddress(account.coin, account.address) - ) { - continue; - } - const auto& derivationPath = account.derivationPath; - const auto key = wallet.getKey(account.coin, derivationPath); - const auto pubKey = key.getPublicKey(TW::publicKeyType(account.coin)); - account.address = TW::deriveAddress(account.coin, pubKey, account.derivation); - account.publicKey = hex(pubKey.bytes); - } + case StoredKeyType::mnemonicPhrase: { + const auto wallet = this->wallet(password); + for (auto& account : accounts) { + if (!account.address.empty() && !account.publicKey.empty() && + TW::validateAddress(account.coin, account.address)) { + continue; } - break; - - case StoredKeyType::privateKey: { - auto key = PrivateKey(payload.decrypt(password)); - for (auto& account : accounts) { - if (!account.address.empty() && - !account.publicKey.empty() && - TW::validateAddress(account.coin, account.address) - ) { - continue; - } - const auto pubKey = key.getPublicKey(TW::publicKeyType(account.coin)); - account.address = TW::deriveAddress(account.coin, pubKey, account.derivation); - account.publicKey = hex(pubKey.bytes); - } + const auto& derivationPath = account.derivationPath; + const auto key = wallet.getKey(account.coin, derivationPath); + const auto pubKey = key.getPublicKey(TW::publicKeyType(account.coin)); + account.address = TW::deriveAddress(account.coin, pubKey, account.derivation); + account.publicKey = hex(pubKey.bytes); + } + } break; + + case StoredKeyType::privateKey: { + auto key = PrivateKey(payload.decrypt(password)); + for (auto& account : accounts) { + if (!account.address.empty() && !account.publicKey.empty() && + TW::validateAddress(account.coin, account.address)) { + continue; } - break; + const auto pubKey = key.getPublicKey(TW::publicKeyType(account.coin)); + account.address = TW::deriveAddress(account.coin, pubKey, account.derivation); + account.publicKey = hex(pubKey.bytes); + } + } break; } } - // ----------------- // Encoding/Decoding // ----------------- @@ -312,23 +303,23 @@ StoredKey StoredKey::createWithJson(const nlohmann::json& json) { } namespace CodingKeys { - static const auto address = "address"; - static const auto type = "type"; - static const auto name = "name"; - static const auto id = "id"; - static const auto crypto = "crypto"; - static const auto activeAccounts = "activeAccounts"; - static const auto version = "version"; - static const auto coin = "coin"; +static const auto address = "address"; +static const auto type = "type"; +static const auto name = "name"; +static const auto id = "id"; +static const auto crypto = "crypto"; +static const auto activeAccounts = "activeAccounts"; +static const auto version = "version"; +static const auto coin = "coin"; } // namespace CodingKeys namespace UppercaseCodingKeys { - static const auto crypto = "Crypto"; +static const auto crypto = "Crypto"; } // namespace UppercaseCodingKeys namespace TypeString { - static const auto privateKey = "private-key"; - static const auto mnemonic = "mnemonic"; +static const auto privateKey = "private-key"; +static const auto mnemonic = "mnemonic"; } // namespace TypeString void StoredKey::loadJson(const nlohmann::json& json) { @@ -363,7 +354,8 @@ void StoredKey::loadJson(const nlohmann::json& json) { } } - if (accounts.empty() && json.count(CodingKeys::address) != 0 && json[CodingKeys::address].is_string()) { + if (accounts.empty() && json.count(CodingKeys::address) != 0 && + json[CodingKeys::address].is_string()) { TWCoinType coin = TWCoinTypeEthereum; if (json.count(CodingKeys::coin) != 0) { coin = json[CodingKeys::coin].get(); diff --git a/src/Polkadot/Extrinsic.cpp b/src/Polkadot/Extrinsic.cpp index 17a41164d0d..be841581e93 100644 --- a/src/Polkadot/Extrinsic.cpp +++ b/src/Polkadot/Extrinsic.cpp @@ -28,41 +28,40 @@ static const std::string stakingChill = "Staking.chill"; // Readable decoded call index can be found from https://polkascan.io static std::map polkadotCallIndices = { - {balanceTransfer, Data{0x05, 0x00}}, - {stakingBond, Data{0x07, 0x00}}, - {stakingBondExtra, Data{0x07, 0x01}}, - {stakingUnbond, Data{0x07, 0x02}}, + {balanceTransfer, Data{0x05, 0x00}}, + {stakingBond, Data{0x07, 0x00}}, + {stakingBondExtra, Data{0x07, 0x01}}, + {stakingUnbond, Data{0x07, 0x02}}, {stakingWithdrawUnbond, Data{0x07, 0x03}}, - {stakingNominate, Data{0x07, 0x05}}, - {stakingChill, Data{0x07, 0x06}}, - {utilityBatch, Data{0x1a, 0x02}}, + {stakingNominate, Data{0x07, 0x05}}, + {stakingChill, Data{0x07, 0x06}}, + {utilityBatch, Data{0x1a, 0x02}}, }; static std::map kusamaCallIndices = { - {balanceTransfer, Data{0x04, 0x00}}, - {stakingBond, Data{0x06, 0x00}}, - {stakingBondExtra, Data{0x06, 0x01}}, - {stakingUnbond, Data{0x06, 0x02}}, + {balanceTransfer, Data{0x04, 0x00}}, + {stakingBond, Data{0x06, 0x00}}, + {stakingBondExtra, Data{0x06, 0x01}}, + {stakingUnbond, Data{0x06, 0x02}}, {stakingWithdrawUnbond, Data{0x06, 0x03}}, - {stakingNominate, Data{0x06, 0x05}}, - {stakingChill, Data{0x06, 0x06}}, - {utilityBatch, Data{0x18, 0x02}}, + {stakingNominate, Data{0x06, 0x05}}, + {stakingChill, Data{0x06, 0x06}}, + {utilityBatch, Data{0x18, 0x02}}, }; static Data getCallIndex(TWSS58AddressType network, const std::string& key) { - switch (network) { - case TWSS58AddressTypePolkadot: + if (network == TWSS58AddressTypePolkadot) { return polkadotCallIndices[key]; - case TWSS58AddressTypeKusama: - return kusamaCallIndices[key]; } + // network == TWSS58AddressTypeKusama + return kusamaCallIndices[key]; } bool Extrinsic::encodeRawAccount(TWSS58AddressType network, uint32_t specVersion) { if ((network == TWSS58AddressTypePolkadot && specVersion >= multiAddrSpecVersion) || (network == TWSS58AddressTypeKusama && specVersion >= multiAddrSpecVersionKsm)) { - return false; - } + return false; + } return true; } @@ -113,129 +112,115 @@ Data Extrinsic::encodeBatchCall(const std::vector& calls, TWSS58AddressTyp Data Extrinsic::encodeStakingCall(const Proto::Staking& staking, TWSS58AddressType network, uint32_t specVersion) { Data data; switch (staking.message_oneof_case()) { - case Proto::Staking::kBond: - { - auto address = SS58Address(staking.bond().controller(), byte(network)); - auto value = load(staking.bond().value()); - auto reward = byte(staking.bond().reward_destination()); - // call index - append(data, getCallIndex(network, stakingBond)); - // controller - append(data, encodeAccountId(address.keyBytes(), encodeRawAccount(network, specVersion))); - // value - append(data, encodeCompact(value)); - // reward destination - append(data, reward); - } - break; - - case Proto::Staking::kBondAndNominate: - { - // encode call1 - Data call1; - { - auto staking1 = Proto::Staking(); - auto* bond = staking1.mutable_bond(); - bond->set_controller(staking.bond_and_nominate().controller()); - bond->set_value(staking.bond_and_nominate().value()); - bond->set_reward_destination(staking.bond_and_nominate().reward_destination()); - // recursive call - call1 = encodeStakingCall(staking1, network, specVersion); - } + case Proto::Staking::kBond: { + auto address = SS58Address(staking.bond().controller(), byte(network)); + auto value = load(staking.bond().value()); + auto reward = byte(staking.bond().reward_destination()); + // call index + append(data, getCallIndex(network, stakingBond)); + // controller + append(data, encodeAccountId(address.keyBytes(), encodeRawAccount(network, specVersion))); + // value + append(data, encodeCompact(value)); + // reward destination + append(data, reward); + } break; - // encode call2 - Data call2; - { - auto staking2 = Proto::Staking(); - auto* nominate = staking2.mutable_nominate(); - for (auto i = 0; i < staking.bond_and_nominate().nominators_size(); ++i) { - nominate->add_nominators(staking.bond_and_nominate().nominators(i)); - } - // recursive call - call2 = encodeStakingCall(staking2, network, specVersion); - } + case Proto::Staking::kBondAndNominate: { + // encode call1 + Data call1; + { + auto staking1 = Proto::Staking(); + auto* bond = staking1.mutable_bond(); + bond->set_controller(staking.bond_and_nominate().controller()); + bond->set_value(staking.bond_and_nominate().value()); + bond->set_reward_destination(staking.bond_and_nominate().reward_destination()); + // recursive call + call1 = encodeStakingCall(staking1, network, specVersion); + } - auto calls = std::vector{call1, call2}; - data = encodeBatchCall(calls, network); + // encode call2 + Data call2; + { + auto staking2 = Proto::Staking(); + auto* nominate = staking2.mutable_nominate(); + for (auto i = 0; i < staking.bond_and_nominate().nominators_size(); ++i) { + nominate->add_nominators(staking.bond_and_nominate().nominators(i)); } - break; + // recursive call + call2 = encodeStakingCall(staking2, network, specVersion); + } - case Proto::Staking::kBondExtra: - { - auto value = load(staking.bond_extra().value()); - // call index - append(data, getCallIndex(network, stakingBondExtra)); - // value - append(data, encodeCompact(value)); - } - break; + auto calls = std::vector{call1, call2}; + data = encodeBatchCall(calls, network); + } break; - case Proto::Staking::kUnbond: - { - auto value = load(staking.unbond().value()); - // call index - append(data, getCallIndex(network, stakingUnbond)); - // value - append(data, encodeCompact(value)); - } - break; + case Proto::Staking::kBondExtra: { + auto value = load(staking.bond_extra().value()); + // call index + append(data, getCallIndex(network, stakingBondExtra)); + // value + append(data, encodeCompact(value)); + } break; - case Proto::Staking::kWithdrawUnbonded: - { - auto spans = staking.withdraw_unbonded().slashing_spans(); - // call index - append(data, getCallIndex(network, stakingWithdrawUnbond)); - // num_slashing_spans - encode32LE(spans, data); - } - break; + case Proto::Staking::kUnbond: { + auto value = load(staking.unbond().value()); + // call index + append(data, getCallIndex(network, stakingUnbond)); + // value + append(data, encodeCompact(value)); + } break; - case Proto::Staking::kNominate: - { - std::vector accountIds; - for (auto& n : staking.nominate().nominators()) { - accountIds.emplace_back(SS58Address(n, network)); - } - // call index - append(data, getCallIndex(network, stakingNominate)); - // nominators - append(data, encodeAccountIds(accountIds, encodeRawAccount(network, specVersion))); - } - break; + case Proto::Staking::kWithdrawUnbonded: { + auto spans = staking.withdraw_unbonded().slashing_spans(); + // call index + append(data, getCallIndex(network, stakingWithdrawUnbond)); + // num_slashing_spans + encode32LE(spans, data); + } break; - case Proto::Staking::kChill: - // call index - append(data, getCallIndex(network, stakingChill)); - break; + case Proto::Staking::kNominate: { + std::vector accountIds; + for (auto& n : staking.nominate().nominators()) { + accountIds.emplace_back(SS58Address(n, network)); + } + // call index + append(data, getCallIndex(network, stakingNominate)); + // nominators + append(data, encodeAccountIds(accountIds, encodeRawAccount(network, specVersion))); + } break; - case Proto::Staking::kChillAndUnbond: - { - // encode call1 - Data call1; - { - auto staking1 = Proto::Staking(); - staking1.mutable_chill(); - // recursive call - call1 = encodeStakingCall(staking1, network, specVersion); - } + case Proto::Staking::kChill: + // call index + append(data, getCallIndex(network, stakingChill)); + break; - // encode call2 - Data call2; - { - auto staking2 = Proto::Staking(); - auto* unbond = staking2.mutable_unbond(); - unbond->set_value(staking.chill_and_unbond().value()); - // recursive call - call2 = encodeStakingCall(staking2, network, specVersion); - } + case Proto::Staking::kChillAndUnbond: { + // encode call1 + Data call1; + { + auto staking1 = Proto::Staking(); + staking1.mutable_chill(); + // recursive call + call1 = encodeStakingCall(staking1, network, specVersion); + } - auto calls = std::vector{call1, call2}; - data = encodeBatchCall(calls, network); - } - break; + // encode call2 + Data call2; + { + auto staking2 = Proto::Staking(); + auto* unbond = staking2.mutable_unbond(); + unbond->set_value(staking.chill_and_unbond().value()); + // recursive call + call2 = encodeStakingCall(staking2, network, specVersion); + } + + auto calls = std::vector{call1, call2}; + data = encodeBatchCall(calls, network); + } break; - default: - break; + default: + break; } return data; } diff --git a/src/PublicKey.cpp b/src/PublicKey.cpp index 70d4e0cb20d..60327ffcaec 100644 --- a/src/PublicKey.cpp +++ b/src/PublicKey.cpp @@ -9,10 +9,10 @@ #include #include +#include #include #include #include -#include #include @@ -47,7 +47,8 @@ bool PublicKey::isValid(const Data& data, enum TWPublicKeyType type) { /// Initializes a public key with a collection of bytes. /// /// @throws std::invalid_argument if the data is not a valid public key. -PublicKey::PublicKey(const Data& data, enum TWPublicKeyType type) : type(type) { +PublicKey::PublicKey(const Data& data, enum TWPublicKeyType type) + : type(type) { if (!isValid(data, type)) { throw std::invalid_argument("Invalid public key data"); } @@ -119,7 +120,9 @@ PublicKey PublicKey::extended() const { case TWPublicKeyTypeCURVE25519: case TWPublicKeyTypeED25519Blake2b: case TWPublicKeyTypeED25519Extended: - return *this; + return *this; + default: + return *this; } } @@ -137,8 +140,8 @@ bool PublicKey::verify(const Data& signature, const Data& message) const { return ed25519_sign_open_blake2b(message.data(), message.size(), bytes.data(), signature.data()) == 0; case TWPublicKeyTypeED25519Extended: throw std::logic_error("Not yet implemented"); - //ed25519_sign_open(message.data(), message.size(), bytes.data(), signature.data()) == 0; - case TWPublicKeyTypeCURVE25519: + // ed25519_sign_open(message.data(), message.size(), bytes.data(), signature.data()) == 0; + case TWPublicKeyTypeCURVE25519: { auto ed25519PublicKey = Data(); ed25519PublicKey.resize(PublicKey::ed25519Size); curve25519_pk_to_ed25519(ed25519PublicKey.data(), bytes.data()); @@ -150,23 +153,24 @@ bool PublicKey::verify(const Data& signature, const Data& message) const { auto verifyBuffer = Data(); append(verifyBuffer, signature); verifyBuffer[63] &= 127; - return ed25519_sign_open(message.data(), message.size(), ed25519PublicKey.data(), - verifyBuffer.data()) == 0; + return ed25519_sign_open(message.data(), message.size(), ed25519PublicKey.data(), verifyBuffer.data()) == 0; + } + default: + throw std::logic_error("Not yet implemented"); } } bool PublicKey::verifyAsDER(const Data& signature, const Data& message) const { switch (type) { case TWPublicKeyTypeSECP256k1: - case TWPublicKeyTypeSECP256k1Extended: - { - Data sig(64); - int ret = ecdsa_sig_from_der(signature.data(), signature.size(), sig.data()); - if (ret) { - return false; - } - return ecdsa_verify_digest(&secp256k1, bytes.data(), sig.data(), message.data()) == 0; + case TWPublicKeyTypeSECP256k1Extended: { + Data sig(64); + int ret = ecdsa_sig_from_der(signature.data(), signature.size(), sig.data()); + if (ret) { + return false; } + return ecdsa_verify_digest(&secp256k1, bytes.data(), sig.data(), message.data()) == 0; + } default: return false; From 2eec467f3908224291e324da1a9a3ac1a28716bd Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 11 Jul 2022 08:33:44 +0200 Subject: [PATCH 020/497] [Improvements]: Upgrade to c++20 (#2331) * feat(input_selector): add missing optional include * feat(ci): try update clang * feat(ci): use llvm-cov-14 on the coverage script * feat(ci): update Dockerfile * feat(ci): upgrade macos-11 to macos-12 * feat(input_selector): remove duplicated include --- .github/workflows/android-ci.yml | 2 +- .github/workflows/ios-ci.yml | 2 +- .github/workflows/linux-ci.yml | 6 +++--- .github/workflows/linux-sampleapp-ci.yml | 2 +- CMakeLists.txt | 2 +- Dockerfile | 19 ++++++++++--------- cmake/Protobuf.cmake | 2 +- cmake/Wasm.cmake | 2 +- protobuf-plugin/CMakeLists.txt | 2 +- samples/cpp/CMakeLists.txt | 2 +- src/Bitcoin/InputSelector.cpp | 1 + tests/CMakeLists.txt | 2 +- tools/coverage | 2 +- walletconsole/CMakeLists.txt | 2 +- walletconsole/lib/CMakeLists.txt | 2 +- 15 files changed, 26 insertions(+), 24 deletions(-) diff --git a/.github/workflows/android-ci.yml b/.github/workflows/android-ci.yml index 56badb9d825..0bb3ed90964 100644 --- a/.github/workflows/android-ci.yml +++ b/.github/workflows/android-ci.yml @@ -9,7 +9,7 @@ on: jobs: build: - runs-on: macos-11 + runs-on: macos-12 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/ios-ci.yml b/.github/workflows/ios-ci.yml index 21d4ca246a7..a7078f649e3 100644 --- a/.github/workflows/ios-ci.yml +++ b/.github/workflows/ios-ci.yml @@ -8,7 +8,7 @@ on: jobs: build: - runs-on: macos-11 + runs-on: macos-12 steps: - uses: actions/checkout@v2 - name: Install system dependencies diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 7071ebed20c..981f5a67cc5 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -8,13 +8,13 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - name: Install system dependencies run: | - # build-essential clang-11 libc++-dev libc++abi-dev ruby-full cmake - sudo apt-get update && sudo apt-get install ninja-build lcov llvm-11 clang-tidy-11 libboost-all-dev --fix-missing + # build-essential clang-14 libc++-dev libc++abi-dev ruby-full cmake + sudo apt-get update && sudo apt-get install ninja-build lcov llvm-14 clang-tidy-14 libboost-all-dev --fix-missing - name: Cache internal dependencies id: internal_cache uses: actions/cache@v1.1.2 diff --git a/.github/workflows/linux-sampleapp-ci.yml b/.github/workflows/linux-sampleapp-ci.yml index 882d8b33da8..a5654b096a7 100644 --- a/.github/workflows/linux-sampleapp-ci.yml +++ b/.github/workflows/linux-sampleapp-ci.yml @@ -8,7 +8,7 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - name: Install system dependencies diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fe591894f7..e35185b0810 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ include(GNUInstallDirs) # Configure warnings set(TW_CXX_WARNINGS "-Wshorten-64-to-32") -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TW_CXX_WARNINGS}") set(CMAKE_EXPORT_COMPILE_COMMANDS 1) diff --git a/Dockerfile b/Dockerfile index ce77a076d68..fae3ef89269 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 +FROM ubuntu:22.04 ENV DEBIAN_FRONTEND=noninteractive @@ -17,9 +17,10 @@ RUN apt-get update \ # Add latest cmake/boost SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc | apt-key add - \ - && apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main' \ - && apt-add-repository -y ppa:mhier/libboost-latest + && apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main' + +RUN wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb && dpkg -i ./libssl1.1_1.1.0g-2ubuntu4_amd64.deb # Install required packages for dev RUN apt-get update \ && apt-get install -y \ @@ -27,16 +28,16 @@ RUN apt-get update \ libtool autoconf pkg-config \ ninja-build \ ruby-full \ - clang-10 \ - llvm-10 \ + clang-14 \ + llvm-14 \ libc++-dev libc++abi-dev \ - cmake \ - libboost1.74-dev \ + cmake \ + libboost-all-dev \ ccache \ && apt-get clean && rm -rf /var/lib/apt/lists/* -ENV CC=/usr/bin/clang-10 -ENV CXX=/usr/bin/clang++-10 +ENV CC=/usr/bin/clang-14 +ENV CXX=/usr/bin/clang++-14 # ↑ Setup build environment # ↓ Build and compile wallet core diff --git a/cmake/Protobuf.cmake b/cmake/Protobuf.cmake index aef75b91077..fe59c9ea73a 100644 --- a/cmake/Protobuf.cmake +++ b/cmake/Protobuf.cmake @@ -202,7 +202,7 @@ add_library(protobuf ${protobuf_SOURCE_FILES} ${protobuf_HEADER_FILES}) set_target_properties( protobuf PROPERTIES - CXX_STANDARD 17 + CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON IMPORTED_CONFIGURATIONS Release INCLUDE_DIRECTORIES ${protobuf_source_dir}/src diff --git a/cmake/Wasm.cmake b/cmake/Wasm.cmake index 5775243f42c..13535817e1d 100644 --- a/cmake/Wasm.cmake +++ b/cmake/Wasm.cmake @@ -14,7 +14,7 @@ message(STATUS "Building for emscripten") # Configure warnings set(TW_CXX_WARNINGS "-Wshorten-64-to-32") -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TW_CXX_WARNINGS}") set(CMAKE_EXPORT_COMPILE_COMMANDS 1) diff --git a/protobuf-plugin/CMakeLists.txt b/protobuf-plugin/CMakeLists.txt index 45d18608f21..57b7ac59d83 100644 --- a/protobuf-plugin/CMakeLists.txt +++ b/protobuf-plugin/CMakeLists.txt @@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.2 FATAL_ERROR) project(TrustWalletCoreProtobufPlugin) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14" CACHE STRING "Minimum OS X deployment version" FORCE) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) if ("$ENV{PREFIX}" STREQUAL "") diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index 618f27f4482..5ecf5e6ba0d 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -19,7 +19,7 @@ if (NOT WALLET_CORE) message (FATAL_ERROR "${SETUP_MESSAGE}") endif () -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set (CMAKE_C_STANDARD 11) diff --git a/src/Bitcoin/InputSelector.cpp b/src/Bitcoin/InputSelector.cpp index 22331773c5d..1104344285f 100644 --- a/src/Bitcoin/InputSelector.cpp +++ b/src/Bitcoin/InputSelector.cpp @@ -9,6 +9,7 @@ #include "UTXO.h" #include +#include #include using namespace TW; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ae58472a213..958d830d97d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -29,7 +29,7 @@ target_compile_options(tests PRIVATE "-Wall") set_target_properties(tests PROPERTIES - CXX_STANDARD 17 + CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON ) diff --git a/tools/coverage b/tools/coverage index 8a33e5f215d..648a1a81f8f 100755 --- a/tools/coverage +++ b/tools/coverage @@ -23,7 +23,7 @@ set -e function install_llvm_gcov() { cat << EOF > /tmp/llvm-gcov.sh #!/bin/bash -exec /usr/bin/llvm-cov-11 gcov "\$@" +exec /usr/bin/llvm-cov-14 gcov "\$@" EOF sudo chmod 755 /tmp/llvm-gcov.sh } diff --git a/walletconsole/CMakeLists.txt b/walletconsole/CMakeLists.txt index 6aabb95e234..8177f65d24f 100644 --- a/walletconsole/CMakeLists.txt +++ b/walletconsole/CMakeLists.txt @@ -13,7 +13,7 @@ target_compile_options(walletconsole PRIVATE "-Wall") set_target_properties(walletconsole PROPERTIES - CXX_STANDARD 17 + CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON ) diff --git a/walletconsole/lib/CMakeLists.txt b/walletconsole/lib/CMakeLists.txt index 4f42ec02667..875ca6fb4c0 100644 --- a/walletconsole/lib/CMakeLists.txt +++ b/walletconsole/lib/CMakeLists.txt @@ -14,6 +14,6 @@ target_compile_options(walletconsolelib PRIVATE "-Wall") set_target_properties(walletconsolelib PROPERTIES - CXX_STANDARD 17 + CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON ) From b13e470b669815317087522eba5827783bf8cd5d Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 11 Jul 2022 12:51:24 +0200 Subject: [PATCH 021/497] [Fix]: Clang Tidy alternative approach with CMake (#2364) * fix(clang_tidy): alternative approach for clang-tidy and CMake - Introduce StandardSettings.cmake which will contains all the options of the project - Introduce StaticAnalyzers.cmake which support clang-tidy for now - Update linux CI * feat(linux_ci): re-enable master condition --- .github/workflows/linux-ci.yml | 2 +- CMakeLists.txt | 13 ++----------- cmake/StandardSettings.cmake | 6 ++++++ cmake/StaticAnalyzers.cmake | 9 +++++++++ tools/lint-all | 3 ++- 5 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 cmake/StandardSettings.cmake create mode 100644 cmake/StaticAnalyzers.cmake diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 981f5a67cc5..0d29b3f9eab 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -37,7 +37,7 @@ jobs: - name: CMake (coverage/clang-tidy/clang-asan) if: github.ref == 'refs/heads/master' run: | - cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCODE_COVERAGE=ON -DCLANG_TIDY=ON -DCLANG_ASAN=ON + cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCODE_COVERAGE=ON -DTrustWalletCore_ENABLE_CLANG_TIDY=ON -DCLANG_ASAN=ON env: CC: /usr/bin/clang CXX: /usr/bin/clang++ diff --git a/CMakeLists.txt b/CMakeLists.txt index e35185b0810..2838c20342a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,8 @@ cmake_minimum_required(VERSION 3.8 FATAL_ERROR) project(TrustWalletCore) include(GNUInstallDirs) +include(cmake/StandardSettings.cmake) +include(cmake/StaticAnalyzers.cmake) # Configure warnings set(TW_CXX_WARNINGS "-Wshorten-64-to-32") @@ -66,17 +68,6 @@ if(CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") set(CMAKE_EXE_LINKER_FLAGS "-fprofile-arcs -ftest-coverage") endif() -option(CLANG_TIDY "Enable static code analysis with (clang-tidy)" OFF) -if(CLANG_TIDY) - find_program(CLANG_TIDY_BIN NAMES clang-tidy-11) - if(CLANG_TIDY_BIN) - set(CMAKE_CXX_CLANG_TIDY clang-tidy-11;) - message("clang-tidy ${CMAKE_CXX_CLANG_TIDY} ${CLANG_TIDY_BIN}") - else() - message(FATAL_ERROR "Could not find clang-tidy") - endif() -endif() - option(CLANG_ASAN "Enable ASAN dynamic address sanitizer" OFF) if(CLANG_ASAN) # https://clang.llvm.org/docs/AddressSanitizer.html diff --git a/cmake/StandardSettings.cmake b/cmake/StandardSettings.cmake new file mode 100644 index 00000000000..ad21616da1a --- /dev/null +++ b/cmake/StandardSettings.cmake @@ -0,0 +1,6 @@ +# +# Static analyzers +# +# Currently supporting: Clang-Tidy. + +option(${PROJECT_NAME}_ENABLE_CLANG_TIDY "Enable static analysis with Clang-Tidy." OFF) \ No newline at end of file diff --git a/cmake/StaticAnalyzers.cmake b/cmake/StaticAnalyzers.cmake new file mode 100644 index 00000000000..07537ca88c4 --- /dev/null +++ b/cmake/StaticAnalyzers.cmake @@ -0,0 +1,9 @@ +if(${PROJECT_NAME}_ENABLE_CLANG_TIDY) + find_program(CLANGTIDY clang-tidy) + if(CLANGTIDY) + set(CMAKE_CXX_CLANG_TIDY ${CLANGTIDY} -extra-arg=-Wno-unknown-warning-option) + message("Clang-Tidy finished setting up.") + else() + message(SEND_ERROR "Clang-Tidy requested but executable not found.") + endif() +endif() \ No newline at end of file diff --git a/tools/lint-all b/tools/lint-all index e3e1eb781c8..c2afc4bc026 100755 --- a/tools/lint-all +++ b/tools/lint-all @@ -4,4 +4,5 @@ set -e -find src \( -name "*.cpp" -o -name "*.h" \) -not -path "./src/proto/*" -not -path "./src/Tron/Protobuf/*" -exec clang-tidy-11 -quiet -p=build '{}' \; +clang-tidy --version +find src \( -name "*.cpp" -o -name "*.h" \) -not -path "./src/proto/*" -not -path "./src/Tron/Protobuf/*" -exec clang-tidy -quiet -p=build '{}' \; From e8a6268346443e15aa0e755e686ced32366f4725 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Mon, 11 Jul 2022 15:07:21 +0200 Subject: [PATCH 022/497] Terra 2.0 support (#2308) * Add support for Terra2.0 (alongside Terra Classic) * Set Terra Classic not deprecated * Minor test adjustments * Rename 20 -> V2 * Swift test fix, enum casing * Update Kotlin tests * Kotlin fix, msg type name (no terra) * Fix explorer links * Add real world claim / stake tests Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- .../blockchains/CoinAddressDerivationTests.kt | 2 +- .../blockchains/terra/TestTerraClassicTxs.kt | 209 ++++++ .../terra/TestTerraTransactions.kt | 135 +--- docs/registry.md | 2 + include/TrustWalletCore/TWCoinType.h | 3 +- registry.json | 35 +- src/Cosmos/Protobuf/cosmwasm_wasm_v1_tx.proto | 19 + .../Protobuf/terra_wasm_v1beta1_tx.proto | 3 +- src/Cosmos/ProtobufSerialization.cpp | 66 ++ src/Cosmos/ProtobufSerialization.h | 4 + src/proto/Cosmos.proto | 60 +- .../Tests/Blockchains/TerraClassicTests.swift | 605 +++++++++++++++++ swift/Tests/Blockchains/TerraTests.swift | 606 ++++-------------- swift/Tests/CoinAddressDerivationTests.swift | 3 +- swift/Tests/HDWalletTests.swift | 6 +- tests/Terra/SignerTests.cpp | 312 ++++----- tests/Terra/SignerTestsClassic.cpp | 456 +++++++++++++ tests/Terra/TWCoinTypeTests.cpp | 26 +- 18 files changed, 1720 insertions(+), 832 deletions(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraClassicTxs.kt create mode 100644 src/Cosmos/Protobuf/cosmwasm_wasm_v1_tx.proto create mode 100644 swift/Tests/Blockchains/TerraClassicTests.swift create mode 100644 tests/Terra/SignerTestsClassic.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 59e5cf16ea6..f8fd85fcb37 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -81,7 +81,7 @@ class CoinAddressDerivationTests { RAVENCOIN -> assertEquals("RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS", address) WAVES -> assertEquals("3P63vkaHhyE9pPv9EfsjwGKqmZYcCRHys4n", address) AETERNITY -> assertEquals("ak_QDHJSfvHG9sDHBobaWt2TAGhuhipYjEqZEH34bWugpJfJc3GN", address) - TERRA -> assertEquals("terra1rh402g98t7sly8trzqw5cyracntlep6qe3smug", address) + TERRA, TERRAV2 -> assertEquals("terra1rh402g98t7sly8trzqw5cyracntlep6qe3smug", address) MONACOIN -> assertEquals("M9xFZzZdZhCDxpx42cM8bQHnLwaeX1aNja", address) FIO -> assertEquals("FIO7MN1LuSfFgrbVHmrt9cVa2FYAs857Ppr9dzvEXoD1miKSxm3n3", address) HARMONY -> assertEquals("one12fk20wmvgypdkn59n4hq8e3aa5899xfx4vsu09", address) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraClassicTxs.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraClassicTxs.kt new file mode 100644 index 00000000000..2c67c665dd8 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraClassicTxs.kt @@ -0,0 +1,209 @@ +package com.trustwallet.core.app.blockchains.terra + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* +import wallet.core.jni.CoinType.TERRA +import wallet.core.jni.proto.Cosmos +import wallet.core.jni.proto.Cosmos.SigningOutput +import wallet.core.jni.proto.Cosmos.SigningMode +import wallet.core.java.AnySigner + +class TestTerraClassicTxs { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testSigningTransaction() { + val key = + PrivateKey("1037f828ca313f4c9e120316e8e9ff25e17f07fe66ba557d5bc5e2eeb7cba8f6".toHexByteArray()) + val publicKey = key.getPublicKeySecp256k1(true) + val from = AnyAddress(publicKey, TERRA).description() + + val txAmount = Cosmos.Amount.newBuilder().apply { + amount = "1000000" + denom = "uluna" + }.build() + + val sendCoinsMsg = Cosmos.Message.Send.newBuilder().apply { + fromAddress = from + toAddress = "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms" + addAllAmounts(listOf(txAmount)) + typePrefix = "bank/MsgSend" + }.build() + + val message = Cosmos.Message.newBuilder().apply { + sendCoinsMessage = sendCoinsMsg + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "3000" + denom = "uluna" + }.build() + + val cosmosFee = Cosmos.Fee.newBuilder().apply { + gas = 200000 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + accountNumber = 158 + chainId = "soju-0013" + memo = "" + sequence = 0 + fee = cosmosFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, TERRA, SigningOutput.parser()) + val jsonPayload = output.json + + val expectedJsonPayload = """{"mode":"block","tx":{"fee":{"amount":[{"amount":"3000","denom":"uluna"}],"gas":"200000"},"memo":"","msg":[{"type":"bank/MsgSend","value":{"amount":[{"amount":"1000000","denom":"uluna"}],"from_address":"terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe","to_address":"terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms"}}],"signatures":[{"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk"},"signature":"KPdiVsKpY12JG/VKEJVa/FpMKclxlS0qNNG6VOAypj10R5vY5UX5IgRJET1zNYnH0wvcXxfNXV+s8jtwN2UXiQ=="}]}}""" + assertEquals(expectedJsonPayload, jsonPayload) + + } + + @Test + fun testSigningWasmTerraTransferTxProtobuf() { + val key = + PrivateKey("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616".toHexByteArray()) + val publicKey = key.getPublicKeySecp256k1(true) + val from = AnyAddress(publicKey, TERRA).description() + + val wasmTransferMessage = Cosmos.Message.WasmTerraExecuteContractTransfer.newBuilder().apply { + senderAddress = from + contractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76" // ANC + amount = ByteString.copyFrom("0x3D090".toHexByteArray()) // 250000 + recipientAddress = "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" + }.build() + + val message = Cosmos.Message.newBuilder().apply { + wasmTerraExecuteContractTransferMessage = wasmTransferMessage + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "3000" + denom = "uluna" + }.build() + + val cosmosFee = Cosmos.Fee.newBuilder().apply { + gas = 200000 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = SigningMode.Protobuf + accountNumber = 3407705 + chainId = "columbus-5" + memo = "" + sequence = 3 + fee = cosmosFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, TERRA, SigningOutput.parser()) + + assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CucBCuQBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBK5AQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Glt7InRyYW5zZmVyIjp7ImFtb3VudCI6IjI1MDAwMCIsInJlY2lwaWVudCI6InRlcnJhMWpsZ2FxeTludm4yaGY1dDJzcmE5eWN6OHM3N3duZjlsMGttZ2NwIn19EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNwZjrHsPmJKW/rXOWfukpQ1+lOHOJW3/IlFFnKLNmsABIECgIIARgDEhMKDQoFdWx1bmESBDMwMDAQwJoMGkAaprIEMLPH2HmFdwFGoaipb2GIyhXt6ombz+WMnG2mORBI6gFt0M+IymYgzZz6w1SW52R922yafDnn7yXfutRw\"}") + assertEquals(output.error, "") + } + + @Test + fun testSigningWasmTerraGenericProtobuf() { + val key = + PrivateKey("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616".toHexByteArray()) + val publicKey = key.getPublicKeySecp256k1(true) + val from = AnyAddress(publicKey, TERRA).description() + + val wasmGenericMessage = Cosmos.Message.WasmTerraExecuteContractGeneric.newBuilder().apply { + senderAddress = from + contractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76" // ANC + executeMsg = """{"transfer": { "amount": "250000", "recipient": "terra1d7048csap4wzcv5zm7z6tdqem2agyp9647vdyj" } }""" + }.build() + + val message = Cosmos.Message.newBuilder().apply { + wasmTerraExecuteContractGeneric = wasmGenericMessage + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "3000" + denom = "uluna" + }.build() + + val cosmosFee = Cosmos.Fee.newBuilder().apply { + gas = 200000 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = SigningMode.Protobuf + accountNumber = 3407705 + chainId = "columbus-5" + memo = "" + sequence = 7 + fee = cosmosFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, TERRA, SigningOutput.parser()) + + assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"Cu4BCusBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLAAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2GmJ7InRyYW5zZmVyIjogeyAiYW1vdW50IjogIjI1MDAwMCIsICJyZWNpcGllbnQiOiAidGVycmExZDcwNDhjc2FwNHd6Y3Y1em03ejZ0ZHFlbTJhZ3lwOTY0N3ZkeWoiIH0gfRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYBxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAkPsS7xlSng2LMc9KiD1soN5NLaDcUh8I9okPmsdJN3le1B7yxRGNB4aQfhaRl/8Z0r5vitRT0AWuxDasd8wcFw==\"}") + assertEquals(output.error, "") + } + + @Test + fun testSigningWasmTerraGenericWithCoinsProtobuf() { + val key = + PrivateKey("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616".toHexByteArray()) + val publicKey = key.getPublicKeySecp256k1(true) + val from = AnyAddress(publicKey, TERRA).description() + + val coins = Cosmos.Amount.newBuilder().apply { + amount = "1000" + denom = "uusd" + }.build() + + val wasmGenericMessage = Cosmos.Message.WasmTerraExecuteContractGeneric.newBuilder().apply { + senderAddress = from + contractAddress = "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s" // ANC Market + executeMsg = """{ "deposit_stable": {} }""" + addCoins(coins) + }.build() + + val message = Cosmos.Message.newBuilder().apply { + wasmTerraExecuteContractGeneric = wasmGenericMessage + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "7000" + denom = "uluna" + }.build() + + val cosmosFee = Cosmos.Fee.newBuilder().apply { + gas = 600000 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = SigningMode.Protobuf + accountNumber = 3407705 + chainId = "columbus-5" + memo = "" + sequence = 9 + fee = cosmosFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, TERRA, SigningOutput.parser()) + + assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CrIBCq8BCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBKEAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMXNlcGZqN3MwYWVnNTk2N3V4bmZrNHRoemxlcnJza3RrcGVsbTVzGhh7ICJkZXBvc2l0X3N0YWJsZSI6IHt9IH0qDAoEdXVzZBIEMTAwMBJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYCRITCg0KBXVsdW5hEgQ3MDAwEMDPJBpAGyi7f1ioY8XV6pjFq1s86Om4++CIUnd3rLHif2iopCcYvX0mLkTlQ6NUERg8nWTYgXcj6fOTO/ptgPuAtv0NWg==\"}") + assertEquals(output.error, "") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraTransactions.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraTransactions.kt index 0d472d980ef..6ee4574001a 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraTransactions.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/terra/TestTerraTransactions.kt @@ -5,7 +5,7 @@ import com.trustwallet.core.app.utils.toHexByteArray import org.junit.Assert.assertEquals import org.junit.Test import wallet.core.jni.* -import wallet.core.jni.CoinType.TERRA +import wallet.core.jni.CoinType.TERRAV2 import wallet.core.jni.proto.Cosmos import wallet.core.jni.proto.Cosmos.SigningOutput import wallet.core.jni.proto.Cosmos.SigningMode @@ -20,9 +20,9 @@ class TestTerraTransactions { @Test fun testSigningTransaction() { val key = - PrivateKey("1037f828ca313f4c9e120316e8e9ff25e17f07fe66ba557d5bc5e2eeb7cba8f6".toHexByteArray()) + PrivateKey("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005".toHexByteArray()) val publicKey = key.getPublicKeySecp256k1(true) - val from = AnyAddress(publicKey, TERRA).description() + val from = AnyAddress(publicKey, TERRAV2).description() val txAmount = Cosmos.Amount.newBuilder().apply { amount = "1000000" @@ -31,9 +31,8 @@ class TestTerraTransactions { val sendCoinsMsg = Cosmos.Message.Send.newBuilder().apply { fromAddress = from - toAddress = "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms" + toAddress = "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" addAllAmounts(listOf(txAmount)) - typePrefix = "bank/MsgSend" }.build() val message = Cosmos.Message.newBuilder().apply { @@ -41,7 +40,7 @@ class TestTerraTransactions { }.build() val feeAmount = Cosmos.Amount.newBuilder().apply { - amount = "3000" + amount = "30000" denom = "uluna" }.build() @@ -51,39 +50,39 @@ class TestTerraTransactions { }.build() val signingInput = Cosmos.SigningInput.newBuilder().apply { - accountNumber = 158 - chainId = "soju-0013" + signingMode = SigningMode.Protobuf + accountNumber = 1037 + chainId = "phoenix-1" memo = "" - sequence = 0 + sequence = 1 fee = cosmosFee privateKey = ByteString.copyFrom(key.data()) addAllMessages(listOf(message)) }.build() - val output = AnySigner.sign(signingInput, TERRA, SigningOutput.parser()) + val output = AnySigner.sign(signingInput, TERRAV2, SigningOutput.parser()) val jsonPayload = output.json - val expectedJsonPayload = """{"mode":"block","tx":{"fee":{"amount":[{"amount":"3000","denom":"uluna"}],"gas":"200000"},"memo":"","msg":[{"type":"bank/MsgSend","value":{"amount":[{"amount":"1000000","denom":"uluna"}],"from_address":"terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe","to_address":"terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms"}}],"signatures":[{"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk"},"signature":"KPdiVsKpY12JG/VKEJVa/FpMKclxlS0qNNG6VOAypj10R5vY5UX5IgRJET1zNYnH0wvcXxfNXV+s8jtwN2UXiQ=="}]}}""" - assertEquals(expectedJsonPayload, jsonPayload) - + assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CpEBCo4BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm4KLHRlcnJhMWhzazZqcnl5cWpmaHA1ZGhjNTV0YzlqdGNreWd4MGVwMzdoZGQyEix0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcBoQCgV1bHVuYRIHMTAwMDAwMBJoClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiECVyhuw/N9M1V7u6oACyd0SskCOqmWfK51oYHR/5H6ncUSBAoCCAEYARIUCg4KBXVsdW5hEgUzMDAwMBDAmgwaQPh0C3rjzdixIUiyPx3FlWAxzbKILNAcSRVeQnaTl1vsI5DEfYa2oYlUBLqyilcMCcU/iaJLhex30No2ak0Zn1Q=\"}") + assertEquals(output.error, "") } @Test - fun testSigningWasmTerraTransferTxProtobuf() { + fun testSigningWasmTerraTransferTx() { val key = PrivateKey("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616".toHexByteArray()) val publicKey = key.getPublicKeySecp256k1(true) - val from = AnyAddress(publicKey, TERRA).description() + val from = AnyAddress(publicKey, TERRAV2).description() - val wasmTransferMessage = Cosmos.Message.WasmTerraExecuteContractTransfer.newBuilder().apply { + val wasmTransferMessage = Cosmos.Message.WasmExecuteContractTransfer.newBuilder().apply { senderAddress = from - contractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76" // ANC + contractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76" amount = ByteString.copyFrom("0x3D090".toHexByteArray()) // 250000 recipientAddress = "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" }.build() val message = Cosmos.Message.newBuilder().apply { - wasmTerraExecuteContractTransferMessage = wasmTransferMessage + wasmExecuteContractTransferMessage = wasmTransferMessage }.build() val feeAmount = Cosmos.Amount.newBuilder().apply { @@ -99,7 +98,7 @@ class TestTerraTransactions { val signingInput = Cosmos.SigningInput.newBuilder().apply { signingMode = SigningMode.Protobuf accountNumber = 3407705 - chainId = "columbus-5" + chainId = "phoenix-1" memo = "" sequence = 3 fee = cosmosFee @@ -107,103 +106,9 @@ class TestTerraTransactions { addAllMessages(listOf(message)) }.build() - val output = AnySigner.sign(signingInput, TERRA, SigningOutput.parser()) - - assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CucBCuQBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBK5AQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Glt7InRyYW5zZmVyIjp7ImFtb3VudCI6IjI1MDAwMCIsInJlY2lwaWVudCI6InRlcnJhMWpsZ2FxeTludm4yaGY1dDJzcmE5eWN6OHM3N3duZjlsMGttZ2NwIn19EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNwZjrHsPmJKW/rXOWfukpQ1+lOHOJW3/IlFFnKLNmsABIECgIIARgDEhMKDQoFdWx1bmESBDMwMDAQwJoMGkAaprIEMLPH2HmFdwFGoaipb2GIyhXt6ombz+WMnG2mORBI6gFt0M+IymYgzZz6w1SW52R922yafDnn7yXfutRw\"}") - assertEquals(output.error, "") - } - - @Test - fun testSigningWasmTerraGenericProtobuf() { - val key = - PrivateKey("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616".toHexByteArray()) - val publicKey = key.getPublicKeySecp256k1(true) - val from = AnyAddress(publicKey, TERRA).description() - - val wasmGenericMessage = Cosmos.Message.WasmTerraExecuteContractGeneric.newBuilder().apply { - senderAddress = from - contractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76" // ANC - executeMsg = """{"transfer": { "amount": "250000", "recipient": "terra1d7048csap4wzcv5zm7z6tdqem2agyp9647vdyj" } }""" - }.build() - - val message = Cosmos.Message.newBuilder().apply { - wasmTerraExecuteContractGeneric = wasmGenericMessage - }.build() - - val feeAmount = Cosmos.Amount.newBuilder().apply { - amount = "3000" - denom = "uluna" - }.build() - - val cosmosFee = Cosmos.Fee.newBuilder().apply { - gas = 200000 - addAllAmounts(listOf(feeAmount)) - }.build() - - val signingInput = Cosmos.SigningInput.newBuilder().apply { - signingMode = SigningMode.Protobuf - accountNumber = 3407705 - chainId = "columbus-5" - memo = "" - sequence = 7 - fee = cosmosFee - privateKey = ByteString.copyFrom(key.data()) - addAllMessages(listOf(message)) - }.build() - - val output = AnySigner.sign(signingInput, TERRA, SigningOutput.parser()) - - assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"Cu4BCusBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLAAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2GmJ7InRyYW5zZmVyIjogeyAiYW1vdW50IjogIjI1MDAwMCIsICJyZWNpcGllbnQiOiAidGVycmExZDcwNDhjc2FwNHd6Y3Y1em03ejZ0ZHFlbTJhZ3lwOTY0N3ZkeWoiIH0gfRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYBxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAkPsS7xlSng2LMc9KiD1soN5NLaDcUh8I9okPmsdJN3le1B7yxRGNB4aQfhaRl/8Z0r5vitRT0AWuxDasd8wcFw==\"}") - assertEquals(output.error, "") - } - - @Test - fun testSigningWasmTerraGenericWithCoinsProtobuf() { - val key = - PrivateKey("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616".toHexByteArray()) - val publicKey = key.getPublicKeySecp256k1(true) - val from = AnyAddress(publicKey, TERRA).description() - - val coins = Cosmos.Amount.newBuilder().apply { - amount = "1000" - denom = "uusd" - }.build() - - val wasmGenericMessage = Cosmos.Message.WasmTerraExecuteContractGeneric.newBuilder().apply { - senderAddress = from - contractAddress = "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s" // ANC Market - executeMsg = """{ "deposit_stable": {} }""" - addCoins(coins) - }.build() - - val message = Cosmos.Message.newBuilder().apply { - wasmTerraExecuteContractGeneric = wasmGenericMessage - }.build() - - val feeAmount = Cosmos.Amount.newBuilder().apply { - amount = "7000" - denom = "uluna" - }.build() - - val cosmosFee = Cosmos.Fee.newBuilder().apply { - gas = 600000 - addAllAmounts(listOf(feeAmount)) - }.build() - - val signingInput = Cosmos.SigningInput.newBuilder().apply { - signingMode = SigningMode.Protobuf - accountNumber = 3407705 - chainId = "columbus-5" - memo = "" - sequence = 9 - fee = cosmosFee - privateKey = ByteString.copyFrom(key.data()) - addAllMessages(listOf(message)) - }.build() - - val output = AnySigner.sign(signingInput, TERRA, SigningOutput.parser()) + val output = AnySigner.sign(signingInput, TERRAV2, SigningOutput.parser()) - assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CrIBCq8BCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBKEAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMXNlcGZqN3MwYWVnNTk2N3V4bmZrNHRoemxlcnJza3RrcGVsbTVzGhh7ICJkZXBvc2l0X3N0YWJsZSI6IHt9IH0qDAoEdXVzZBIEMTAwMBJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYCRITCg0KBXVsdW5hEgQ3MDAwEMDPJBpAGyi7f1ioY8XV6pjFq1s86Om4++CIUnd3rLHif2iopCcYvX0mLkTlQ6NUERg8nWTYgXcj6fOTO/ptgPuAtv0NWg==\"}") + assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CuUBCuIBCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QSuQEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTE0ejU2bDBmcDJsc2Y4Nnp5M2h0eTJ6NDdlemtobnRodHI5eXE3NhpbeyJ0cmFuc2ZlciI6eyJhbW91bnQiOiIyNTAwMDAiLCJyZWNpcGllbnQiOiJ0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcCJ9fRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYAxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAiBGbQaj+jsXE6/FssD3fC77QOxpli9GqsPea+KoNyMIEgVj89Hii+oU1bAEQS4qV0SaE2V6RNy24uCcFTIRbcQ==\"}") assertEquals(output.error, "") } } diff --git a/docs/registry.md b/docs/registry.md index 6e4cfe5ae5d..3aa40ae48b0 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -33,6 +33,7 @@ This list is generated from [./registry.json](../registry.json) | 283 | Algorand | ALGO | | | | 304 | IoTeX | IOTX | | | | 313 | Zilliqa | ZIL | | | +| 330 | Terra Classic | LUNC | | | | 354 | Polkadot | DOT | | | | 394 | Crypto.org | CRO | | | | 397 | NEAR | NEAR | | | @@ -77,6 +78,7 @@ This list is generated from [./registry.json](../registry.json) | 10000250 | Fantom | FTM | | | | 10000288 | Boba | BOBAETH | | | | 10000321 | KuCoin Community Chain | KCS | | | +| 10000330 | Terra | LUNA | | | | 10000553 | Huobi ECO Chain | HT | | | | 10001088 | Metis | METIS | | | | 10001284 | Moonbeam | GLMR | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 6fdcea797b8..4751fea77e6 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -73,7 +73,8 @@ enum TWCoinType { TWCoinTypeZelcash = 19167, TWCoinTypeRavencoin = 175, TWCoinTypeWaves = 5741564, - TWCoinTypeTerra = 330, + TWCoinTypeTerra = 330, // see also TerraV2 + TWCoinTypeTerraV2 = 10000330, // see also Terra TWCoinTypeHarmony = 1023, TWCoinTypeAlgorand = 283, TWCoinTypeKusama = 434, diff --git a/registry.json b/registry.json index 114de52a3b7..a82e24d0dc6 100644 --- a/registry.json +++ b/registry.json @@ -901,17 +901,46 @@ "hrp": "terra", "addressHasher": "sha256ripemd", "explorer": { - "url": "https://finder.terra.money/tx", + "url": "https://finder.terra.money/classic", "txPath": "/tx/", "accountPath": "/address/" }, "info": { "url": "https://terra.money", "source": "https://github.com/terra-project/core", - "rpc": "https://classic.fcd.terra.dev", + "rpc": "https://columbus-fcd.terra.dev", "documentation": "https://docs.terra.money" + } + }, + { + "id": "terrav2", + "name": "TerraV2", + "displayName": "Terra", + "coinId": 10000330, + "symbol": "LUNA", + "decimals": 6, + "blockchain": "Cosmos", + "derivation": [ + { + "path": "m/44'/330'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "terra", + "chainId": "phoenix-1", + "addressHasher": "sha256ripemd", + "explorer": { + "url": "https://finder.terra.money/mainnet", + "txPath": "/tx/", + "accountPath": "/address/" }, - "deprecated": true + "info": { + "url": "https://terra.money", + "source": "https://github.com/terra-project/core", + "rpc": "https://phoenix-lcd.terra.dev", + "documentation": "https://docs.terra.money" + } }, { "id": "polkadot", diff --git a/src/Cosmos/Protobuf/cosmwasm_wasm_v1_tx.proto b/src/Cosmos/Protobuf/cosmwasm_wasm_v1_tx.proto new file mode 100644 index 00000000000..68f0995a016 --- /dev/null +++ b/src/Cosmos/Protobuf/cosmwasm_wasm_v1_tx.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; +package cosmwasm.wasm.v1; + +// Src: https://github.com/CosmWasm/wasmd/blob/main/proto/cosmwasm/wasm/v1/tx.proto + +import "coin.proto"; + +// MsgExecuteContract submits the given message data to a smart contract +message MsgExecuteContract { + // Sender is the that actor that signed the messages + string sender = 1; + // Contract is the address of the smart contract + string contract = 2; + // Msg json encoded message to be passed to the contract + bytes msg = 3; + // Funds coins that are transferred to the contract on execution + // Gap in field numbering is intentional! + repeated cosmos.base.v1beta1.Coin funds = 5; +} diff --git a/src/Cosmos/Protobuf/terra_wasm_v1beta1_tx.proto b/src/Cosmos/Protobuf/terra_wasm_v1beta1_tx.proto index c54893def38..a544e58b2ea 100644 --- a/src/Cosmos/Protobuf/terra_wasm_v1beta1_tx.proto +++ b/src/Cosmos/Protobuf/terra_wasm_v1beta1_tx.proto @@ -1,8 +1,9 @@ syntax = "proto3"; package terra.wasm.v1beta1; +// Terra-Classic-specific fork, used only by Terra Classic // Src: https://github.com/terra-money/core/blob/main/proto/terra/wasm/v1beta1/tx.proto -// Terra-specific fork, original in https://github.com/CosmWasm/wasmd/blob/master/proto/cosmwasm/wasm/v1/tx.proto +// original in https://github.com/CosmWasm/wasmd/blob/master/proto/cosmwasm/wasm/v1/tx.proto import "coin.proto"; diff --git a/src/Cosmos/ProtobufSerialization.cpp b/src/Cosmos/ProtobufSerialization.cpp index 0ceb5bff9d2..b92c9ac5162 100644 --- a/src/Cosmos/ProtobufSerialization.cpp +++ b/src/Cosmos/ProtobufSerialization.cpp @@ -9,6 +9,7 @@ #include "../proto/Cosmos.pb.h" #include "Protobuf/coin.pb.h" #include "Protobuf/bank_tx.pb.h" +#include "Protobuf/cosmwasm_wasm_v1_tx.pb.h" #include "Protobuf/distribution_tx.pb.h" #include "Protobuf/staking_tx.pb.h" #include "Protobuf/tx.pb.h" @@ -162,6 +163,7 @@ google::protobuf::Any convertMessage(const Proto::Message& msg) { any.PackFrom(msgSend, ProtobufAnyNamespacePrefix); return any; } + case Proto::Message::kWasmTerraExecuteContractGeneric: { assert(msg.has_wasm_terra_execute_contract_generic()); const auto& wasmExecute = msg.wasm_terra_execute_contract_generic(); @@ -177,6 +179,47 @@ google::protobuf::Any convertMessage(const Proto::Message& msg) { return any; } + case Proto::Message::kWasmExecuteContractTransferMessage: + { + assert(msg.has_wasm_execute_contract_transfer_message()); + const auto& wasmExecute = msg.wasm_execute_contract_transfer_message(); + auto msgExecute = cosmwasm::wasm::v1::MsgExecuteContract(); + msgExecute.set_sender(wasmExecute.sender_address()); + msgExecute.set_contract(wasmExecute.contract_address()); + const std::string payload = Cosmos::wasmExecuteTransferPayload(wasmExecute).dump(); + msgExecute.set_msg(payload); + any.PackFrom(msgExecute, ProtobufAnyNamespacePrefix); + return any; + } + + case Proto::Message::kWasmExecuteContractSendMessage: + { + assert(msg.has_wasm_execute_contract_send_message()); + const auto& wasmExecute = msg.wasm_execute_contract_send_message(); + auto msgExecute = cosmwasm::wasm::v1::MsgExecuteContract(); + msgExecute.set_sender(wasmExecute.sender_address()); + msgExecute.set_contract(wasmExecute.contract_address()); + const std::string payload = Cosmos::wasmExecuteSendPayload(wasmExecute).dump(); + msgExecute.set_msg(payload); + any.PackFrom(msgExecute, ProtobufAnyNamespacePrefix); + return any; + } + + case Proto::Message::kWasmExecuteContractGeneric: { + assert(msg.has_wasm_execute_contract_generic()); + const auto& wasmExecute = msg.wasm_execute_contract_generic(); + auto msgExecute = cosmwasm::wasm::v1::MsgExecuteContract(); + msgExecute.set_sender(wasmExecute.sender_address()); + msgExecute.set_contract(wasmExecute.contract_address()); + msgExecute.set_msg(wasmExecute.execute_msg()); + + for (auto i = 0; i < wasmExecute.coins_size(); ++i) { + *msgExecute.add_funds() = convertCoin(wasmExecute.coins(i)); + } + any.PackFrom(msgExecute, ProtobufAnyNamespacePrefix); + return any; + } + default: throw std::invalid_argument(std::string("Message not supported ") + std::to_string(msg.message_oneof_case())); } @@ -287,6 +330,29 @@ std::string buildProtoTxJson(const Proto::SigningInput& input, const std::string return jsonSerialized.dump(); } +json wasmExecuteTransferPayload(const Proto::Message_WasmExecuteContractTransfer& msg) { + return { + {"transfer", + { + {"amount", toString(load(data(msg.amount())))}, + {"recipient", msg.recipient_address()} + } + } + }; +} + +json wasmExecuteSendPayload(const Proto::Message_WasmExecuteContractSend& msg) { + return { + {"send", + { + {"amount", toString(load(data(msg.amount())))}, + {"contract", msg.recipient_contract_address()}, + {"msg", msg.msg()} + } + } + }; +} + json wasmTerraExecuteTransferPayload(const Proto::Message_WasmTerraExecuteContractTransfer& msg) { return { {"transfer", diff --git a/src/Cosmos/ProtobufSerialization.h b/src/Cosmos/ProtobufSerialization.h index 2e48685685a..de41eb3269b 100644 --- a/src/Cosmos/ProtobufSerialization.h +++ b/src/Cosmos/ProtobufSerialization.h @@ -26,6 +26,10 @@ std::string buildProtoTxRaw(const Proto::SigningInput& input, const std::string& std::string buildProtoTxJson(const Proto::SigningInput& input, const std::string& serializedTx); +nlohmann::json wasmExecuteTransferPayload(const Proto::Message_WasmExecuteContractTransfer& msg); + +nlohmann::json wasmExecuteSendPayload(const Proto::Message_WasmExecuteContractSend& msg); + nlohmann::json wasmTerraExecuteTransferPayload(const Proto::Message_WasmTerraExecuteContractTransfer& msg); nlohmann::json wasmTerraExecuteSendPayload(const Proto::Message_WasmTerraExecuteContractSend& msg); diff --git a/src/proto/Cosmos.proto b/src/proto/Cosmos.proto index 6f44115718e..307f4a12ad6 100644 --- a/src/proto/Cosmos.proto +++ b/src/proto/Cosmos.proto @@ -85,7 +85,7 @@ message Message { string type_prefix = 3; } - // transfer within wasm/MsgExecuteContract, used by Terra + // transfer within wasm/MsgExecuteContract, used by Terra Classic message WasmTerraExecuteContractTransfer { // sender address string sender_address = 1; @@ -99,7 +99,7 @@ message Message { string recipient_address = 4; } - // send within wasm/MsgExecuteContract, used by Terra + // send within wasm/MsgExecuteContract, used by Terra Classic message WasmTerraExecuteContractSend { // sender address string sender_address = 1; @@ -126,7 +126,7 @@ message Message { repeated Amount amounts = 3; } - // send within wasm/MsgExecuteContract, used by Terra + // execute within wasm/MsgExecuteContract, used by Terra Classic message WasmTerraExecuteContractGeneric { // sender address string sender_address = 1; @@ -142,6 +142,56 @@ message Message { repeated Amount coins = 5; } + // transfer within wasm/MsgExecuteContract + message WasmExecuteContractTransfer { + // sender address + string sender_address = 1; + + // token contract address + string contract_address = 2; + + // size is uint128, as bigint + bytes amount = 3; + + string recipient_address = 4; + } + + // send within wasm/MsgExecuteContract + message WasmExecuteContractSend { + // sender address + string sender_address = 1; + + // token contract address + string contract_address = 2; + + // size is uint128, as bigint + bytes amount = 3; + + string recipient_contract_address = 4; + + // execute_msg to be executed in the context of recipient contract + string msg = 5; + + // used in case you are sending native tokens along with this message + repeated string coin = 6; + } + + // execute within wasm/MsgExecuteContract + message WasmExecuteContractGeneric { + // sender address + string sender_address = 1; + + // token contract address + string contract_address = 2; + + // execute_msg to be executed in the context of recipient contract + string execute_msg = 3; + + // used in case you are sending native tokens along with this message + // Gap in field numbering is intentional + repeated Amount coins = 5; + } + message RawJSON { string type = 1; string value = 2; @@ -159,7 +209,9 @@ message Message { WasmTerraExecuteContractSend wasm_terra_execute_contract_send_message = 9; THORChainSend thorchain_send_message = 10; WasmTerraExecuteContractGeneric wasm_terra_execute_contract_generic = 11; - + WasmExecuteContractTransfer wasm_execute_contract_transfer_message = 12; + WasmExecuteContractSend wasm_execute_contract_send_message = 13; + WasmExecuteContractGeneric wasm_execute_contract_generic = 14; } } diff --git a/swift/Tests/Blockchains/TerraClassicTests.swift b/swift/Tests/Blockchains/TerraClassicTests.swift new file mode 100644 index 00000000000..bb1e8c81e21 --- /dev/null +++ b/swift/Tests/Blockchains/TerraClassicTests.swift @@ -0,0 +1,605 @@ +// Copyright © 2017-2020 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import XCTest +import WalletCore + +class TerraClassicTests: XCTestCase { + + let privateKey = PrivateKey(data: Data(hexString: "1037f828ca313f4c9e120316e8e9ff25e17f07fe66ba557d5bc5e2eeb7cba8f6")!)! + + func testAddress() { + let address = CoinType.terra.deriveAddress(privateKey: privateKey) + + XCTAssertEqual(address, "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe") + XCTAssertTrue(CoinType.terra.validate(address: "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms")) + XCTAssertTrue(CoinType.terra.validate(address: "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk")) + XCTAssertFalse(CoinType.terra.validate(address: "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02")) + } + + func testRawJSON() { + let publicKey = privateKey.getPublicKeySecp256k1(compressed: true) + let fromAddress = AnyAddress(publicKey: publicKey, coin: .terra).description + + let message = CosmosMessage.with { + $0.rawJsonMessage = CosmosMessage.RawJSON.with { + $0.type = "bank/MsgSend" + $0.value = """ + { + "amount": [{ + "amount": "1000000", + "denom": "uluna" + }], + "from_address": "\(fromAddress)", + "to_address": "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms" + } + """ + } + } + + let fee = CosmosFee.with { + $0.gas = 200000 + $0.amounts = [CosmosAmount.with { + $0.amount = "3000" + $0.denom = "uluna" + }] + } + + let input = CosmosSigningInput.with { + $0.accountNumber = 158 + $0.chainID = "soju-0013" + $0.memo = "" + $0.sequence = 0 + $0.messages = [message] + $0.fee = fee + $0.privateKey = privateKey.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) + + let expectedJSON: String = +""" +{ + "mode": "block", + "tx": { + "msg": [{ + "type": "bank/MsgSend", + "value": { + "from_address": "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe", + "to_address": "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms", + "amount": [{ + "denom": "uluna", + "amount": "1000000" + }] + } + }], + "fee": { + "amount": [{ + "denom": "uluna", + "amount": "3000" + }], + "gas": "200000" + }, + "signatures": [{ + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk" + }, + "signature": "KPdiVsKpY12JG/VKEJVa/FpMKclxlS0qNNG6VOAypj10R5vY5UX5IgRJET1zNYnH0wvcXxfNXV+s8jtwN2UXiQ==" + }], + "memo": "" + } +} +""" + XCTAssertJSONEqual(expectedJSON, output.json) + } + + func testSigningTransaction() { + // https://finder.terra.money/soju-0013/tx/1403B07F2D218BCE961CB92D83377A924FEDB54C1F0B62E25C8B93B63470EBF7 + let publicKey = privateKey.getPublicKeySecp256k1(compressed: true) + let fromAddress = AnyAddress(publicKey: publicKey, coin: .terra).description + + let message = CosmosMessage.with { + $0.sendCoinsMessage = CosmosMessage.Send.with { + $0.fromAddress = fromAddress + $0.toAddress = "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms" + $0.amounts = [CosmosAmount.with { + $0.amount = "1000000" + $0.denom = "uluna" + }] + $0.typePrefix = "bank/MsgSend" + } + } + + let fee = CosmosFee.with { + $0.gas = 200000 + $0.amounts = [CosmosAmount.with { + $0.amount = "3000" + $0.denom = "uluna" + }] + } + + let input = CosmosSigningInput.with { + $0.accountNumber = 158 + $0.chainID = "soju-0013" + $0.memo = "" + $0.sequence = 0 + $0.messages = [message] + $0.fee = fee + $0.privateKey = privateKey.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) + + let expectedJSON: String = +""" +{ + "mode": "block", + "tx": { + "msg": [{ + "type": "bank/MsgSend", + "value": { + "from_address": "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe", + "to_address": "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms", + "amount": [{ + "denom": "uluna", + "amount": "1000000" + }] + } + }], + "fee": { + "amount": [{ + "denom": "uluna", + "amount": "3000" + }], + "gas": "200000" + }, + "signatures": [{ + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk" + }, + "signature": "KPdiVsKpY12JG/VKEJVa/FpMKclxlS0qNNG6VOAypj10R5vY5UX5IgRJET1zNYnH0wvcXxfNXV+s8jtwN2UXiQ==" + }], + "memo": "" + } +} +""" + XCTAssertJSONEqual(expectedJSON, output.json) + } + + func testStaking() { + // https://finder.terra.money/soju-0013/tx/4C0A6690ECB601ACB42D3ECAF4C24C0555B5E32E45B09C3B1607B144CD191F87 + let stakeMessage = CosmosMessage.Delegate.with { + $0.delegatorAddress = "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe" + $0.validatorAddress = "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" + $0.amount = CosmosAmount.with { + $0.amount = "1000000" + $0.denom = "uluna" + } + $0.typePrefix = "staking/MsgDelegate" + } + + let message = CosmosMessage.with { + $0.stakeMessage = stakeMessage + } + + let fee = CosmosFee.with { + $0.gas = 200000 + $0.amounts = [CosmosAmount.with { + $0.amount = "3000" + $0.denom = "uluna" + }] + } + + let input = CosmosSigningInput.with { + $0.accountNumber = 158 + $0.chainID = "soju-0013" + $0.memo = "" + $0.sequence = 1 + $0.messages = [message] + $0.fee = fee + $0.privateKey = privateKey.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) + + let expectedJSON = """ +{ + "mode": "block", + "tx": { + "fee": { + "amount": [{ + "amount": "3000", + "denom": "uluna" + }], + "gas": "200000" + }, + "memo": "", + "msg": [{ + "type": "staking/MsgDelegate", + "value": { + "amount": { + "amount": "1000000", + "denom": "uluna" + }, + "delegator_address": "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe", + "validator_address": "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" + } + }], + "signatures": [{ + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk" + }, + "signature": "F8UJxbkqa0j6dYTk8PymrudBKI3WYhZImRxMFCw0ecFCmPGgNTg7yfpKZo6K6JtnoJaP7bQ4db5e4wnhMCJyAQ==" + }] + } +} +""" + XCTAssertJSONEqual(expectedJSON, output.json) + } + + func testWithdraw() { + // https://finder.terra.money/soju-0013/tx/AE0E4F2B254449950A3A7F41FABCE0B3C846D70F809380313CE3BB323E490BBD + let withdrawMessage = CosmosMessage.WithdrawDelegationReward.with { + $0.delegatorAddress = "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe" + $0.validatorAddress = "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" + $0.typePrefix = "distribution/MsgWithdrawDelegationReward" + } + + let message = CosmosMessage.with { + $0.withdrawStakeRewardMessage = withdrawMessage + } + + let fee = CosmosFee.with { + $0.amounts = [CosmosAmount.with { + $0.amount = "3000" + $0.denom = "uluna" + }] + $0.gas = 200000 + } + + let input = CosmosSigningInput.with { + $0.accountNumber = 158 + $0.chainID = "soju-0013" + $0.memo = "" + $0.sequence = 2 + $0.messages = [message] + $0.fee = fee + $0.privateKey = privateKey.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) + + let expectedJSON = """ +{ + "mode": "block", + "tx": { + "fee": { + "amount": [{ + "amount": "3000", + "denom": "uluna" + }], + "gas": "200000" + }, + "memo": "", + "msg": [{ + "type": "distribution/MsgWithdrawDelegationReward", + "value": { + "delegator_address": "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe", + "validator_address": "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" + } + }], + "signatures": [{ + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk" + }, + "signature": "Kfwi1uJplzLucXDyQZsJI9v8lMFJFUBLD46+MpwBwYwPJgqPRzSOfyjRpmNou0G/Qe1hbsGEgqb85FQpsgLz+g==" + }] + } +} +""" + XCTAssertJSONEqual(expectedJSON, output.json) + } + + func testUndelegate() { + // https://finder.terra.money/soju-0013/tx/FCF50C180303AECA97F916D0CE0E0937BA4C4D2F6777FFF2AA0D52A9DAF9CCBA + let unstakeMessage = CosmosMessage.Undelegate.with { + $0.delegatorAddress = "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe" + $0.validatorAddress = "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" + $0.amount = CosmosAmount.with { + $0.amount = "500000" + $0.denom = "uluna" + } + $0.typePrefix = "staking/MsgUndelegate" + } + + let message = CosmosMessage.with { + $0.unstakeMessage = unstakeMessage + } + + let fee = CosmosFee.with { + $0.gas = 200000 + $0.amounts = [CosmosAmount.with { + $0.amount = "3000" + $0.denom = "uluna" + }] + } + + let input = CosmosSigningInput.with { + $0.accountNumber = 158 + $0.chainID = "soju-0013" + $0.memo = "" + $0.sequence = 3 + $0.messages = [message] + $0.fee = fee + $0.privateKey = privateKey.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) + + let expectedJSON = """ +{ + "mode": "block", + "tx": { + "fee": { + "amount": [{ + "amount": "3000", + "denom": "uluna" + }], + "gas": "200000" + }, + "memo": "", + "msg": [{ + "type": "staking/MsgUndelegate", + "value": { + "amount": { + "amount": "500000", + "denom": "uluna" + }, + "delegator_address": "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe", + "validator_address": "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" + } + }], + "signatures": [{ + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk" + }, + "signature": "THf/RxsBr2EhHE2OMHLXfv+qSP9ORbvHgo4OSOS2P95xxGH73wW+t1zIl9cGlIVvcoChwaCg5/iEuvbgXUWpNw==" + }] + } +} +""" + XCTAssertJSONEqual(expectedJSON, output.json) + } + + func testRedlegate() { + // https://finder.terra.money/soju-0013/tx/36CE381BDF72AD7407EEE3859E3349F83B723BE9AD407E9D8C38DEE0C4434D29 + let restakeMessage = CosmosMessage.BeginRedelegate.with { + $0.delegatorAddress = "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe" + $0.validatorSrcAddress = "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" + $0.validatorDstAddress = "terravaloper1rhrptnx87ufpv62c7ngt9yqlz2hr77xr9nkcr9" + $0.amount = CosmosAmount.with { + $0.amount = "500000" + $0.denom = "uluna" + } + $0.typePrefix = "staking/MsgBeginRedelegate" + } + + let message = CosmosMessage.with { + $0.restakeMessage = restakeMessage + } + + let fee = CosmosFee.with { + $0.gas = 200000 + $0.amounts = [CosmosAmount.with { + $0.amount = "3000" + $0.denom = "uluna" + }] + } + + let input = CosmosSigningInput.with { + $0.accountNumber = 158 + $0.chainID = "soju-0013" + $0.memo = "" + $0.sequence = 4 + $0.messages = [message] + $0.fee = fee + $0.privateKey = privateKey.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) + + let expectedJSON = """ +{ + "mode": "block", + "tx": { + "fee": { + "amount": [{ + "amount": "3000", + "denom": "uluna" + }], + "gas": "200000" + }, + "memo": "", + "msg": [{ + "type": "staking/MsgBeginRedelegate", + "value": { + "amount": { + "amount": "500000", + "denom": "uluna" + }, + "delegator_address": "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe", + "validator_dst_address": "terravaloper1rhrptnx87ufpv62c7ngt9yqlz2hr77xr9nkcr9", + "validator_src_address": "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" + } + }], + "signatures": [{ + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk" + }, + "signature": "HyEpSz48dkebmBFvwh5xDiiZD0jUdOvzTD3ACMw0rOQ9F3JhK2cPaEx6/ZmYNIrdsPqMNkUnHcDYD1o4IztoEg==" + }] + } +} +""" + XCTAssertJSONEqual(expectedJSON, output.json) + } + + func testSigningWasmTerraTransferTxProtobuf() { + let privateKey = PrivateKey(data: Data(hexString: "cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616")!)! + let publicKey = privateKey.getPublicKeySecp256k1(compressed: true) + let fromAddress = AnyAddress(publicKey: publicKey, coin: .terra) + + let wasmTransferMessage = CosmosMessage.WasmTerraExecuteContractTransfer.with { + $0.senderAddress = fromAddress.description + $0.contractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76" // ANC + $0.amount = Data(hexString: "03D090")! // 250000 + $0.recipientAddress = "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" + } + + let message = CosmosMessage.with { + $0.wasmTerraExecuteContractTransferMessage = wasmTransferMessage + } + + let fee = CosmosFee.with { + $0.gas = 200000 + $0.amounts = [CosmosAmount.with { + $0.amount = "3000" + $0.denom = "uluna" + }] + } + + let input = CosmosSigningInput.with { + $0.signingMode = .protobuf; + $0.accountNumber = 3407705 + $0.chainID = "columbus-5" + $0.memo = "" + $0.sequence = 3 + $0.messages = [message] + $0.fee = fee + $0.privateKey = privateKey.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) + + XCTAssertJSONEqual(output.serialized, +""" +{ + "tx_bytes": "CucBCuQBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBK5AQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Glt7InRyYW5zZmVyIjp7ImFtb3VudCI6IjI1MDAwMCIsInJlY2lwaWVudCI6InRlcnJhMWpsZ2FxeTludm4yaGY1dDJzcmE5eWN6OHM3N3duZjlsMGttZ2NwIn19EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNwZjrHsPmJKW/rXOWfukpQ1+lOHOJW3/IlFFnKLNmsABIECgIIARgDEhMKDQoFdWx1bmESBDMwMDAQwJoMGkAaprIEMLPH2HmFdwFGoaipb2GIyhXt6ombz+WMnG2mORBI6gFt0M+IymYgzZz6w1SW52R922yafDnn7yXfutRw", + "mode": "BROADCAST_MODE_BLOCK" +} +""" + ) + XCTAssertEqual(output.error, "") + } + + func testSigningWasmTerraGenericProtobuf() { + let privateKey = PrivateKey(data: Data(hexString: "cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616")!)! + let publicKey = privateKey.getPublicKeySecp256k1(compressed: true) + let fromAddress = AnyAddress(publicKey: publicKey, coin: .terra) + + let wasmGenericMessage = CosmosMessage.WasmTerraExecuteContractGeneric.with { + $0.senderAddress = fromAddress.description + $0.contractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76" // ANC + $0.executeMsg = """ + {"transfer": { "amount": "250000", "recipient": "terra1d7048csap4wzcv5zm7z6tdqem2agyp9647vdyj" } } + """ + } + + let message = CosmosMessage.with { + $0.wasmTerraExecuteContractGeneric = wasmGenericMessage + } + + let fee = CosmosFee.with { + $0.gas = 200000 + $0.amounts = [CosmosAmount.with { + $0.amount = "3000" + $0.denom = "uluna" + }] + } + + let input = CosmosSigningInput.with { + $0.signingMode = .protobuf; + $0.accountNumber = 3407705 + $0.chainID = "columbus-5" + $0.memo = "" + $0.sequence = 7 + $0.messages = [message] + $0.fee = fee + $0.privateKey = privateKey.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) + + XCTAssertJSONEqual(output.serialized, + """ + { + "tx_bytes": "Cu4BCusBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLAAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2GmJ7InRyYW5zZmVyIjogeyAiYW1vdW50IjogIjI1MDAwMCIsICJyZWNpcGllbnQiOiAidGVycmExZDcwNDhjc2FwNHd6Y3Y1em03ejZ0ZHFlbTJhZ3lwOTY0N3ZkeWoiIH0gfRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYBxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAkPsS7xlSng2LMc9KiD1soN5NLaDcUh8I9okPmsdJN3le1B7yxRGNB4aQfhaRl/8Z0r5vitRT0AWuxDasd8wcFw==", + "mode": "BROADCAST_MODE_BLOCK" + } + """ + ) + XCTAssertEqual(output.error, "") + } + + func testSigningWasmTerraGenericWithCoins() { + let privateKey = PrivateKey(data: Data(hexString: "cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616")!)! + let publicKey = privateKey.getPublicKeySecp256k1(compressed: true) + let fromAddress = AnyAddress(publicKey: publicKey, coin: .terra) + + let wasmGenericMessage = CosmosMessage.WasmTerraExecuteContractGeneric.with { + $0.senderAddress = fromAddress.description + $0.contractAddress = "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s" // ANC Market + $0.executeMsg = """ + { "deposit_stable": {} } + """ + $0.coins = [CosmosAmount.with { + $0.amount = "1000" + $0.denom = "uusd" + }] + } + + let message = CosmosMessage.with { + $0.wasmTerraExecuteContractGeneric = wasmGenericMessage + } + + let fee = CosmosFee.with { + $0.gas = 600000 + $0.amounts = [CosmosAmount.with { + $0.amount = "7000" + $0.denom = "uluna" + }] + } + + let input = CosmosSigningInput.with { + $0.signingMode = .protobuf; + $0.accountNumber = 3407705 + $0.chainID = "columbus-5" + $0.memo = "" + $0.sequence = 9 + $0.messages = [message] + $0.fee = fee + $0.privateKey = privateKey.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) + + XCTAssertJSONEqual(output.serialized, + """ + { + "tx_bytes": "CrIBCq8BCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBKEAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMXNlcGZqN3MwYWVnNTk2N3V4bmZrNHRoemxlcnJza3RrcGVsbTVzGhh7ICJkZXBvc2l0X3N0YWJsZSI6IHt9IH0qDAoEdXVzZBIEMTAwMBJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYCRITCg0KBXVsdW5hEgQ3MDAwEMDPJBpAGyi7f1ioY8XV6pjFq1s86Om4++CIUnd3rLHif2iopCcYvX0mLkTlQ6NUERg8nWTYgXcj6fOTO/ptgPuAtv0NWg==", + "mode": "BROADCAST_MODE_BLOCK" + } + """ + ) + XCTAssertEqual(output.error, "") + } + } diff --git a/swift/Tests/Blockchains/TerraTests.swift b/swift/Tests/Blockchains/TerraTests.swift index d6bcceeb2aa..02a264beadf 100644 --- a/swift/Tests/Blockchains/TerraTests.swift +++ b/swift/Tests/Blockchains/TerraTests.swift @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,182 +9,81 @@ import WalletCore class TerraTests: XCTestCase { - let privateKey = PrivateKey(data: Data(hexString: "1037f828ca313f4c9e120316e8e9ff25e17f07fe66ba557d5bc5e2eeb7cba8f6")!)! + let privateKey80e8 = PrivateKey(data: Data(hexString: "80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005")!)! // terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2 + let privateKeycf08 = PrivateKey(data: Data(hexString: "cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616")!)! // terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf + let privateKey1037 = PrivateKey(data: Data(hexString: "1037f828ca313f4c9e120316e8e9ff25e17f07fe66ba557d5bc5e2eeb7cba8f6")!)! func testAddress() { - let address = CoinType.terra.deriveAddress(privateKey: privateKey) + let address = CoinType.terraV2.deriveAddress(privateKey: privateKey1037) XCTAssertEqual(address, "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe") - XCTAssertTrue(CoinType.terra.validate(address: "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms")) - XCTAssertTrue(CoinType.terra.validate(address: "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk")) - XCTAssertFalse(CoinType.terra.validate(address: "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02")) + XCTAssertTrue(CoinType.terraV2.validate(address: "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms")) + XCTAssertTrue(CoinType.terraV2.validate(address: "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk")) + XCTAssertFalse(CoinType.terraV2.validate(address: "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02")) } - func testRawJSON() { - let publicKey = privateKey.getPublicKeySecp256k1(compressed: true) - let fromAddress = AnyAddress(publicKey: publicKey, coin: .terra).description - - let message = CosmosMessage.with { - $0.rawJsonMessage = CosmosMessage.RawJSON.with { - $0.type = "bank/MsgSend" - $0.value = """ - { - "amount": [{ - "amount": "1000000", - "denom": "uluna" - }], - "from_address": "\(fromAddress)", - "to_address": "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms" - } - """ - } - } - - let fee = CosmosFee.with { - $0.gas = 200000 - $0.amounts = [CosmosAmount.with { - $0.amount = "3000" - $0.denom = "uluna" - }] - } - - let input = CosmosSigningInput.with { - $0.accountNumber = 158 - $0.chainID = "soju-0013" - $0.memo = "" - $0.sequence = 0 - $0.messages = [message] - $0.fee = fee - $0.privateKey = privateKey.data - } - - let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) - - let expectedJSON: String = -""" -{ - "mode": "block", - "tx": { - "msg": [{ - "type": "bank/MsgSend", - "value": { - "from_address": "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe", - "to_address": "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms", - "amount": [{ - "denom": "uluna", - "amount": "1000000" - }] - } - }], - "fee": { - "amount": [{ - "denom": "uluna", - "amount": "3000" - }], - "gas": "200000" - }, - "signatures": [{ - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk" - }, - "signature": "KPdiVsKpY12JG/VKEJVa/FpMKclxlS0qNNG6VOAypj10R5vY5UX5IgRJET1zNYnH0wvcXxfNXV+s8jtwN2UXiQ==" - }], - "memo": "" - } -} -""" - XCTAssertJSONEqual(expectedJSON, output.json) - } - - func testSigningTransaction() { - // https://finder.terra.money/soju-0013/tx/1403B07F2D218BCE961CB92D83377A924FEDB54C1F0B62E25C8B93B63470EBF7 - let publicKey = privateKey.getPublicKeySecp256k1(compressed: true) - let fromAddress = AnyAddress(publicKey: publicKey, coin: .terra).description + func testSignSendTx() { + let publicKey = privateKey80e8.getPublicKeySecp256k1(compressed: true) + let fromAddress = AnyAddress(publicKey: publicKey, coin: .terraV2).description + XCTAssertEqual(fromAddress, "terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2") let message = CosmosMessage.with { $0.sendCoinsMessage = CosmosMessage.Send.with { $0.fromAddress = fromAddress - $0.toAddress = "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms" + $0.toAddress = "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" $0.amounts = [CosmosAmount.with { $0.amount = "1000000" $0.denom = "uluna" }] - $0.typePrefix = "bank/MsgSend" } } let fee = CosmosFee.with { $0.gas = 200000 $0.amounts = [CosmosAmount.with { - $0.amount = "3000" + $0.amount = "30000" $0.denom = "uluna" }] } let input = CosmosSigningInput.with { - $0.accountNumber = 158 - $0.chainID = "soju-0013" + $0.signingMode = .protobuf; + $0.accountNumber = 1037 + $0.chainID = "phoenix-1" $0.memo = "" - $0.sequence = 0 + $0.sequence = 1 $0.messages = [message] $0.fee = fee - $0.privateKey = privateKey.data + $0.privateKey = privateKey80e8.data } - let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terraV2) let expectedJSON: String = -""" -{ - "mode": "block", - "tx": { - "msg": [{ - "type": "bank/MsgSend", - "value": { - "from_address": "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe", - "to_address": "terra1hdp298kaz0eezpgl6scsykxljrje3667d233ms", - "amount": [{ - "denom": "uluna", - "amount": "1000000" - }] - } - }], - "fee": { - "amount": [{ - "denom": "uluna", - "amount": "3000" - }], - "gas": "200000" - }, - "signatures": [{ - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk" - }, - "signature": "KPdiVsKpY12JG/VKEJVa/FpMKclxlS0qNNG6VOAypj10R5vY5UX5IgRJET1zNYnH0wvcXxfNXV+s8jtwN2UXiQ==" - }], - "memo": "" - } -} -""" - XCTAssertJSONEqual(expectedJSON, output.json) + """ + { + "tx_bytes": "CpEBCo4BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm4KLHRlcnJhMWhzazZqcnl5cWpmaHA1ZGhjNTV0YzlqdGNreWd4MGVwMzdoZGQyEix0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcBoQCgV1bHVuYRIHMTAwMDAwMBJoClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiECVyhuw/N9M1V7u6oACyd0SskCOqmWfK51oYHR/5H6ncUSBAoCCAEYARIUCg4KBXVsdW5hEgUzMDAwMBDAmgwaQPh0C3rjzdixIUiyPx3FlWAxzbKILNAcSRVeQnaTl1vsI5DEfYa2oYlUBLqyilcMCcU/iaJLhex30No2ak0Zn1Q=", + "mode": "BROADCAST_MODE_BLOCK" + } + """ + XCTAssertJSONEqual(expectedJSON, output.serialized) + XCTAssertEqual(output.error, "") } - func testStaking() { - // https://finder.terra.money/soju-0013/tx/4C0A6690ECB601ACB42D3ECAF4C24C0555B5E32E45B09C3B1607B144CD191F87 - let stakeMessage = CosmosMessage.Delegate.with { - $0.delegatorAddress = "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe" - $0.validatorAddress = "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" - $0.amount = CosmosAmount.with { - $0.amount = "1000000" - $0.denom = "uluna" - } - $0.typePrefix = "staking/MsgDelegate" + func testSignWasmTransferTx() { + let publicKey = privateKeycf08.getPublicKeySecp256k1(compressed: true) + let fromAddress = AnyAddress(publicKey: publicKey, coin: .terraV2).description + XCTAssertEqual(fromAddress, "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf") + + let wasmTransferMessage = CosmosMessage.WasmExecuteContractTransfer.with { + $0.senderAddress = fromAddress.description + $0.contractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76" + $0.amount = Data(hexString: "03D090")! // 250000 + $0.recipientAddress = "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" } let message = CosmosMessage.with { - $0.stakeMessage = stakeMessage + $0.wasmExecuteContractTransferMessage = wasmTransferMessage } let fee = CosmosFee.with { @@ -196,410 +95,123 @@ class TerraTests: XCTestCase { } let input = CosmosSigningInput.with { - $0.accountNumber = 158 - $0.chainID = "soju-0013" + $0.signingMode = .protobuf; + $0.accountNumber = 3407705 + $0.chainID = "phoenix-1" $0.memo = "" - $0.sequence = 1 + $0.sequence = 3 $0.messages = [message] $0.fee = fee - $0.privateKey = privateKey.data + $0.privateKey = privateKeycf08.data } - let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) - - let expectedJSON = """ -{ - "mode": "block", - "tx": { - "fee": { - "amount": [{ - "amount": "3000", - "denom": "uluna" - }], - "gas": "200000" - }, - "memo": "", - "msg": [{ - "type": "staking/MsgDelegate", - "value": { - "amount": { - "amount": "1000000", - "denom": "uluna" - }, - "delegator_address": "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe", - "validator_address": "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" - } - }], - "signatures": [{ - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk" - }, - "signature": "F8UJxbkqa0j6dYTk8PymrudBKI3WYhZImRxMFCw0ecFCmPGgNTg7yfpKZo6K6JtnoJaP7bQ4db5e4wnhMCJyAQ==" - }] - } -} -""" - XCTAssertJSONEqual(expectedJSON, output.json) - } - - func testWithdraw() { - // https://finder.terra.money/soju-0013/tx/AE0E4F2B254449950A3A7F41FABCE0B3C846D70F809380313CE3BB323E490BBD - let withdrawMessage = CosmosMessage.WithdrawDelegationReward.with { - $0.delegatorAddress = "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe" - $0.validatorAddress = "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" - $0.typePrefix = "distribution/MsgWithdrawDelegationReward" - } - - let message = CosmosMessage.with { - $0.withdrawStakeRewardMessage = withdrawMessage - } - - let fee = CosmosFee.with { - $0.amounts = [CosmosAmount.with { - $0.amount = "3000" - $0.denom = "uluna" - }] - $0.gas = 200000 - } + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terraV2) - let input = CosmosSigningInput.with { - $0.accountNumber = 158 - $0.chainID = "soju-0013" - $0.memo = "" - $0.sequence = 2 - $0.messages = [message] - $0.fee = fee - $0.privateKey = privateKey.data + XCTAssertJSONEqual(output.serialized, + """ + { + "tx_bytes": "CuUBCuIBCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QSuQEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTE0ejU2bDBmcDJsc2Y4Nnp5M2h0eTJ6NDdlemtobnRodHI5eXE3NhpbeyJ0cmFuc2ZlciI6eyJhbW91bnQiOiIyNTAwMDAiLCJyZWNpcGllbnQiOiJ0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcCJ9fRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYAxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAiBGbQaj+jsXE6/FssD3fC77QOxpli9GqsPea+KoNyMIEgVj89Hii+oU1bAEQS4qV0SaE2V6RNy24uCcFTIRbcQ==", + "mode": "BROADCAST_MODE_BLOCK" } - - let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) - - let expectedJSON = """ -{ - "mode": "block", - "tx": { - "fee": { - "amount": [{ - "amount": "3000", - "denom": "uluna" - }], - "gas": "200000" - }, - "memo": "", - "msg": [{ - "type": "distribution/MsgWithdrawDelegationReward", - "value": { - "delegator_address": "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe", - "validator_address": "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" - } - }], - "signatures": [{ - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk" - }, - "signature": "Kfwi1uJplzLucXDyQZsJI9v8lMFJFUBLD46+MpwBwYwPJgqPRzSOfyjRpmNou0G/Qe1hbsGEgqb85FQpsgLz+g==" - }] - } -} -""" - XCTAssertJSONEqual(expectedJSON, output.json) + """ + ) + XCTAssertEqual(output.error, "") } - func testUndelegate() { - // https://finder.terra.money/soju-0013/tx/FCF50C180303AECA97F916D0CE0E0937BA4C4D2F6777FFF2AA0D52A9DAF9CCBA - let unstakeMessage = CosmosMessage.Undelegate.with { - $0.delegatorAddress = "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe" - $0.validatorAddress = "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" + func testSignStakeTx() throws { + + let stakeMessage = CosmosMessage.Delegate.with { + $0.delegatorAddress = "terra1ncfyexz3nrrdru37ahqpp4wen48v7p5nany478" + $0.validatorAddress = "terravaloper1ekq8xuypdxtf3nfmffmydnhny59pjuy0p8wpn7" $0.amount = CosmosAmount.with { - $0.amount = "500000" + $0.amount = "1000000" // 5 Luna $0.denom = "uluna" } - $0.typePrefix = "staking/MsgUndelegate" } let message = CosmosMessage.with { - $0.unstakeMessage = unstakeMessage + $0.stakeMessage = stakeMessage } let fee = CosmosFee.with { - $0.gas = 200000 + $0.gas = 254682 $0.amounts = [CosmosAmount.with { - $0.amount = "3000" + $0.amount = "38203" $0.denom = "uluna" }] } let input = CosmosSigningInput.with { - $0.accountNumber = 158 - $0.chainID = "soju-0013" - $0.memo = "" - $0.sequence = 3 + $0.signingMode = .protobuf; + $0.accountNumber = 127185 + $0.chainID = "phoenix-1" + $0.sequence = 6 $0.messages = [message] $0.fee = fee - $0.privateKey = privateKey.data - } - - let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) - - let expectedJSON = """ -{ - "mode": "block", - "tx": { - "fee": { - "amount": [{ - "amount": "3000", - "denom": "uluna" - }], - "gas": "200000" - }, - "memo": "", - "msg": [{ - "type": "staking/MsgUndelegate", - "value": { - "amount": { - "amount": "500000", - "denom": "uluna" - }, - "delegator_address": "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe", - "validator_address": "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" - } - }], - "signatures": [{ - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk" - }, - "signature": "THf/RxsBr2EhHE2OMHLXfv+qSP9ORbvHgo4OSOS2P95xxGH73wW+t1zIl9cGlIVvcoChwaCg5/iEuvbgXUWpNw==" - }] - } -} -""" - XCTAssertJSONEqual(expectedJSON, output.json) - } - - func testRedlegate() { - // https://finder.terra.money/soju-0013/tx/36CE381BDF72AD7407EEE3859E3349F83B723BE9AD407E9D8C38DEE0C4434D29 - let restakeMessage = CosmosMessage.BeginRedelegate.with { - $0.delegatorAddress = "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe" - $0.validatorSrcAddress = "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" - $0.validatorDstAddress = "terravaloper1rhrptnx87ufpv62c7ngt9yqlz2hr77xr9nkcr9" - $0.amount = CosmosAmount.with { - $0.amount = "500000" - $0.denom = "uluna" - } - $0.typePrefix = "staking/MsgBeginRedelegate" - } - - let message = CosmosMessage.with { - $0.restakeMessage = restakeMessage - } - - let fee = CosmosFee.with { - $0.gas = 200000 - $0.amounts = [CosmosAmount.with { - $0.amount = "3000" - $0.denom = "uluna" - }] + $0.privateKey = privateKey1037.data // real key is terra: define... } - let input = CosmosSigningInput.with { - $0.accountNumber = 158 - $0.chainID = "soju-0013" - $0.memo = "" - $0.sequence = 4 - $0.messages = [message] - $0.fee = fee - $0.privateKey = privateKey.data + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terraV2) + let expected = """ + { + "mode": "BROADCAST_MODE_BLOCK", + "tx_bytes": "Cp8BCpwBCiMvY29zbW9zLnN0YWtpbmcudjFiZXRhMS5Nc2dEZWxlZ2F0ZRJ1Cix0ZXJyYTFuY2Z5ZXh6M25ycmRydTM3YWhxcHA0d2VuNDh2N3A1bmFueTQ3OBIzdGVycmF2YWxvcGVyMWVrcTh4dXlwZHh0ZjNuZm1mZm15ZG5obnk1OXBqdXkwcDh3cG43GhAKBXVsdW5hEgcxMDAwMDAwEmgKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNd8YVWZSHWp4AjGe4G4aKOl7d3Lftf3RPKbwV1UYlo5BIECgIIARgGEhQKDgoFdWx1bmESBTM4MjAzENrFDxpAamKyAvWhWCv0nUKz7yiYETpkZETflDvfe1vmuFIy31g+s0u1cgLNo+7jBRXRuzYJXukigtwoLUrxY/C8rowiJw==" } + """ - let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) - - let expectedJSON = """ -{ - "mode": "block", - "tx": { - "fee": { - "amount": [{ - "amount": "3000", - "denom": "uluna" - }], - "gas": "200000" - }, - "memo": "", - "msg": [{ - "type": "staking/MsgBeginRedelegate", - "value": { - "amount": { - "amount": "500000", - "denom": "uluna" - }, - "delegator_address": "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe", - "validator_dst_address": "terravaloper1rhrptnx87ufpv62c7ngt9yqlz2hr77xr9nkcr9", - "validator_src_address": "terravaloper1pdx498r0hrc2fj36sjhs8vuhrz9hd2cw0yhqtk" - } - }], - "signatures": [{ - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjk" - }, - "signature": "HyEpSz48dkebmBFvwh5xDiiZD0jUdOvzTD3ACMw0rOQ9F3JhK2cPaEx6/ZmYNIrdsPqMNkUnHcDYD1o4IztoEg==" - }] - } -} -""" - XCTAssertJSONEqual(expectedJSON, output.json) + // https://finder.terra.money/mainnet/tx/4441c65f24783b8f59b20b1b80ee43f1f4f6ff827597d87b6bbc94982b45be0c + XCTAssertJSONEqual(output.serialized, expected) + XCTAssertEqual(output.error, "") } - func testSigningWasmTerraTransferTxProtobuf() { - let privateKey = PrivateKey(data: Data(hexString: "cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616")!)! - let publicKey = privateKey.getPublicKeySecp256k1(compressed: true) - let fromAddress = AnyAddress(publicKey: publicKey, coin: .terra) + func testSignClaimRewards() throws { + let delegator = "terra1ncfyexz3nrrdru37ahqpp4wen48v7p5nany478" + let validators = [ + "terravaloper1ekq8xuypdxtf3nfmffmydnhny59pjuy0p8wpn7" + ] - let wasmTransferMessage = CosmosMessage.WasmTerraExecuteContractTransfer.with { - $0.senderAddress = fromAddress.description - $0.contractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76" // ANC - $0.amount = Data(hexString: "03D090")! // 250000 - $0.recipientAddress = "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" - } - - let message = CosmosMessage.with { - $0.wasmTerraExecuteContractTransferMessage = wasmTransferMessage + let withdrawals = validators.map { validator in + CosmosMessage.WithdrawDelegationReward.with { + $0.delegatorAddress = delegator + $0.validatorAddress = validator + } + }.map { withdraw in + CosmosMessage.with { + $0.withdrawStakeRewardMessage = withdraw + } } let fee = CosmosFee.with { - $0.gas = 200000 $0.amounts = [CosmosAmount.with { - $0.amount = "3000" + $0.amount = "29513" $0.denom = "uluna" }] + $0.gas = 196749 } let input = CosmosSigningInput.with { $0.signingMode = .protobuf; - $0.accountNumber = 3407705 - $0.chainID = "columbus-5" - $0.memo = "" - $0.sequence = 3 - $0.messages = [message] $0.fee = fee - $0.privateKey = privateKey.data + $0.accountNumber = 127185 + $0.chainID = "phoenix-1" + $0.sequence = 5 + $0.messages = withdrawals + $0.fee = fee + $0.privateKey = privateKey1037.data // real key is terra: define... } - let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) - - XCTAssertJSONEqual(output.serialized, -""" -{ - "tx_bytes": "CucBCuQBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBK5AQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Glt7InRyYW5zZmVyIjp7ImFtb3VudCI6IjI1MDAwMCIsInJlY2lwaWVudCI6InRlcnJhMWpsZ2FxeTludm4yaGY1dDJzcmE5eWN6OHM3N3duZjlsMGttZ2NwIn19EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNwZjrHsPmJKW/rXOWfukpQ1+lOHOJW3/IlFFnKLNmsABIECgIIARgDEhMKDQoFdWx1bmESBDMwMDAQwJoMGkAaprIEMLPH2HmFdwFGoaipb2GIyhXt6ombz+WMnG2mORBI6gFt0M+IymYgzZz6w1SW52R922yafDnn7yXfutRw", - "mode": "BROADCAST_MODE_BLOCK" -} -""" - ) - XCTAssertEqual(output.error, "") - } - - func testSigningWasmTerraGenericProtobuf() { - let privateKey = PrivateKey(data: Data(hexString: "cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616")!)! - let publicKey = privateKey.getPublicKeySecp256k1(compressed: true) - let fromAddress = AnyAddress(publicKey: publicKey, coin: .terra) - - let wasmGenericMessage = CosmosMessage.WasmTerraExecuteContractGeneric.with { - $0.senderAddress = fromAddress.description - $0.contractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76" // ANC - $0.executeMsg = """ - {"transfer": { "amount": "250000", "recipient": "terra1d7048csap4wzcv5zm7z6tdqem2agyp9647vdyj" } } - """ - } - - let message = CosmosMessage.with { - $0.wasmTerraExecuteContractGeneric = wasmGenericMessage - } - - let fee = CosmosFee.with { - $0.gas = 200000 - $0.amounts = [CosmosAmount.with { - $0.amount = "3000" - $0.denom = "uluna" - }] - } - - let input = CosmosSigningInput.with { - $0.signingMode = .protobuf; - $0.accountNumber = 3407705 - $0.chainID = "columbus-5" - $0.memo = "" - $0.sequence = 7 - $0.messages = [message] - $0.fee = fee - $0.privateKey = privateKey.data - } - - let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terraV2) - XCTAssertJSONEqual(output.serialized, - """ - { - "tx_bytes": "Cu4BCusBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLAAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2GmJ7InRyYW5zZmVyIjogeyAiYW1vdW50IjogIjI1MDAwMCIsICJyZWNpcGllbnQiOiAidGVycmExZDcwNDhjc2FwNHd6Y3Y1em03ejZ0ZHFlbTJhZ3lwOTY0N3ZkeWoiIH0gfRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYBxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAkPsS7xlSng2LMc9KiD1soN5NLaDcUh8I9okPmsdJN3le1B7yxRGNB4aQfhaRl/8Z0r5vitRT0AWuxDasd8wcFw==", - "mode": "BROADCAST_MODE_BLOCK" - } - """ - ) - XCTAssertEqual(output.error, "") + let expected = """ + { + "mode": "BROADCAST_MODE_BLOCK", + "tx_bytes": "CqEBCp4BCjcvY29zbW9zLmRpc3RyaWJ1dGlvbi52MWJldGExLk1zZ1dpdGhkcmF3RGVsZWdhdG9yUmV3YXJkEmMKLHRlcnJhMW5jZnlleHozbnJyZHJ1MzdhaHFwcDR3ZW40OHY3cDVuYW55NDc4EjN0ZXJyYXZhbG9wZXIxZWtxOHh1eXBkeHRmM25mbWZmbXlkbmhueTU5cGp1eTBwOHdwbjcSaApQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA13xhVZlIdangCMZ7gbhoo6Xt3ct+1/dE8pvBXVRiWjkEgQKAggBGAUSFAoOCgV1bHVuYRIFMjk1MTMQjYEMGkA/bh2va6RRZvkSLnej84dJgSSvbgcHgYDbkRt8wDge03W747BZcuBcg/U5EuE7zBqSJrKUTZl7oUCp//rYlJKV" } + """ - func testSigningWasmTerraGenericWithCoins() { - let privateKey = PrivateKey(data: Data(hexString: "cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616")!)! - let publicKey = privateKey.getPublicKeySecp256k1(compressed: true) - let fromAddress = AnyAddress(publicKey: publicKey, coin: .terra) - - let wasmGenericMessage = CosmosMessage.WasmTerraExecuteContractGeneric.with { - $0.senderAddress = fromAddress.description - $0.contractAddress = "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s" // ANC Market - $0.executeMsg = """ - { "deposit_stable": {} } - """ - $0.coins = [CosmosAmount.with { - $0.amount = "1000" - $0.denom = "uusd" - }] - } - - let message = CosmosMessage.with { - $0.wasmTerraExecuteContractGeneric = wasmGenericMessage - } - - let fee = CosmosFee.with { - $0.gas = 600000 - $0.amounts = [CosmosAmount.with { - $0.amount = "7000" - $0.denom = "uluna" - }] - } - - let input = CosmosSigningInput.with { - $0.signingMode = .protobuf; - $0.accountNumber = 3407705 - $0.chainID = "columbus-5" - $0.memo = "" - $0.sequence = 9 - $0.messages = [message] - $0.fee = fee - $0.privateKey = privateKey.data - } - - let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .terra) - - XCTAssertJSONEqual(output.serialized, - """ - { - "tx_bytes": "CrIBCq8BCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBKEAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMXNlcGZqN3MwYWVnNTk2N3V4bmZrNHRoemxlcnJza3RrcGVsbTVzGhh7ICJkZXBvc2l0X3N0YWJsZSI6IHt9IH0qDAoEdXVzZBIEMTAwMBJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYCRITCg0KBXVsdW5hEgQ3MDAwEMDPJBpAGyi7f1ioY8XV6pjFq1s86Om4++CIUnd3rLHif2iopCcYvX0mLkTlQ6NUERg8nWTYgXcj6fOTO/ptgPuAtv0NWg==", - "mode": "BROADCAST_MODE_BLOCK" - } - """ - ) - XCTAssertEqual(output.error, "") - } + // https://finder.terra.money/mainnet/tx/0e62170ed5407992251d7e161f23c3467e1bea54c7f601953953bdabc7f0c30c + XCTAssertJSONEqual(output.serialized, expected) + XCTAssertEqual(output.error, "") } + +} diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 0fed0294bc1..562e7c019bd 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -175,7 +175,8 @@ class CoinAddressDerivationTests: XCTestCase { case .stellar: let expectedResult = "GA3H6I4C5XUBYGVB66KXR27JV5KS3APSTKRUWOIXZ5MVWZKVTLXWKZ2P" assertCoinDerivation(coin, expectedResult, derivedAddress, address) - case .terra: + case .terra, + .terraV2: let expectedResult = "terra1rh402g98t7sly8trzqw5cyracntlep6qe3smug" assertCoinDerivation(coin, expectedResult, derivedAddress, address) case .tezos: diff --git a/swift/Tests/HDWalletTests.swift b/swift/Tests/HDWalletTests.swift index 4267fed457d..e6e5b8b6b46 100644 --- a/swift/Tests/HDWalletTests.swift +++ b/swift/Tests/HDWalletTests.swift @@ -386,10 +386,10 @@ class HDWalletTests: XCTestCase { XCTAssertEqual("RHQmrg7nNFnRUwg2mH7GafhRY3ZaF6FB2x", address) } - func testDeriveTerra() { - let coin = CoinType.terra + func testDeriveTerraV2() { + let coin = CoinType.terraV2 let key = HDWallet.test.getKeyForCoin(coin: coin) - let address = CoinType.terra.deriveAddress(privateKey: key) + let address = CoinType.terraV2.deriveAddress(privateKey: key) XCTAssertEqual(address, "terra1jf9aaj9myrzsnmpdr7twecnaftzmku2mhs2hfe") } diff --git a/tests/Terra/SignerTests.cpp b/tests/Terra/SignerTests.cpp index 2dd1777d43e..eed38ba3adf 100644 --- a/tests/Terra/SignerTests.cpp +++ b/tests/Terra/SignerTests.cpp @@ -20,94 +20,91 @@ using namespace TW; using namespace TW::Cosmos; - TEST(TerraSigner, SignSendTx) { auto input = Proto::SigningInput(); - input.set_signing_mode(Proto::JSON); + input.set_signing_mode(Proto::Protobuf); input.set_account_number(1037); - input.set_chain_id("columbus-5"); + input.set_chain_id("phoenix-1"); input.set_memo(""); - input.set_sequence(2); + input.set_sequence(1); Address fromAddress; ASSERT_TRUE(Address::decode("terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2", fromAddress)); Address toAddress; - ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", toAddress)); + ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); auto msg = input.add_messages(); auto& message = *msg->mutable_send_coins_message(); message.set_from_address(fromAddress.string()); message.set_to_address(toAddress.string()); auto amountOfTx = message.add_amounts(); - amountOfTx->set_denom("luna"); + amountOfTx->set_denom("uluna"); amountOfTx->set_amount("1000000"); auto& fee = *input.mutable_fee(); fee.set_gas(200000); auto amountOfFee = fee.add_amounts(); - amountOfFee->set_denom("luna"); - amountOfFee->set_amount("200"); - - std::string json; - google::protobuf::util::MessageToJsonString(input, &json); - EXPECT_EQ(json, R"({"accountNumber":"1037","chainId":"columbus-5","fee":{"amounts":[{"denom":"luna","amount":"200"}],"gas":"200000"},"sequence":"2","messages":[{"sendCoinsMessage":{"fromAddress":"terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2","toAddress":"terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf","amounts":[{"denom":"luna","amount":"1000000"}]}}]})"); - - auto privateKey = parse_hex("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005"); - input.set_private_key(privateKey.data(), privateKey.size()); - - auto output = Signer::sign(input, TWCoinTypeTerra); - - assertJSONEqual(output.json(), R"( - { - "mode": "block", - "tx": { + amountOfFee->set_denom("uluna"); + amountOfFee->set_amount("30000"); + + { + std::string json; + google::protobuf::util::MessageToJsonString(input, &json); + assertJSONEqual(json, R"( + { + "signingMode": "Protobuf", + "accountNumber": "1037", + "chainId": "phoenix-1", "fee": { - "amount": [ + "amounts": [ { - "amount": "200", - "denom": "luna" + "denom": "uluna", + "amount": "30000" } ], "gas": "200000" }, - "memo": "", - "msg": [ + "sequence": "1", + "messages": [ { - "type": "cosmos-sdk/MsgSend", - "value": { - "amount": [ + "sendCoinsMessage": { + "fromAddress": "terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2", + "toAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", + "amounts": [ { - "amount": "1000000", - "denom": "luna" + "denom": "uluna", + "amount": "1000000" } - ], - "from_address": "terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2", - "to_address": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf" + ] } } - ], - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "AlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3F" - }, - "signature": "ofdIsLJzkODcQwLG89eE2g4HOaUmfKPh/08t07ehKPUqRMl4rVonzo73mkOvqtrHWjdtB+6t6R8DGudPpb6bRg==" - } ] } + )"); + } + + auto privateKey = parse_hex("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerraV2); + + // similar tx: https://finder.terra.money/mainnet/tx/fbbe73ad2f0db3a13911dc424f8a34370dc4b7e8b66687f536797e68ee200ece + assertJSONEqual(output.serialized(), R"( + { + "tx_bytes": "CpEBCo4BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm4KLHRlcnJhMWhzazZqcnl5cWpmaHA1ZGhjNTV0YzlqdGNreWd4MGVwMzdoZGQyEix0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcBoQCgV1bHVuYRIHMTAwMDAwMBJoClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiECVyhuw/N9M1V7u6oACyd0SskCOqmWfK51oYHR/5H6ncUSBAoCCAEYARIUCg4KBXVsdW5hEgUzMDAwMBDAmgwaQPh0C3rjzdixIUiyPx3FlWAxzbKILNAcSRVeQnaTl1vsI5DEfYa2oYlUBLqyilcMCcU/iaJLhex30No2ak0Zn1Q=", + "mode": "BROADCAST_MODE_BLOCK" } )"); - EXPECT_EQ(hex(output.signature()), "a1f748b0b27390e0dc4302c6f3d784da0e0739a5267ca3e1ff4f2dd3b7a128f52a44c978ad5a27ce8ef79a43afaadac75a376d07eeade91f031ae74fa5be9b46"); - EXPECT_EQ(output.serialized(), ""); + EXPECT_EQ(hex(output.signature()), "f8740b7ae3cdd8b12148b23f1dc5956031cdb2882cd01c49155e427693975bec2390c47d86b6a1895404bab28a570c09c53f89a24b85ec77d0da366a4d199f54"); EXPECT_EQ(output.error(), ""); + EXPECT_EQ(output.json(), ""); } -TEST(TerraSigner, SignWasmTransferTxProtobuf_9FF3F0) { +TEST(TerraSigner, SignWasmTransferTx) { auto input = Proto::SigningInput(); input.set_signing_mode(Proto::Protobuf); input.set_account_number(3407705); - input.set_chain_id("columbus-5"); + input.set_chain_id("phoenix-1"); input.set_memo(""); input.set_sequence(3); @@ -115,10 +112,10 @@ TEST(TerraSigner, SignWasmTransferTxProtobuf_9FF3F0) { ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); Address toAddress; ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); - const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_terra_execute_contract_transfer_message(); + auto& message = *msg->mutable_wasm_execute_contract_transfer_message(); message.set_sender_address(fromAddress.string()); message.set_contract_address(tokenContractAddress); const auto amount = store(uint256_t(250000), 0); @@ -131,151 +128,69 @@ TEST(TerraSigner, SignWasmTransferTxProtobuf_9FF3F0) { amountOfFee->set_denom("uluna"); amountOfFee->set_amount("3000"); - std::string json; - google::protobuf::util::MessageToJsonString(input, &json); - assertJSONEqual(json, R"( - { - "signingMode": "Protobuf", - "accountNumber": "3407705", - "chainId": "columbus-5", - "fee": { - "amounts": [ + { + std::string json; + google::protobuf::util::MessageToJsonString(input, &json); + assertJSONEqual(json, R"( + { + "signingMode": "Protobuf", + "accountNumber": "3407705", + "chainId": "phoenix-1", + "fee": { + "amounts": [ + { + "denom": "uluna", + "amount": "3000" + } + ], + "gas": "200000" + }, + "sequence": "3", + "messages": [ { - "denom": "uluna", - "amount": "3000" - } - ], - "gas": "200000" - }, - "sequence": "3", - "messages": [ - { - "wasmTerraExecuteContractTransferMessage": { - "senderAddress": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", - "contractAddress": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", - "amount": "A9CQ", - "recipientAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" + "wasmExecuteContractTransferMessage": { + "senderAddress": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", + "contractAddress": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", + "amount": "A9CQ", + "recipientAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" + } } - } - ] - } - )"); + ] + } + )"); + } auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); input.set_private_key(privateKey.data(), privateKey.size()); - auto output = Signer::sign(input, TWCoinTypeTerra); + auto output = Signer::sign(input, TWCoinTypeTerraV2); - // https://finder.terra.money/mainnet/tx/9FF3F0A16879254C22EB90D8B4D6195467FE5014381FD36BD3C23CA6698FE94B - // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "CogCCo..wld8"})' https:///cosmos/tx/v1beta1/txs assertJSONEqual(output.serialized(), R"( { - "tx_bytes": "CucBCuQBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBK5AQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Glt7InRyYW5zZmVyIjp7ImFtb3VudCI6IjI1MDAwMCIsInJlY2lwaWVudCI6InRlcnJhMWpsZ2FxeTludm4yaGY1dDJzcmE5eWN6OHM3N3duZjlsMGttZ2NwIn19EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNwZjrHsPmJKW/rXOWfukpQ1+lOHOJW3/IlFFnKLNmsABIECgIIARgDEhMKDQoFdWx1bmESBDMwMDAQwJoMGkAaprIEMLPH2HmFdwFGoaipb2GIyhXt6ombz+WMnG2mORBI6gFt0M+IymYgzZz6w1SW52R922yafDnn7yXfutRw", + "tx_bytes": "CuUBCuIBCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QSuQEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTE0ejU2bDBmcDJsc2Y4Nnp5M2h0eTJ6NDdlemtobnRodHI5eXE3NhpbeyJ0cmFuc2ZlciI6eyJhbW91bnQiOiIyNTAwMDAiLCJyZWNpcGllbnQiOiJ0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcCJ9fRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYAxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAiBGbQaj+jsXE6/FssD3fC77QOxpli9GqsPea+KoNyMIEgVj89Hii+oU1bAEQS4qV0SaE2V6RNy24uCcFTIRbcQ==", "mode": "BROADCAST_MODE_BLOCK" } )"); - EXPECT_EQ(hex(output.signature()), "1aa6b20430b3c7d87985770146a1a8a96f6188ca15edea899bcfe58c9c6da6391048ea016dd0cf88ca6620cd9cfac35496e7647ddb6c9a7c39e7ef25dfbad470"); - EXPECT_EQ(output.json(), ""); - EXPECT_EQ(output.error(), ""); -} - -TEST(TerraSigner, SignWasmTransferTxJson_078E90) { - auto input = Proto::SigningInput(); - input.set_signing_mode(Proto::JSON); - input.set_account_number(3407705); - input.set_chain_id("columbus-5"); - input.set_memo(""); - input.set_sequence(2); - - Address fromAddress; - ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); - Address toAddress; - ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); - const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC - - auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_terra_execute_contract_transfer_message(); - message.set_sender_address(fromAddress.string()); - message.set_contract_address(tokenContractAddress); - const auto amount = store(250000); - message.set_amount(amount.data(), amount.size()); - message.set_recipient_address(toAddress.string()); - - auto& fee = *input.mutable_fee(); - fee.set_gas(200000); - auto amountOfFee = fee.add_amounts(); - amountOfFee->set_denom("uluna"); - amountOfFee->set_amount("3000"); - - auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); - input.set_private_key(privateKey.data(), privateKey.size()); - - auto output = Signer::sign(input, TWCoinTypeTerra); - - // https://finder.terra.money/mainnet/tx/078E90458061611F6FD8B708882B55FF5C1FFB3FCE61322107A0A0DE39FC0F3E - // curl -H 'Content-Type: application/json' --data-binary '{"mode": "block","tx":{...}}' https:///txs - assertJSONEqual(output.json(), R"( - { - "mode": "block", - "tx": - { - "fee": {"amount":[{"amount": "3000","denom": "uluna"}],"gas": "200000"}, - "memo": "", - "msg": - [ - { - "type": "wasm/MsgExecuteContract", - "value": - { - "sender": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", - "contract": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", - "execute_msg": - { - "transfer": - { - "amount": "250000", - "recipient": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" - } - }, - "coins": [] - } - } - ], - "signatures": - [ - { - "pub_key": - { - "type": "tendermint/PubKeySecp256k1", - "value": "A3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awA" - }, - "signature": "BjETdtbA97Wv1zvcsCV1tM+bdYKC8O3uGTk4mMRv6pBJB2y/Ds7qoS7s/zrkhYak1YChklQetHsI30XRXzGIkg==" - } - ] - } - })"); - EXPECT_EQ(hex(output.signature()), "06311376d6c0f7b5afd73bdcb02575b4cf9b758282f0edee19393898c46fea9049076cbf0eceeaa12eecff3ae48586a4d580a192541eb47b08df45d15f318892"); - EXPECT_EQ(output.serialized(), ""); + EXPECT_EQ(hex(output.signature()), "88119b41a8fe8ec5c4ebf16cb03ddf0bbed03b1a658bd1aab0f79af8aa0dc8c2048158fcf478a2fa85356c01104b8a95d12684d95e91372db8b827054c845b71"); EXPECT_EQ(output.error(), ""); + EXPECT_EQ(output.json(), ""); } -TEST(TerraSigner, SignWasmGeneric_EC4F85) { +TEST(TerraSigner, SignWasmGeneric) { auto input = Proto::SigningInput(); input.set_signing_mode(Proto::Protobuf); input.set_account_number(3407705); - input.set_chain_id("columbus-5"); + input.set_chain_id("phoenix-1"); input.set_memo(""); input.set_sequence(7); Address fromAddress; ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); - Address toAddress; - ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); - const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; const auto txMessage = R"({"transfer": { "amount": "250000", "recipient": "terra1d7048csap4wzcv5zm7z6tdqem2agyp9647vdyj" } })"; auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_terra_execute_contract_generic(); + auto& message = *msg->mutable_wasm_execute_contract_generic(); message.set_sender_address(fromAddress.string()); message.set_contract_address(tokenContractAddress); message.set_execute_msg(txMessage); @@ -289,40 +204,35 @@ TEST(TerraSigner, SignWasmGeneric_EC4F85) { auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); input.set_private_key(privateKey.data(), privateKey.size()); - auto output = Signer::sign(input, TWCoinTypeTerra); + auto output = Signer::sign(input, TWCoinTypeTerraV2); - // https://finder.terra.money/mainnet/tx/EC4F8532847E4D6AF016E6F6D3F027AE7FB6FF0B533C5132B01382D83B214A6F - // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "Cu4BC...iVt"})' https:///cosmos/tx/v1beta1/txs assertJSONEqual(output.serialized(), R"( { - "tx_bytes": "Cu4BCusBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLAAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2GmJ7InRyYW5zZmVyIjogeyAiYW1vdW50IjogIjI1MDAwMCIsICJyZWNpcGllbnQiOiAidGVycmExZDcwNDhjc2FwNHd6Y3Y1em03ejZ0ZHFlbTJhZ3lwOTY0N3ZkeWoiIH0gfRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYBxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAkPsS7xlSng2LMc9KiD1soN5NLaDcUh8I9okPmsdJN3le1B7yxRGNB4aQfhaRl/8Z0r5vitRT0AWuxDasd8wcFw==", + "tx_bytes": "CuwBCukBCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QSwAEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTE0ejU2bDBmcDJsc2Y4Nnp5M2h0eTJ6NDdlemtobnRodHI5eXE3NhpieyJ0cmFuc2ZlciI6IHsgImFtb3VudCI6ICIyNTAwMDAiLCAicmVjaXBpZW50IjogInRlcnJhMWQ3MDQ4Y3NhcDR3emN2NXptN3o2dGRxZW0yYWd5cDk2NDd2ZHlqIiB9IH0SZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awAEgQKAggBGAcSEwoNCgV1bHVuYRIEMzAwMBDAmgwaQGlYzOoAu/PfyCTSTisGJVW9KWwifxMbCmzy2xwqNg+ZHQkDjVRyUBl7gmbXXLzdOMqtwF1CMauJhlGwmEdzhK4=", "mode": "BROADCAST_MODE_BLOCK" } )"); - EXPECT_EQ(hex(output.signature()), "90fb12ef19529e0d8b31cf4a883d6ca0de4d2da0dc521f08f6890f9ac74937795ed41ef2c5118d0786907e169197ff19d2be6f8ad453d005aec436ac77cc1c17"); - EXPECT_EQ(output.json(), ""); + EXPECT_EQ(hex(output.signature()), "6958ccea00bbf3dfc824d24e2b062555bd296c227f131b0a6cf2db1c2a360f991d09038d547250197b8266d75cbcdd38caadc05d4231ab898651b098477384ae"); EXPECT_EQ(output.error(), ""); + EXPECT_EQ(output.json(), ""); } - -TEST(TerraSigner, SignWasmGenericWithCoins_6651FC) { +TEST(TerraSigner, SignWasmGenericWithCoins) { auto input = Proto::SigningInput(); input.set_signing_mode(Proto::Protobuf); input.set_account_number(3407705); - input.set_chain_id("columbus-5"); + input.set_chain_id("phoenix-1"); input.set_memo(""); input.set_sequence(9); Address fromAddress; ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); - Address toAddress; - ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); - const auto tokenContractAddress = "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s"; // ANC Market + const auto tokenContractAddress = "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s"; const auto txMessage = R"({ "deposit_stable": {} })"; auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_terra_execute_contract_generic(); + auto& message = *msg->mutable_wasm_execute_contract_generic(); message.set_sender_address(fromAddress.string()); message.set_contract_address(tokenContractAddress); message.set_execute_msg(txMessage); @@ -340,27 +250,25 @@ TEST(TerraSigner, SignWasmGenericWithCoins_6651FC) { auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); input.set_private_key(privateKey.data(), privateKey.size()); - auto output = Signer::sign(input, TWCoinTypeTerra); + auto output = Signer::sign(input, TWCoinTypeTerraV2); - // https://finder.terra.money/mainnet/tx/6651FCE0EE5C6D6ACB655CC49A6FD5E939FB082862854616EA0642475BCDD0C9 - // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "CrIBCq8B.....0NWg=="})' https:///cosmos/tx/v1beta1/txs assertJSONEqual(output.serialized(), R"( { - "tx_bytes": "CrIBCq8BCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBKEAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMXNlcGZqN3MwYWVnNTk2N3V4bmZrNHRoemxlcnJza3RrcGVsbTVzGhh7ICJkZXBvc2l0X3N0YWJsZSI6IHt9IH0qDAoEdXVzZBIEMTAwMBJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYCRITCg0KBXVsdW5hEgQ3MDAwEMDPJBpAGyi7f1ioY8XV6pjFq1s86Om4++CIUnd3rLHif2iopCcYvX0mLkTlQ6NUERg8nWTYgXcj6fOTO/ptgPuAtv0NWg==", + "tx_bytes": "CrABCq0BCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QShAEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTFzZXBmajdzMGFlZzU5Njd1eG5mazR0aHpsZXJyc2t0a3BlbG01cxoYeyAiZGVwb3NpdF9zdGFibGUiOiB7fSB9KgwKBHV1c2QSBDEwMDASZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awAEgQKAggBGAkSEwoNCgV1bHVuYRIENzAwMBDAzyQaQEDA2foXegF+rslj6o8bX2HPJfn+q/6Ezbq2iAd0SFOTQqS8aAyywQkdZJRToXcaby1HOYL1WvmsMPgrFzChiY4=", "mode": "BROADCAST_MODE_BLOCK" } )"); - EXPECT_EQ(hex(output.signature()), "1b28bb7f58a863c5d5ea98c5ab5b3ce8e9b8fbe088527777acb1e27f68a8a42718bd7d262e44e543a35411183c9d64d8817723e9f3933bfa6d80fb80b6fd0d5a"); - EXPECT_EQ(output.json(), ""); + EXPECT_EQ(hex(output.signature()), "40c0d9fa177a017eaec963ea8f1b5f61cf25f9feabfe84cdbab688077448539342a4bc680cb2c1091d649453a1771a6f2d473982f55af9ac30f82b1730a1898e"); EXPECT_EQ(output.error(), ""); + EXPECT_EQ(output.json(), ""); } -TEST(TerraSigner, SignWasmSendTxProtobuf) { +TEST(TerraSigner, SignWasmSendTx) { auto input = Proto::SigningInput(); input.set_signing_mode(Proto::Protobuf); input.set_account_number(3407705); - input.set_chain_id("columbus-5"); + input.set_chain_id("phoenix-1"); input.set_memo(""); input.set_sequence(4); @@ -368,10 +276,10 @@ TEST(TerraSigner, SignWasmSendTxProtobuf) { ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); Address toAddress; ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); - const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_terra_execute_contract_send_message(); + auto& message = *msg->mutable_wasm_execute_contract_send_message(); message.set_sender_address(fromAddress.string()); message.set_contract_address(tokenContractAddress); const auto amount = store(uint256_t(250000), 0); @@ -393,7 +301,7 @@ TEST(TerraSigner, SignWasmSendTxProtobuf) { { "signingMode": "Protobuf", "accountNumber": "3407705", - "chainId": "columbus-5", + "chainId": "phoenix-1", "fee": { "amounts": [ { @@ -406,7 +314,7 @@ TEST(TerraSigner, SignWasmSendTxProtobuf) { "sequence": "4", "messages": [ { - "wasmTerraExecuteContractSendMessage": { + "wasmExecuteContractSendMessage": { "senderAddress": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", "contractAddress": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", "amount": "A9CQ", @@ -421,28 +329,26 @@ TEST(TerraSigner, SignWasmSendTxProtobuf) { auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); input.set_private_key(privateKey.data(), privateKey.size()); - auto output = Signer::sign(input, TWCoinTypeTerra); + auto output = Signer::sign(input, TWCoinTypeTerraV2); - // https://finder.terra.money/mainnet/tx/9FF3F0A16879254C22EB90D8B4D6195467FE5014381FD36BD3C23CA6698FE94B - // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "CogCCo..wld8"})' https:///cosmos/tx/v1beta1/txs assertJSONEqual(output.serialized(), R"( { - "tx_bytes": "CocCCoQCCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLZAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Gnt7InNlbmQiOnsiYW1vdW50IjoiMjUwMDAwIiwiY29udHJhY3QiOiJ0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcCIsIm1zZyI6ImV5SnpiMjFsWDIxbGMzTmhaMlVpT250OWZRPT0ifX0SZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awAEgQKAggBGAQSEwoNCgV1bHVuYRIEMzAwMBDAmgwaQL6NByKeRZsyq5g6CTMdmPqiM77nOe9uLO8FjpetFgkBFiG3Le7ieZZ+4vCMhD1bcFgMwSHibFI/uPil847U/+g=", + "tx_bytes": "CoUCCoICCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QS2QEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTE0ejU2bDBmcDJsc2Y4Nnp5M2h0eTJ6NDdlemtobnRodHI5eXE3Nhp7eyJzZW5kIjp7ImFtb3VudCI6IjI1MDAwMCIsImNvbnRyYWN0IjoidGVycmExamxnYXF5OW52bjJoZjV0MnNyYTl5Y3o4czc3d25mOWwwa21nY3AiLCJtc2ciOiJleUp6YjIxbFgyMWxjM05oWjJVaU9udDlmUT09In19EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNwZjrHsPmJKW/rXOWfukpQ1+lOHOJW3/IlFFnKLNmsABIECgIIARgEEhMKDQoFdWx1bmESBDMwMDAQwJoMGkBKJbW1GDrv9j2FIckm7MtpDZzP2RjgDjU84oYmOHNHsxEBPLjtt3YAjsKWBCAsjbnbVoJ3s2XFG08nxQXS9xBK", "mode": "BROADCAST_MODE_BLOCK" } )"); - EXPECT_EQ(hex(output.signature()), "be8d07229e459b32ab983a09331d98faa233bee739ef6e2cef058e97ad1609011621b72deee279967ee2f08c843d5b70580cc121e26c523fb8f8a5f38ed4ffe8"); - EXPECT_EQ(output.json(), ""); + EXPECT_EQ(hex(output.signature()), "4a25b5b5183aeff63d8521c926eccb690d9ccfd918e00e353ce28626387347b311013cb8edb776008ec29604202c8db9db568277b365c51b4f27c505d2f7104a"); EXPECT_EQ(output.error(), ""); + EXPECT_EQ(output.json(), ""); } -TEST(TerraSigner, SignWasmTerraTransferPayload) { - auto proto = Proto::Message_WasmTerraExecuteContractTransfer(); +TEST(TerraSigner, SignWasmTransferPayload) { + auto proto = Proto::Message_WasmExecuteContractTransfer(); proto.set_recipient_address("recipient=address"); const auto amount = store(uint256_t(250000), 0); proto.set_amount(amount.data(), amount.size()); - const auto payload = wasmTerraExecuteTransferPayload(proto); + const auto payload = wasmExecuteTransferPayload(proto); assertJSONEqual(payload.dump(), R"( { diff --git a/tests/Terra/SignerTestsClassic.cpp b/tests/Terra/SignerTestsClassic.cpp new file mode 100644 index 00000000000..f77f59da050 --- /dev/null +++ b/tests/Terra/SignerTestsClassic.cpp @@ -0,0 +1,456 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Coin.h" +#include "HexCoding.h" +#include "Base64.h" +#include "proto/Cosmos.pb.h" +#include "Cosmos/Address.h" +#include "Cosmos/Signer.h" +#include "Cosmos/ProtobufSerialization.h" +#include "uint256.h" +#include "../interface/TWTestUtilities.h" + +#include +#include + +using namespace TW; +using namespace TW::Cosmos; + + +TEST(TerraClassicSigner, SignSendTx) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::JSON); + input.set_account_number(1037); + input.set_chain_id("columbus-5"); + input.set_memo(""); + input.set_sequence(2); + + Address fromAddress; + ASSERT_TRUE(Address::decode("terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2", fromAddress)); + Address toAddress; + ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", toAddress)); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_send_coins_message(); + message.set_from_address(fromAddress.string()); + message.set_to_address(toAddress.string()); + auto amountOfTx = message.add_amounts(); + amountOfTx->set_denom("luna"); + amountOfTx->set_amount("1000000"); + + auto& fee = *input.mutable_fee(); + fee.set_gas(200000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("luna"); + amountOfFee->set_amount("200"); + + std::string json; + google::protobuf::util::MessageToJsonString(input, &json); + EXPECT_EQ(json, R"({"accountNumber":"1037","chainId":"columbus-5","fee":{"amounts":[{"denom":"luna","amount":"200"}],"gas":"200000"},"sequence":"2","messages":[{"sendCoinsMessage":{"fromAddress":"terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2","toAddress":"terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf","amounts":[{"denom":"luna","amount":"1000000"}]}}]})"); + + auto privateKey = parse_hex("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerra); + + assertJSONEqual(output.json(), R"( + { + "mode": "block", + "tx": { + "fee": { + "amount": [ + { + "amount": "200", + "denom": "luna" + } + ], + "gas": "200000" + }, + "memo": "", + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "amount": [ + { + "amount": "1000000", + "denom": "luna" + } + ], + "from_address": "terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2", + "to_address": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf" + } + } + ], + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "AlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3F" + }, + "signature": "ofdIsLJzkODcQwLG89eE2g4HOaUmfKPh/08t07ehKPUqRMl4rVonzo73mkOvqtrHWjdtB+6t6R8DGudPpb6bRg==" + } + ] + } + } + )"); + EXPECT_EQ(hex(output.signature()), "a1f748b0b27390e0dc4302c6f3d784da0e0739a5267ca3e1ff4f2dd3b7a128f52a44c978ad5a27ce8ef79a43afaadac75a376d07eeade91f031ae74fa5be9b46"); + EXPECT_EQ(output.serialized(), ""); + EXPECT_EQ(output.error(), ""); +} + +TEST(TerraClassicSigner, SignWasmTransferTxProtobuf_9FF3F0) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(3407705); + input.set_chain_id("columbus-5"); + input.set_memo(""); + input.set_sequence(3); + + Address fromAddress; + ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); + Address toAddress; + ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC + + auto msg = input.add_messages(); + auto& message = *msg->mutable_wasm_terra_execute_contract_transfer_message(); + message.set_sender_address(fromAddress.string()); + message.set_contract_address(tokenContractAddress); + const auto amount = store(uint256_t(250000), 0); + message.set_amount(amount.data(), amount.size()); + message.set_recipient_address(toAddress.string()); + + auto& fee = *input.mutable_fee(); + fee.set_gas(200000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uluna"); + amountOfFee->set_amount("3000"); + + std::string json; + google::protobuf::util::MessageToJsonString(input, &json); + assertJSONEqual(json, R"( + { + "signingMode": "Protobuf", + "accountNumber": "3407705", + "chainId": "columbus-5", + "fee": { + "amounts": [ + { + "denom": "uluna", + "amount": "3000" + } + ], + "gas": "200000" + }, + "sequence": "3", + "messages": [ + { + "wasmTerraExecuteContractTransferMessage": { + "senderAddress": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", + "contractAddress": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", + "amount": "A9CQ", + "recipientAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" + } + } + ] + } + )"); + + auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerra); + + // https://finder.terra.money/mainnet/tx/9FF3F0A16879254C22EB90D8B4D6195467FE5014381FD36BD3C23CA6698FE94B + // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "CogCCo..wld8"})' https:///cosmos/tx/v1beta1/txs + assertJSONEqual(output.serialized(), R"( + { + "tx_bytes": "CucBCuQBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBK5AQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Glt7InRyYW5zZmVyIjp7ImFtb3VudCI6IjI1MDAwMCIsInJlY2lwaWVudCI6InRlcnJhMWpsZ2FxeTludm4yaGY1dDJzcmE5eWN6OHM3N3duZjlsMGttZ2NwIn19EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNwZjrHsPmJKW/rXOWfukpQ1+lOHOJW3/IlFFnKLNmsABIECgIIARgDEhMKDQoFdWx1bmESBDMwMDAQwJoMGkAaprIEMLPH2HmFdwFGoaipb2GIyhXt6ombz+WMnG2mORBI6gFt0M+IymYgzZz6w1SW52R922yafDnn7yXfutRw", + "mode": "BROADCAST_MODE_BLOCK" + } + )"); + EXPECT_EQ(hex(output.signature()), "1aa6b20430b3c7d87985770146a1a8a96f6188ca15edea899bcfe58c9c6da6391048ea016dd0cf88ca6620cd9cfac35496e7647ddb6c9a7c39e7ef25dfbad470"); + EXPECT_EQ(output.json(), ""); + EXPECT_EQ(output.error(), ""); +} + +TEST(TerraClassicSigner, SignWasmTransferTxJson_078E90) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::JSON); + input.set_account_number(3407705); + input.set_chain_id("columbus-5"); + input.set_memo(""); + input.set_sequence(2); + + Address fromAddress; + ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); + Address toAddress; + ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC + + auto msg = input.add_messages(); + auto& message = *msg->mutable_wasm_terra_execute_contract_transfer_message(); + message.set_sender_address(fromAddress.string()); + message.set_contract_address(tokenContractAddress); + const auto amount = store(250000); + message.set_amount(amount.data(), amount.size()); + message.set_recipient_address(toAddress.string()); + + auto& fee = *input.mutable_fee(); + fee.set_gas(200000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uluna"); + amountOfFee->set_amount("3000"); + + auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerra); + + // https://finder.terra.money/mainnet/tx/078E90458061611F6FD8B708882B55FF5C1FFB3FCE61322107A0A0DE39FC0F3E + // curl -H 'Content-Type: application/json' --data-binary '{"mode": "block","tx":{...}}' https:///txs + assertJSONEqual(output.json(), R"( + { + "mode": "block", + "tx": + { + "fee": {"amount":[{"amount": "3000","denom": "uluna"}],"gas": "200000"}, + "memo": "", + "msg": + [ + { + "type": "wasm/MsgExecuteContract", + "value": + { + "sender": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", + "contract": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", + "execute_msg": + { + "transfer": + { + "amount": "250000", + "recipient": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" + } + }, + "coins": [] + } + } + ], + "signatures": + [ + { + "pub_key": + { + "type": "tendermint/PubKeySecp256k1", + "value": "A3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awA" + }, + "signature": "BjETdtbA97Wv1zvcsCV1tM+bdYKC8O3uGTk4mMRv6pBJB2y/Ds7qoS7s/zrkhYak1YChklQetHsI30XRXzGIkg==" + } + ] + } + })"); + EXPECT_EQ(hex(output.signature()), "06311376d6c0f7b5afd73bdcb02575b4cf9b758282f0edee19393898c46fea9049076cbf0eceeaa12eecff3ae48586a4d580a192541eb47b08df45d15f318892"); + EXPECT_EQ(output.serialized(), ""); + EXPECT_EQ(output.error(), ""); +} + +TEST(TerraClassicSigner, SignWasmGeneric_EC4F85) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(3407705); + input.set_chain_id("columbus-5"); + input.set_memo(""); + input.set_sequence(7); + + Address fromAddress; + ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); + Address toAddress; + ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC + const auto txMessage = R"({"transfer": { "amount": "250000", "recipient": "terra1d7048csap4wzcv5zm7z6tdqem2agyp9647vdyj" } })"; + + auto msg = input.add_messages(); + auto& message = *msg->mutable_wasm_terra_execute_contract_generic(); + message.set_sender_address(fromAddress.string()); + message.set_contract_address(tokenContractAddress); + message.set_execute_msg(txMessage); + + auto& fee = *input.mutable_fee(); + fee.set_gas(200000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uluna"); + amountOfFee->set_amount("3000"); + + auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerra); + + // https://finder.terra.money/mainnet/tx/EC4F8532847E4D6AF016E6F6D3F027AE7FB6FF0B533C5132B01382D83B214A6F + // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "Cu4BC...iVt"})' https:///cosmos/tx/v1beta1/txs + assertJSONEqual(output.serialized(), R"( + { + "tx_bytes": "Cu4BCusBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLAAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2GmJ7InRyYW5zZmVyIjogeyAiYW1vdW50IjogIjI1MDAwMCIsICJyZWNpcGllbnQiOiAidGVycmExZDcwNDhjc2FwNHd6Y3Y1em03ejZ0ZHFlbTJhZ3lwOTY0N3ZkeWoiIH0gfRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYBxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAkPsS7xlSng2LMc9KiD1soN5NLaDcUh8I9okPmsdJN3le1B7yxRGNB4aQfhaRl/8Z0r5vitRT0AWuxDasd8wcFw==", + "mode": "BROADCAST_MODE_BLOCK" + } + )"); + + EXPECT_EQ(hex(output.signature()), "90fb12ef19529e0d8b31cf4a883d6ca0de4d2da0dc521f08f6890f9ac74937795ed41ef2c5118d0786907e169197ff19d2be6f8ad453d005aec436ac77cc1c17"); + EXPECT_EQ(output.json(), ""); + EXPECT_EQ(output.error(), ""); +} + + +TEST(TerraClassicSigner, SignWasmGenericWithCoins_6651FC) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(3407705); + input.set_chain_id("columbus-5"); + input.set_memo(""); + input.set_sequence(9); + + Address fromAddress; + ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); + Address toAddress; + ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); + const auto tokenContractAddress = "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s"; // ANC Market + const auto txMessage = R"({ "deposit_stable": {} })"; + + auto msg = input.add_messages(); + auto& message = *msg->mutable_wasm_terra_execute_contract_generic(); + message.set_sender_address(fromAddress.string()); + message.set_contract_address(tokenContractAddress); + message.set_execute_msg(txMessage); + + auto amount = message.add_coins(); + amount->set_denom("uusd"); + amount->set_amount("1000"); + + auto& fee = *input.mutable_fee(); + fee.set_gas(600000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uluna"); + amountOfFee->set_amount("7000"); + + auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerra); + + // https://finder.terra.money/mainnet/tx/6651FCE0EE5C6D6ACB655CC49A6FD5E939FB082862854616EA0642475BCDD0C9 + // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "CrIBCq8B.....0NWg=="})' https:///cosmos/tx/v1beta1/txs + assertJSONEqual(output.serialized(), R"( + { + "tx_bytes": "CrIBCq8BCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBKEAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMXNlcGZqN3MwYWVnNTk2N3V4bmZrNHRoemxlcnJza3RrcGVsbTVzGhh7ICJkZXBvc2l0X3N0YWJsZSI6IHt9IH0qDAoEdXVzZBIEMTAwMBJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYCRITCg0KBXVsdW5hEgQ3MDAwEMDPJBpAGyi7f1ioY8XV6pjFq1s86Om4++CIUnd3rLHif2iopCcYvX0mLkTlQ6NUERg8nWTYgXcj6fOTO/ptgPuAtv0NWg==", + "mode": "BROADCAST_MODE_BLOCK" + } + )"); + + EXPECT_EQ(hex(output.signature()), "1b28bb7f58a863c5d5ea98c5ab5b3ce8e9b8fbe088527777acb1e27f68a8a42718bd7d262e44e543a35411183c9d64d8817723e9f3933bfa6d80fb80b6fd0d5a"); + EXPECT_EQ(output.json(), ""); + EXPECT_EQ(output.error(), ""); +} + +TEST(TerraClassicSigner, SignWasmSendTxProtobuf) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(3407705); + input.set_chain_id("columbus-5"); + input.set_memo(""); + input.set_sequence(4); + + Address fromAddress; + ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); + Address toAddress; + ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC + + auto msg = input.add_messages(); + auto& message = *msg->mutable_wasm_terra_execute_contract_send_message(); + message.set_sender_address(fromAddress.string()); + message.set_contract_address(tokenContractAddress); + const auto amount = store(uint256_t(250000), 0); + message.set_amount(amount.data(), amount.size()); + message.set_recipient_contract_address(toAddress.string()); + const auto msgMsg = Base64::encode(data(std::string(R"({"some_message":{}})"))); + EXPECT_EQ(msgMsg, "eyJzb21lX21lc3NhZ2UiOnt9fQ=="); + message.set_msg(msgMsg); + + auto& fee = *input.mutable_fee(); + fee.set_gas(200000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uluna"); + amountOfFee->set_amount("3000"); + + std::string json; + google::protobuf::util::MessageToJsonString(input, &json); + assertJSONEqual(json, R"( + { + "signingMode": "Protobuf", + "accountNumber": "3407705", + "chainId": "columbus-5", + "fee": { + "amounts": [ + { + "denom": "uluna", + "amount": "3000" + } + ], + "gas": "200000" + }, + "sequence": "4", + "messages": [ + { + "wasmTerraExecuteContractSendMessage": { + "senderAddress": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", + "contractAddress": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", + "amount": "A9CQ", + "recipientContractAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", + "msg": "eyJzb21lX21lc3NhZ2UiOnt9fQ==" + } + } + ] + } + )"); + + auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerra); + + // https://finder.terra.money/mainnet/tx/9FF3F0A16879254C22EB90D8B4D6195467FE5014381FD36BD3C23CA6698FE94B + // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "CogCCo..wld8"})' https:///cosmos/tx/v1beta1/txs + assertJSONEqual(output.serialized(), R"( + { + "tx_bytes": "CocCCoQCCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLZAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Gnt7InNlbmQiOnsiYW1vdW50IjoiMjUwMDAwIiwiY29udHJhY3QiOiJ0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcCIsIm1zZyI6ImV5SnpiMjFsWDIxbGMzTmhaMlVpT250OWZRPT0ifX0SZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awAEgQKAggBGAQSEwoNCgV1bHVuYRIEMzAwMBDAmgwaQL6NByKeRZsyq5g6CTMdmPqiM77nOe9uLO8FjpetFgkBFiG3Le7ieZZ+4vCMhD1bcFgMwSHibFI/uPil847U/+g=", + "mode": "BROADCAST_MODE_BLOCK" + } + )"); + EXPECT_EQ(hex(output.signature()), "be8d07229e459b32ab983a09331d98faa233bee739ef6e2cef058e97ad1609011621b72deee279967ee2f08c843d5b70580cc121e26c523fb8f8a5f38ed4ffe8"); + EXPECT_EQ(output.json(), ""); + EXPECT_EQ(output.error(), ""); +} + +TEST(TerraClassicSigner, SignWasmTerraTransferPayload) { + auto proto = Proto::Message_WasmTerraExecuteContractTransfer(); + proto.set_recipient_address("recipient=address"); + const auto amount = store(uint256_t(250000), 0); + proto.set_amount(amount.data(), amount.size()); + + const auto payload = wasmTerraExecuteTransferPayload(proto); + + assertJSONEqual(payload.dump(), R"( + { + "transfer": + { + "amount": "250000", + "recipient": "recipient=address" + } + } + )"); +} diff --git a/tests/Terra/TWCoinTypeTests.cpp b/tests/Terra/TWCoinTypeTests.cpp index fa45497f705..52aba87d23e 100644 --- a/tests/Terra/TWCoinTypeTests.cpp +++ b/tests/Terra/TWCoinTypeTests.cpp @@ -13,7 +13,27 @@ #include -TEST(TWTerraCoinType, TWCoinType) { +TEST(TWTerraCoinType, TWCoinType20) { + auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeTerraV2)); + auto txId = WRAPS(TWStringCreateWithUTF8Bytes("CFF732C6EBEE06FFA08ABE54EE1657FD53E90FAA81604619E2062C46572A6986")); + auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeTerraV2, txId.get())); + auto accId = WRAPS(TWStringCreateWithUTF8Bytes("terra16t3gx5rqvz6ru37yzn3shuu20erv4ngmfr59zf")); + auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeTerraV2, accId.get())); + auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeTerraV2)); + auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeTerraV2)); + + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeTerraV2), 6); + ASSERT_EQ(TWBlockchainCosmos, TWCoinTypeBlockchain(TWCoinTypeTerraV2)); + ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeTerraV2)); + ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeTerraV2)); + assertStringsEqual(symbol, "LUNA"); + assertStringsEqual(txUrl, "https://finder.terra.money/mainnet/tx/CFF732C6EBEE06FFA08ABE54EE1657FD53E90FAA81604619E2062C46572A6986"); + assertStringsEqual(accUrl, "https://finder.terra.money/mainnet/address/terra16t3gx5rqvz6ru37yzn3shuu20erv4ngmfr59zf"); + assertStringsEqual(id, "terrav2"); + assertStringsEqual(name, "Terra"); +} + +TEST(TWTerraCoinType, TWCoinTypeClassic) { auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeTerra)); auto txId = WRAPS(TWStringCreateWithUTF8Bytes("D28D8AFC7CE89F2A22FA2DBF78D2C0A36E549BB830C4D9FA7459E3F723CA7182")); auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeTerra, txId.get())); @@ -27,8 +47,8 @@ TEST(TWTerraCoinType, TWCoinType) { ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeTerra)); ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeTerra)); assertStringsEqual(symbol, "LUNC"); - assertStringsEqual(txUrl, "https://finder.terra.money/tx/tx/D28D8AFC7CE89F2A22FA2DBF78D2C0A36E549BB830C4D9FA7459E3F723CA7182"); - assertStringsEqual(accUrl, "https://finder.terra.money/tx/address/terra16t3gx5rqvz6ru37yzn3shuu20erv4ngmfr59zf"); + assertStringsEqual(txUrl, "https://finder.terra.money/classic/tx/D28D8AFC7CE89F2A22FA2DBF78D2C0A36E549BB830C4D9FA7459E3F723CA7182"); + assertStringsEqual(accUrl, "https://finder.terra.money/classic/address/terra16t3gx5rqvz6ru37yzn3shuu20erv4ngmfr59zf"); assertStringsEqual(id, "terra"); assertStringsEqual(name, "Terra Classic"); } From 88ca63adff2bf77421dd58abfa63fd74a9e7cc4f Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 12 Jul 2022 14:16:56 +0800 Subject: [PATCH 023/497] [NEAR] Add stake / add key / delete key / create account / delete account (#2367) * Add NEAR stake, add key, delete key, create account, delete account transactions serialization * NEAR serialization: remove unused func * NEAR serialization: add stake test * Add any signer test * use auto&& --- src/NEAR/Serialization.cpp | 63 ++++++++- src/proto/NEAR.proto | 3 +- tests/NEAR/SerializationTests.cpp | 209 +++++++++++++++++++++++++++++- tests/NEAR/TWAnySignerTests.cpp | 33 ++++- 4 files changed, 299 insertions(+), 9 deletions(-) diff --git a/src/NEAR/Serialization.cpp b/src/NEAR/Serialization.cpp index 71ab3d2f181..e972e91741b 100644 --- a/src/NEAR/Serialization.cpp +++ b/src/NEAR/Serialization.cpp @@ -51,14 +51,61 @@ static void writeTransfer(Data& data, const Proto::Transfer& transfer) { static void writeFunctionCall(Data& data, const Proto::FunctionCall& functionCall) { writeString(data, functionCall.method_name()); - + writeU32(data, static_cast(functionCall.args().size())); writeRawBuffer(data, functionCall.args()); - + writeU64(data, functionCall.gas()); writeU128(data, functionCall.deposit()); } +static void writeStake(Data& data, const Proto::Stake& stake) { + writeU128(data, stake.stake()); + writePublicKey(data, stake.public_key()); +} + +static void writeFunctionCallPermission(Data& data, const Proto::FunctionCallPermission& functionCallPermission) { + if (functionCallPermission.allowance().empty()) { + writeU8(data, 0); + } else { + writeU8(data, 1); + writeU128(data, functionCallPermission.allowance()); + } + writeString(data, functionCallPermission.receiver_id()); + writeU32(data, static_cast(functionCallPermission.method_names().size())); + for (auto&& methodName : functionCallPermission.method_names()) { + writeString(data, methodName); + } +} + +static void writeAccessKey(Data& data, const Proto::AccessKey& accessKey) { + writeU64(data, accessKey.nonce()); + switch (accessKey.permission_case()) { + case Proto::AccessKey::kFunctionCall: + writeU8(data, 0); + writeFunctionCallPermission(data, accessKey.function_call()); + break; + case Proto::AccessKey::kFullAccess: + writeU8(data, 1); + break; + case AccessKey::PERMISSION_NOT_SET: + break; + } +} + +static void writeAddKey(Data& data, const Proto::AddKey& addKey) { + writePublicKey(data, addKey.public_key()); + writeAccessKey(data, addKey.access_key()); +} + +static void writeDeleteKey(Data& data, const Proto::DeleteKey& deleteKey) { + writePublicKey(data, deleteKey.public_key()); +} + +static void writeDeleteAccount(Data& data, const Proto::DeleteAccount& deleteAccount) { + writeString(data, deleteAccount.beneficiary_id()); +} + static void writeAction(Data& data, const Proto::Action& action) { writeU8(data, action.payload_case() - Proto::Action::kCreateAccount); switch (action.payload_case()) { @@ -68,6 +115,18 @@ static void writeAction(Data& data, const Proto::Action& action) { case Proto::Action::kFunctionCall: writeFunctionCall(data, action.function_call()); return; + case Proto::Action::kStake: + writeStake(data, action.stake()); + return; + case Proto::Action::kAddKey: + writeAddKey(data, action.add_key()); + return; + case Proto::Action::kDeleteKey: + writeDeleteKey(data, action.delete_key()); + return; + case Proto::Action::kDeleteAccount: + writeDeleteAccount(data, action.delete_account()); + return; default: return; } diff --git a/src/proto/NEAR.proto b/src/proto/NEAR.proto index 8e9c4d6f020..6a2641a2a45 100644 --- a/src/proto/NEAR.proto +++ b/src/proto/NEAR.proto @@ -11,6 +11,7 @@ message PublicKey { message FunctionCallPermission { bytes allowance = 1; // uint128 / little endian byte order string receiver_id = 2; + repeated string method_names = 3; } message FullAccessPermission { @@ -44,7 +45,7 @@ message Transfer { message Stake { bytes stake = 1; // uint128 / little endian byte order - string public_key = 2; + PublicKey public_key = 2; } message AddKey { diff --git a/tests/NEAR/SerializationTests.cpp b/tests/NEAR/SerializationTests.cpp index df4c1334c1b..7f6904988b6 100644 --- a/tests/NEAR/SerializationTests.cpp +++ b/tests/NEAR/SerializationTests.cpp @@ -47,23 +47,23 @@ TEST(NEARSerialization, SerializeFunctionCallTransaction) { input.set_signer_id("test.near"); input.set_nonce(1); input.set_receiver_id("whatever.near"); - + input.add_actions(); auto& functionCall = *input.mutable_actions(0)->mutable_function_call(); - + functionCall.set_method_name("qqq"); functionCall.set_gas(1000); - + Data deposit(16, 0); deposit[0] = 1; functionCall.set_deposit(deposit.data(), deposit.size()); - + Data args(3, 0); args[0] = 1; args[1] = 2; args[2] = 3; functionCall.set_args(args.data(), args.size()); - + auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); input.set_block_hash(blockHash.data(), blockHash.size()); @@ -76,4 +76,203 @@ TEST(NEARSerialization, SerializeFunctionCallTransaction) { ASSERT_EQ(serializedHex, "09000000746573742e6e65617200917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d01000000000000000d00000077686174657665722e6e6561720fa473fd26901df296be6adc4cc4df34d040efa2435224b6986910e630c2fef601000000020300000071717103000000010203e80300000000000001000000000000000000000000000000"); } +TEST(NEARSerialization, SerializeStakeTransaction) { + auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + + auto input = Proto::SigningInput(); + input.set_signer_id("test.near"); + input.set_nonce(1); + input.set_receiver_id("whatever.near"); + + input.add_actions(); + auto& stake = *input.mutable_actions(0)->mutable_stake(); + Data amount(16, 0); + amount[0] = 1; + stake.set_stake(amount.data(), amount.size()); + + auto& pKey = *stake.mutable_public_key(); + pKey.set_data(publicKey.data(), publicKey.size()); + pKey.set_key_type(0); + + auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + input.set_block_hash(blockHash.data(), blockHash.size()); + + auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + input.set_private_key(privateKey.data(), 32); + + auto serialized = transactionData(input); + auto serializedHex = hex(serialized); + + ASSERT_EQ(serializedHex, "09000000746573742e6e65617200917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d01000000000000000d00000077686174657665722e6e6561720fa473fd26901df296be6adc4cc4df34d040efa2435224b6986910e630c2fef601000000040100000000000000000000000000000000917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d"); +} + +TEST(NEARSerialization, SerializeStakeTransaction2) { + auto publicKey = Base58::bitcoin.decode("C2P7YcEmBv31vtCHLBcESteN4Yi4vSCkXEXMTANyB649"); + + auto input = Proto::SigningInput(); + input.set_signer_id("vdx.testnet"); + input.set_nonce(93128451000005); + input.set_receiver_id("vdx.testnet"); + + input.add_actions(); + auto& stake = *input.mutable_actions(0)->mutable_stake(); + // 2490000000000000000000000000 + auto amount = parse_hex("000000fa4f3f757902ae0b0800000000"); // little endian + stake.set_stake(amount.data(), amount.size()); + + auto& pKey = *stake.mutable_public_key(); + pKey.set_data(publicKey.data(), publicKey.size()); + pKey.set_key_type(0); + + auto blockHash = Base58::bitcoin.decode("ByDnm7c25npQXwNUX5yivbYbpjFcNuNumF6BJjaK3vhJ"); + input.set_block_hash(blockHash.data(), blockHash.size()); + + auto privateKey = Base58::bitcoin.decode("5Cfk7QBnmDxxFxQk75FFq4ADrQS9gxHKe6vtuGH6JCCm8WV8aRPEGVqp579JHNmmHMUt49gkCVcH2t7NRnh2v7Qu"); + input.set_private_key(privateKey.data(), 32); + + auto serialized = transactionData(input); + auto serializedHex = hex(serialized); + + ASSERT_EQ(serializedHex, "0b0000007664782e746573746e657400a3cb23dbb9810abd4a6804328eec47a17236383b5c234cae903b064e9dc426dac5863d28b35400000b0000007664782e746573746e6574a2fbdae8a769c636d109952e4fe760b03688e629933cbf693aedfd97a470c7a50100000004000000fa4f3f757902ae0b080000000000a3cb23dbb9810abd4a6804328eec47a17236383b5c234cae903b064e9dc426da"); +} + +TEST(NEARSerialization, SerializeAddKeyFunctionCallTransaction) { + auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + + auto input = Proto::SigningInput(); + input.set_signer_id("test.near"); + input.set_nonce(1); + input.set_receiver_id("whatever.near"); + + input.add_actions(); + auto& addKey = *input.mutable_actions(0)->mutable_add_key(); + + auto& pKey = *addKey.mutable_public_key(); + pKey.set_data(publicKey.data(), publicKey.size()); + pKey.set_key_type(0); + + auto& accessKey = *addKey.mutable_access_key(); + accessKey.set_nonce(0); + auto& functionCallPermission = *accessKey.mutable_function_call(); + functionCallPermission.set_receiver_id("zzz"); + functionCallPermission.add_method_names("www"); + + auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + input.set_block_hash(blockHash.data(), blockHash.size()); + + auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + input.set_private_key(privateKey.data(), 32); + + auto serialized = transactionData(input); + auto serializedHex = hex(serialized); + + ASSERT_EQ(serializedHex, "09000000746573742e6e65617200917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d01000000000000000d00000077686174657665722e6e6561720fa473fd26901df296be6adc4cc4df34d040efa2435224b6986910e630c2fef6010000000500917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d00000000000000000000030000007a7a7a0100000003000000777777"); +} + +TEST(NEARSerialization, SerializeAddKeyFullAccessTransaction) { + auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + + auto input = Proto::SigningInput(); + input.set_signer_id("test.near"); + input.set_nonce(1); + input.set_receiver_id("whatever.near"); + + input.add_actions(); + auto& addKey = *input.mutable_actions(0)->mutable_add_key(); + + auto& pKey = *addKey.mutable_public_key(); + pKey.set_data(publicKey.data(), publicKey.size()); + pKey.set_key_type(0); + + auto& accessKey = *addKey.mutable_access_key(); + accessKey.set_nonce(0); + + accessKey.mutable_full_access(); + + auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + input.set_block_hash(blockHash.data(), blockHash.size()); + + auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + input.set_private_key(privateKey.data(), 32); + + auto serialized = transactionData(input); + auto serializedHex = hex(serialized); + + ASSERT_EQ(serializedHex, "09000000746573742e6e65617200917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d01000000000000000d00000077686174657665722e6e6561720fa473fd26901df296be6adc4cc4df34d040efa2435224b6986910e630c2fef6010000000500917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d000000000000000001"); +} + +TEST(NEARSerialization, SerializeDeleteKeyTransaction) { + auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + + auto input = Proto::SigningInput(); + input.set_signer_id("test.near"); + input.set_nonce(1); + input.set_receiver_id("whatever.near"); + + input.add_actions(); + auto& deleteKey = *input.mutable_actions(0)->mutable_delete_key(); + + auto& pKey = *deleteKey.mutable_public_key(); + pKey.set_data(publicKey.data(), publicKey.size()); + pKey.set_key_type(0); + + auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + input.set_block_hash(blockHash.data(), blockHash.size()); + + auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + input.set_private_key(privateKey.data(), 32); + + auto serialized = transactionData(input); + auto serializedHex = hex(serialized); + + ASSERT_EQ(serializedHex, "09000000746573742e6e65617200917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d01000000000000000d00000077686174657665722e6e6561720fa473fd26901df296be6adc4cc4df34d040efa2435224b6986910e630c2fef6010000000600917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d"); +} + +TEST(NEARSerialization, SerializeCreateAccountTransaction) { + auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + + auto input = Proto::SigningInput(); + input.set_signer_id("test.near"); + input.set_nonce(1); + input.set_receiver_id("whatever.near"); + + input.add_actions(); + input.mutable_actions(0)->mutable_create_account(); + + auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + input.set_block_hash(blockHash.data(), blockHash.size()); + + auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + input.set_private_key(privateKey.data(), 32); + + auto serialized = transactionData(input); + auto serializedHex = hex(serialized); + + ASSERT_EQ(serializedHex, "09000000746573742e6e65617200917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d01000000000000000d00000077686174657665722e6e6561720fa473fd26901df296be6adc4cc4df34d040efa2435224b6986910e630c2fef60100000000"); +} + +TEST(NEARSerialization, SerializeDeleteAccountTransaction) { + auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + + auto input = Proto::SigningInput(); + input.set_signer_id("test.near"); + input.set_nonce(1); + input.set_receiver_id("whatever.near"); + + input.add_actions(); + auto& deleteAccount = *input.mutable_actions(0)->mutable_delete_account(); + deleteAccount.set_beneficiary_id("123"); + + auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + input.set_block_hash(blockHash.data(), blockHash.size()); + + auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + input.set_private_key(privateKey.data(), 32); + + auto serialized = transactionData(input); + auto serializedHex = hex(serialized); + + ASSERT_EQ(serializedHex, "09000000746573742e6e65617200917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d01000000000000000d00000077686174657665722e6e6561720fa473fd26901df296be6adc4cc4df34d040efa2435224b6986910e630c2fef6010000000703000000313233"); +} + } diff --git a/tests/NEAR/TWAnySignerTests.cpp b/tests/NEAR/TWAnySignerTests.cpp index c3dce258856..2f6204022e7 100644 --- a/tests/NEAR/TWAnySignerTests.cpp +++ b/tests/NEAR/TWAnySignerTests.cpp @@ -12,7 +12,7 @@ namespace TW::NEAR { -TEST(TWAnySignerNEAR, Sign) { +TEST(TWAnySignerNEAR, SignTransfer) { auto privateKey = parse_hex("8737b99bf16fba78e1e753e23ba00c4b5423ac9c45d9b9caae9a519434786568"); auto blockHash = parse_hex("0fa473fd26901df296be6adc4cc4df34d040efa2435224b6986910e630c2fef6"); @@ -37,4 +37,35 @@ TEST(TWAnySignerNEAR, Sign) { ASSERT_EQ(hex(output.hash()), "eea6e680f3ea51a7f667e9a801d0bfadf66e03d41ed54975b3c6006351461b32"); } +TEST(TWAnySignerNEAR, SignStake) { + + auto privateKey = parse_hex("d22149327ceb8e86f70962be0c7293f8308d85d0cbea2cc24e47c3033da7440f"); + auto publicKey = parse_hex("a3cb23dbb9810abd4a6804328eec47a17236383b5c234cae903b064e9dc426da"); + auto blockHash = parse_hex("a2fbdae8a769c636d109952e4fe760b03688e629933cbf693aedfd97a470c7a5"); + + // 2490000000000000000000000000 + auto amount = parse_hex("000000fa4f3f757902ae0b0800000000"); // little endian + + Proto::SigningInput input; + input.set_signer_id("vdx.testnet"); + input.set_nonce(93128451000005); + input.set_receiver_id("vdx.testnet"); + input.set_private_key(privateKey.data(), privateKey.size()); + input.set_block_hash(blockHash.data(), blockHash.size()); + + auto& action = *input.add_actions(); + auto& stake = *action.mutable_stake(); + stake.set_stake(amount.data(), amount.size()); + + auto& pubkey = *stake.mutable_public_key(); + pubkey.set_data(publicKey.data(), publicKey.size()); + pubkey.set_key_type(0); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeNEAR); + + ASSERT_EQ(hex(output.signed_transaction()), "0b0000007664782e746573746e657400a3cb23dbb9810abd4a6804328eec47a17236383b5c234cae903b064e9dc426dac5863d28b35400000b0000007664782e746573746e6574a2fbdae8a769c636d109952e4fe760b03688e629933cbf693aedfd97a470c7a50100000004000000fa4f3f757902ae0b080000000000a3cb23dbb9810abd4a6804328eec47a17236383b5c234cae903b064e9dc426da0011fdbc234d4ce470ec7f2ac5e4d3d8f8fe1525f83e9a2425e7000aea52f7260ff4f5191beaa1a5ac29256e68c6acd368ada0d06ed033e9a204ee119f5ef1b104"); + ASSERT_EQ(hex(output.hash()), "c8aedbf75fcaa9b663a3959d27f1deae809e1923460791471e5219eafecc4ba8"); +} + } // namespace TW::NEAR From 72957c10795d7d63600d04c97c92a12df91da191 Mon Sep 17 00:00:00 2001 From: Maxim Pestryakov Date: Wed, 13 Jul 2022 11:32:48 +0300 Subject: [PATCH 024/497] Replaced grpc dependency with protobuf (#2374) --- android/app/build.gradle | 2 +- android/trustwalletcore/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 9a198ee9732..451d30ecf4d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -42,7 +42,7 @@ dependencies { androidTestImplementation 'androidx.test:runner:1.3.0' androidTestImplementation 'android.arch.core:core-testing:1.1.1' - implementation 'io.grpc:grpc-protobuf:1.43.2' + implementation 'com.google.protobuf:protobuf-java:3.21.2' } repositories { mavenCentral() diff --git a/android/trustwalletcore/build.gradle b/android/trustwalletcore/build.gradle index b89842051d6..7235ffb0656 100644 --- a/android/trustwalletcore/build.gradle +++ b/android/trustwalletcore/build.gradle @@ -47,7 +47,7 @@ android { } dependencies { - implementation 'io.grpc:grpc-protobuf:1.43.2' + implementation 'com.google.protobuf:protobuf-java:3.21.2' } apply from: 'maven-push.gradle' From 4f38375fcac6721849e157c2dbe593c7b7642f0d Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 14 Jul 2022 01:51:53 +0200 Subject: [PATCH 025/497] [Feature]: Base32 to C interface (#2365) * feat(base32): add base32 encoding to c interface * feat(base32): finalize encoding/decoding function * feat(base32): add swift basis unit test * feat(base32): fix review comments * feat(base32): separate lines between assignment and assertion * feat(base32): add typescript unit tests * feat(base32): coding style + line break * feat(base32): use emptiness instead of nullable TWString * feat(base32): add kt unit tests --- .../trustwallet/core/app/utils/TestBase32.kt | 35 ++++++++++ include/TrustWalletCore/TWBase32.h | 53 +++++++++++++++ src/interface/TWBase32.cpp | 44 ++++++++++++ swift/Tests/Base32Tests.swift | 38 +++++++++++ tests/interface/TWBase32Tests.cpp | 67 +++++++++++++++++++ wasm/tests/AES.test.ts | 2 +- wasm/tests/Base32.test.ts | 43 ++++++++++++ 7 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestBase32.kt create mode 100644 include/TrustWalletCore/TWBase32.h create mode 100644 src/interface/TWBase32.cpp create mode 100644 swift/Tests/Base32Tests.swift create mode 100644 tests/interface/TWBase32Tests.cpp create mode 100644 wasm/tests/Base32.test.ts diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestBase32.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestBase32.kt new file mode 100644 index 00000000000..d564eff45d8 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestBase32.kt @@ -0,0 +1,35 @@ +package com.trustwallet.core.app.utils + +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.Base32 + +class TestBase32 { + init { + System.loadLibrary("TrustWalletCore"); + } + + @Test + fun testEncode() { + assertEquals(Base32.encode("HelloWorld".toByteArray()), "JBSWY3DPK5XXE3DE") + } + + @Test + fun testEncodeWithAlphabet() { + assertEquals(Base32.encodeWithAlphabet("7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy".toByteArray(), "abcdefghijklmnopqrstuvwxyz234567"), "g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i") + } + + @Test + fun testDecode() { + var decoded = Base32.decode("JBSWY3DPK5XXE3DE") + + assertEquals(String(decoded, Charsets.UTF_8), "HelloWorld") + } + + @Test + fun testDecodeWithAlphabet() { + var decoded = Base32.decodeWithAlphabet("g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i", "abcdefghijklmnopqrstuvwxyz234567") + + assertEquals(String(decoded, Charsets.UTF_8), "7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy") + } +} diff --git a/include/TrustWalletCore/TWBase32.h b/include/TrustWalletCore/TWBase32.h new file mode 100644 index 00000000000..b69500e1a62 --- /dev/null +++ b/include/TrustWalletCore/TWBase32.h @@ -0,0 +1,53 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +TW_EXPORT_STRUCT +struct TWBase32; + +/// Decode a Base32 input with the given alphabet +/// +/// \param string Encoded base32 input to be decoded +/// \param alphabet Decode with the given alphabet, if empty ALPHABET_RFC4648 is used by default +/// \return The decoded data, can be null. +/// \note ALPHABET_RFC4648 doesn't support padding in the default alphabet +TW_EXPORT_STATIC_METHOD +TWData* _Nullable TWBase32DecodeWithAlphabet(TWString* _Nonnull string, TWString* _Nonnull alphabet); + +/// Decode a Base32 input with the default alphabet (ALPHABET_RFC4648) +/// +/// \param string Encoded input to be decoded +/// \return The decoded data +/// \note Call TWBase32DecodeWithAlphabet with empty string. +TW_EXPORT_STATIC_METHOD +TWData* _Nullable TWBase32Decode(TWString* _Nonnull string); + +/// Encode an input to Base32 with the given alphabet +/// +/// \param data Data to be encoded (raw bytes) +/// \param alphabet Encode with the given alphabet, if empty ALPHABET_RFC4648 is used by default +/// \return The encoded data +/// \note ALPHABET_RFC4648 doesn't support padding in the default alphabet +TW_EXPORT_STATIC_METHOD +TWString *_Nonnull TWBase32EncodeWithAlphabet(TWData *_Nonnull data, TWString* _Nonnull alphabet); + +/// Encode an input to Base32 with the default alphabet (ALPHABET_RFC4648) +/// +/// \param data Data to be encoded (raw bytes) +/// \return The encoded data +/// \note Call TWBase32EncodeWithAlphabet with empty string. +TW_EXPORT_STATIC_METHOD +TWString *_Nonnull TWBase32Encode(TWData *_Nonnull data); + +TW_EXTERN_C_END + diff --git a/src/interface/TWBase32.cpp b/src/interface/TWBase32.cpp new file mode 100644 index 00000000000..11fd93093c8 --- /dev/null +++ b/src/interface/TWBase32.cpp @@ -0,0 +1,44 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include + +#include "../Base32.h" + +#include + +using namespace TW; + +TWData* TWBase32DecodeWithAlphabet(TWString* _Nonnull string, TWString* _Nonnull alphabet) { + Data decodedOut; + auto cppString = *reinterpret_cast(string); + const char* alphabetRaw = nullptr; + if (TWStringSize(alphabet) > 0) { + alphabetRaw = TWStringUTF8Bytes(alphabet); + } + auto result = Base32::decode(cppString, decodedOut, alphabetRaw); + return result ? TWDataCreateWithData(&decodedOut) : nullptr; +} + +TWData* _Nullable TWBase32Decode(TWString* _Nonnull string) { + std::string empty; + return TWBase32DecodeWithAlphabet(string, &empty); +} + +TWString* _Nonnull TWBase32EncodeWithAlphabet(TWData* _Nonnull data, TWString* _Nonnull alphabet) { + auto cppData = *reinterpret_cast(data); + const char* alphabetRaw = nullptr; + if (TWStringSize(alphabet) > 0) { + alphabetRaw = TWStringUTF8Bytes(alphabet); + } + auto result = Base32::encode(cppData, alphabetRaw); + return TWStringCreateWithUTF8Bytes(result.c_str()); +} + +TWString* _Nonnull TWBase32Encode(TWData* _Nonnull data) { + std::string empty; + return TWBase32EncodeWithAlphabet(data, &empty); +} diff --git a/swift/Tests/Base32Tests.swift b/swift/Tests/Base32Tests.swift new file mode 100644 index 00000000000..41be00de149 --- /dev/null +++ b/swift/Tests/Base32Tests.swift @@ -0,0 +1,38 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import XCTest +import WalletCore + +class Base32Tests: XCTestCase { + func testEncode() { + let encoded = Base32.encode(data: Data.init(bytes: "HelloWorld", count: 10)); + XCTAssertEqual(encoded, "JBSWY3DPK5XXE3DE"); + } + + func testEncodeWithAlphabet() { + let encoded = Base32.encodeWithAlphabet(data: Data.init(bytes: "7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy", count: 39), alphabet: "abcdefghijklmnopqrstuvwxyz234567"); + XCTAssertEqual(encoded, "g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i"); + } + + func testDecode() { + guard let decoded = Base32.decode(string: "JBSWY3DPK5XXE3DE") else { + return XCTFail(); + } + let toCompare = String(data: decoded, encoding:.utf8); + + XCTAssertEqual(toCompare, "HelloWorld"); + } + + func testDecodeWithAlphabet() { + guard let decoded = Base32.decodeWithAlphabet(string: "g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i", alphabet:"abcdefghijklmnopqrstuvwxyz234567") else { + return XCTFail(); + } + let toCompare = String(data: decoded, encoding:.utf8); + + XCTAssertEqual(toCompare, "7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"); + } +} diff --git a/tests/interface/TWBase32Tests.cpp b/tests/interface/TWBase32Tests.cpp new file mode 100644 index 00000000000..d426ed1e23b --- /dev/null +++ b/tests/interface/TWBase32Tests.cpp @@ -0,0 +1,67 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "TWTestUtilities.h" + +#include "Data.h" +#include + +#include + +TEST(TWBase32, InvalidDecode) { + const auto encodedInput = STRING("JBSWY3DPK5XXE3DE======="); + auto result = WRAPD(TWBase32Decode(encodedInput.get())); + ASSERT_EQ(result, nullptr); +} + +TEST(TWBase32, Decode) { + const auto encodedInput = STRING("JBSWY3DPK5XXE3DE"); + auto result = WRAPD(TWBase32Decode(encodedInput.get())); + + ASSERT_NE(result, nullptr); + ASSERT_EQ(TWDataSize(result.get()), 10); + + auto data = *reinterpret_cast(result.get()); + std::string str(data.begin(), data.end()); + + ASSERT_EQ(str, "HelloWorld"); +} + +TEST(TWBase32, DecodeWithAlphabet) { + const auto encodedInput = STRING("g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i"); + const auto filecoinAlphabet = STRING("abcdefghijklmnopqrstuvwxyz234567"); + auto result = WRAPD(TWBase32DecodeWithAlphabet(encodedInput.get(), filecoinAlphabet.get())); + + ASSERT_NE(result, nullptr); + ASSERT_EQ(TWDataSize(result.get()), 39); + + auto data = *reinterpret_cast(result.get()); + std::string str(data.begin(), data.end()); + + ASSERT_EQ(str, "7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"); +} + +TEST(TWBase32, Encode) { + TW::Data data{'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd'}; + auto encodedStr = TWBase32Encode(&data); + std::string result = TWStringUTF8Bytes(encodedStr); + + ASSERT_EQ(result, "JBSWY3DPK5XXE3DE"); + + TWStringDelete(encodedStr); +} + +TEST(TWBase32, EncodeWithAlphabet) { + const auto filecoinAlphabet = STRING("abcdefghijklmnopqrstuvwxyz234567"); + TW::Data data{'7', 'u', 'o', 'q', '6', 't', 'p', '4', '2', '7', 'u', 'z', 'v', '7', 'f', + 'z', 't', 'k', 'b', 's', 'n', 'n', '6', '4', 'i', 'w', 'o', 't', 'f', 'r', 'r', 'i', 's', 't', 'w', 'p', 'r', 'y', 'y'}; + auto encodedStr = TWBase32EncodeWithAlphabet(&data, filecoinAlphabet.get()); + std::string result = TWStringUTF8Bytes(encodedStr); + + ASSERT_EQ(result, "g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i"); + + TWStringDelete(encodedStr); +} diff --git a/wasm/tests/AES.test.ts b/wasm/tests/AES.test.ts index fd77e2a228c..4d91a2c5ec0 100644 --- a/wasm/tests/AES.test.ts +++ b/wasm/tests/AES.test.ts @@ -6,8 +6,8 @@ import "mocha"; import { assert } from "chai"; -import { WalletCore } from "../dist"; import { Buffer } from "buffer"; +import { WalletCore } from "../dist"; describe("AES", () => { it("test decrypting", () => { diff --git a/wasm/tests/Base32.test.ts b/wasm/tests/Base32.test.ts new file mode 100644 index 00000000000..84b8edb1152 --- /dev/null +++ b/wasm/tests/Base32.test.ts @@ -0,0 +1,43 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import {assert} from "chai"; +import {Buffer} from "buffer"; +import { WalletCore } from "../dist"; + +describe("Base32", () => { + it("test decrypting", () => { + const {Base32} = WalletCore; + + const decoded = Base32.decode("JBSWY3DPK5XXE3DE"); + + assert.equal(Buffer.from(decoded).toString(), "HelloWorld"); + }); + + it("test decrypting with alphabet", () => { + const {Base32} = WalletCore; + + const decoded = Base32.decodeWithAlphabet("g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i", "abcdefghijklmnopqrstuvwxyz234567"); + + assert.equal(Buffer.from(decoded).toString(), "7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"); + }); + + it("test encrypting", () => { + const {Base32} = WalletCore; + + const encoded = Base32.encode(Buffer.from("HelloWorld")); + + assert.equal(encoded, "JBSWY3DPK5XXE3DE"); + }); + + it("test encrypting with alphabet", () => { + const {Base32} = WalletCore; + + const encoded = Base32.encodeWithAlphabet(Buffer.from("7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"), "abcdefghijklmnopqrstuvwxyz234567"); + + assert.equal(encoded, "g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i"); + }); +}); From 340c7472fd5976b1bd58084e7cbd3f2ebe4c23c0 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 14 Jul 2022 01:56:44 +0200 Subject: [PATCH 026/497] [Fix]: PVS-studio high warnings (#2373) * fix(pvs_high_warnings): fix all pvs-studio high warn * fix(linux_compilation): add climits header * fix(linux_compilation): add limits header in Program.cpp --- src/Base64.cpp | 1 - src/Bitcoin/SigningInput.cpp | 10 +++++----- src/Bitcoin/TransactionBuilder.h | 2 +- src/Cbor.cpp | 2 +- src/Decred/Transaction.cpp | 2 +- src/EOS/Name.h | 2 +- src/Ethereum/RLP.cpp | 2 +- src/Filecoin/Address.cpp | 7 ++++--- src/NEO/ReadData.h | 2 +- src/Polkadot/SS58Address.h | 2 +- src/Result.h | 4 +++- src/Solana/Program.cpp | 14 ++++++-------- src/Solana/Signer.cpp | 3 +-- src/Solana/Transaction.h | 10 ++++++---- src/TransactionCompiler.cpp | 2 +- src/Waves/Address.cpp | 4 +--- 16 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/Base64.cpp b/src/Base64.cpp index 6f5aeb44969..92b51279c0a 100644 --- a/src/Base64.cpp +++ b/src/Base64.cpp @@ -63,7 +63,6 @@ void convertToBase64Url(string& b) { } Data decodeBase64Url(const string& val) { - Data bytes; try { return decode(val); } catch (const exception& ex) { diff --git a/src/Bitcoin/SigningInput.cpp b/src/Bitcoin/SigningInput.cpp index 9929880984a..20b7647ec89 100644 --- a/src/Bitcoin/SigningInput.cpp +++ b/src/Bitcoin/SigningInput.cpp @@ -15,14 +15,14 @@ SigningInput::SigningInput(const Proto::SigningInput& input) { byteFee = input.byte_fee(); toAddress = input.to_address(); changeAddress = input.change_address(); - for (auto& key: input.private_key()) { - privateKeys.emplace_back(PrivateKey(key)); + for (auto&& key: input.private_key()) { + privateKeys.emplace_back(key); } - for (auto& script: input.scripts()) { + for (auto&& script: input.scripts()) { scripts[script.first] = Script(script.second.begin(), script.second.end()); } - for (auto& u: input.utxo()) { - utxos.push_back(UTXO(u)); + for (auto&& u: input.utxo()) { + utxos.emplace_back(u); } useMaxAmount = input.use_max_amount(); coinType = static_cast(input.coin_type()); diff --git a/src/Bitcoin/TransactionBuilder.h b/src/Bitcoin/TransactionBuilder.h index 33131160939..b2c9feeb8c0 100644 --- a/src/Bitcoin/TransactionBuilder.h +++ b/src/Bitcoin/TransactionBuilder.h @@ -48,7 +48,7 @@ class TransactionBuilder { // Optional OP_RETURN output if (plan.outputOpReturn.size() > 0) { auto lockingScriptOpReturn = Script::buildOpReturnScript(plan.outputOpReturn); - tx.outputs.push_back(TransactionOutput(0, lockingScriptOpReturn)); + tx.outputs.emplace_back(0, lockingScriptOpReturn); } return tx; diff --git a/src/Cbor.cpp b/src/Cbor.cpp index add7d0946d4..cccab743fe2 100644 --- a/src/Cbor.cpp +++ b/src/Cbor.cpp @@ -314,7 +314,7 @@ vector Decode::getCompoundElements(uint32_t countMultiplier, TW::byte ex if (idx + elemLen > length()) { throw std::invalid_argument("CBOR array data too short"); } - elems.push_back(Decode(data, subStart + idx, elemLen)); + elems.emplace_back(Decode(data, subStart + idx, elemLen)); idx += elemLen; } return elems; diff --git a/src/Decred/Transaction.cpp b/src/Decred/Transaction.cpp index 7f924d59204..705d37777bb 100644 --- a/src/Decred/Transaction.cpp +++ b/src/Decred/Transaction.cpp @@ -52,7 +52,7 @@ Data Transaction::computeSignatureHash(const Bitcoin::Script& prevOutScript, siz break; case TWBitcoinSigHashTypeSingle: outputsToSign.clear(); - std::copy(outputs.begin(), outputs.begin() + index + 1, outputsToSign.end()); + std::copy(outputs.begin(), outputs.begin() + index + 1, std::back_inserter(outputsToSign)); break; default: // Keep all outputs diff --git a/src/EOS/Name.h b/src/EOS/Name.h index 3d3d3721a47..1bef7d31b7e 100644 --- a/src/EOS/Name.h +++ b/src/EOS/Name.h @@ -14,7 +14,7 @@ class Name { public: uint64_t value = 0; - Name() { } + Name() = default; Name(const std::string& str); uint64_t toSymbol(char c) const noexcept; std::string string() const noexcept; diff --git a/src/Ethereum/RLP.cpp b/src/Ethereum/RLP.cpp index 4a4b7bcba6c..7098d75ff7a 100644 --- a/src/Ethereum/RLP.cpp +++ b/src/Ethereum/RLP.cpp @@ -114,7 +114,7 @@ RLP::DecodedItem RLP::decode(const Data& input) { auto prefix = input[0]; if (prefix <= 0x7f) { // 00--7f: a single byte whose value is in the [0x00, 0x7f] range, that byte is its own RLP encoding. - item.decoded.push_back(Data{input[0]}); + item.decoded.emplace_back(Data{input[0]}); item.remainder = subData(input, 1); return item; } diff --git a/src/Filecoin/Address.cpp b/src/Filecoin/Address.cpp index 28ca9daf774..ab464634e87 100644 --- a/src/Filecoin/Address.cpp +++ b/src/Filecoin/Address.cpp @@ -7,6 +7,7 @@ #include "Address.h" #include +#include #include "../Base32.h" #include "../Data.h" @@ -151,11 +152,11 @@ std::string Address::string() const { uint64_t id = 0; unsigned shift = 0; for (int i = 1; i < bytes.size(); i++) { - if (bytes[i] < 0x80) { - id |= bytes[i] << shift; + if (bytes[i] <= SCHAR_MAX) { + id |= static_cast(bytes[i]) << shift; break; } else { - id |= ((uint64_t)(bytes[i] & 0x7F)) << shift; + id |= static_cast(bytes[i] & SCHAR_MAX) << shift; shift += 7; } } diff --git a/src/NEO/ReadData.h b/src/NEO/ReadData.h index 3c273d75dec..c757c308f4f 100644 --- a/src/NEO/ReadData.h +++ b/src/NEO/ReadData.h @@ -27,7 +27,7 @@ template static std::vector concat(const std::vector& v1, const std::vector& v2) { std::vector v(v1); v.insert(v.end(), v2.begin(), v2.end()); - return std::move(v); + return v; } } // namespace TW diff --git a/src/Polkadot/SS58Address.h b/src/Polkadot/SS58Address.h index 2d8846130da..20d4e292f70 100644 --- a/src/Polkadot/SS58Address.h +++ b/src/Polkadot/SS58Address.h @@ -12,7 +12,7 @@ #include -const std::string SS58Prefix = "SS58PRE"; +inline const std::string SS58Prefix{"SS58PRE"}; namespace TW { diff --git a/src/Result.h b/src/Result.h index c7faede9896..9e5a1f4c8f4 100644 --- a/src/Result.h +++ b/src/Result.h @@ -42,7 +42,7 @@ struct Result { using Storage = typename std::aligned_storage::type; /// Wether the operation succeeded. - bool success_; + bool success_{false}; Storage storage_; public: @@ -73,6 +73,7 @@ struct Result { } else { new (&storage_) E(other.get()); } + return *this; } Result(Result&& other) { @@ -96,6 +97,7 @@ struct Result { } else { new (&storage_) E(std::move(other.get())); } + return *this; } ~Result() { diff --git a/src/Solana/Program.cpp b/src/Solana/Program.cpp index ae33d08bd3d..8a70254a82a 100644 --- a/src/Solana/Program.cpp +++ b/src/Solana/Program.cpp @@ -12,6 +12,7 @@ #include +#include #include using namespace TW; @@ -64,20 +65,17 @@ Address TokenProgram::defaultTokenAddress(const Address& mainAddress, const Addr Address TokenProgram::findProgramAddress(const std::vector& seeds, const Address& programId) { Address result(Data(32)); // cycle through seeds for the rare case when result is not valid - for (uint8_t seed = 255; seed >= 0; --seed) { - std::vector seedsCopy; - for (auto& s: seeds) { - seedsCopy.push_back(s); - } - // add extra seed - seedsCopy.push_back({seed}); + auto bumpSeed = Data{std::numeric_limits::max()}; + for (std::uint8_t seed = 0; seed <= std::numeric_limits::max(); ++seed) { + std::vector seedsCopy = seeds; + seedsCopy.emplace_back(bumpSeed); Address address = createProgramAddress(seedsCopy, Address(ASSOCIATED_TOKEN_PROGRAM_ID_ADDRESS)); PublicKey publicKey = PublicKey(TW::data(address.bytes.data(), address.bytes.size()), TWPublicKeyTypeED25519); if (!publicKey.isValidED25519()) { result = address; break; } - // try next seed + bumpSeed[0] -= 1; } return result; } diff --git a/src/Solana/Signer.cpp b/src/Solana/Signer.cpp index f4311dfa35f..c5a4166fb6d 100644 --- a/src/Solana/Signer.cpp +++ b/src/Solana/Signer.cpp @@ -33,7 +33,7 @@ std::vector
convertReferences(const google::protobuf::RepeatedPtrField< std::vector
ret; for (auto i = 0; i < references.size(); ++i) { if (Address::isValid(references[i])) { - ret.push_back(Address(references[i])); + ret.emplace_back(references[i]); } } return ret; @@ -43,7 +43,6 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto blockhash = Solana::Hash(input.recent_blockhash()); auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); Message message; - std::string stakePubkey; std::vector signerKeys; switch (input.transaction_type_case()) { diff --git a/src/Solana/Transaction.h b/src/Solana/Transaction.h index 118a0151c00..b29bd5ee5b8 100644 --- a/src/Solana/Transaction.h +++ b/src/Solana/Transaction.h @@ -285,8 +285,8 @@ class Message { void compileInstructions(); static void appendReferences(std::vector& accountMetas, const std::vector
& references) { - for (auto reference: references) { - accountMetas.push_back(AccountMeta(reference, false, true)); + for (auto &&reference: references) { + accountMetas.emplace_back(reference, false, true); } } @@ -317,6 +317,7 @@ class Message { auto sysvarStakeHistoryId = Address(SYSVAR_STAKE_HISTORY_ID_ADDRESS); auto stakeProgramId = Address(STAKE_PROGRAM_ID_ADDRESS); std::vector instructions; + instructions.reserve(3); // create_account_with_seed instruction Address seed = Address(data(recentBlockhash.bytes.data(), recentBlockhash.bytes.size())); auto createAccountInstruction = Instruction::createAccountWithSeed(std::vector{ @@ -452,7 +453,8 @@ class Message { const auto systemProgramId = Address(SYSTEM_PROGRAM_ID_ADDRESS); const auto tokenProgramId = Address(TOKEN_PROGRAM_ID_ADDRESS); std::vector instructions; - instructions.push_back(Instruction::createTokenCreateAccount(std::vector{ + instructions.reserve(3); + instructions.emplace_back(Instruction::createTokenCreateAccount(std::vector{ AccountMeta(signer, true, false), // fundingAddress, AccountMeta(recipientTokenAddress, false, false), AccountMeta(recipientMainAddress, false, true), @@ -463,7 +465,7 @@ class Message { })); if (memo.length() > 0) { // Optional memo. Order: before transfer, as per documentation. - instructions.push_back(Instruction::createMemo(memo)); + instructions.emplace_back(Instruction::createMemo(memo)); } std::vector accountMetas = { AccountMeta(senderTokenAddress, false, false), diff --git a/src/TransactionCompiler.cpp b/src/TransactionCompiler.cpp index cc264093075..2f725ab6780 100644 --- a/src/TransactionCompiler.cpp +++ b/src/TransactionCompiler.cpp @@ -29,7 +29,7 @@ Data TransactionCompiler::compileWithSignatures(TWCoinType coinType, const Data& if (!PublicKey::isValid(p, publicKeyType)) { throw std::invalid_argument("Invalid public key"); } - pubs.push_back(PublicKey(p, publicKeyType)); + pubs.emplace_back(p, publicKeyType); } Data txOutput; diff --git a/src/Waves/Address.cpp b/src/Waves/Address.cpp index 685f4327fb5..f95c9de7c58 100644 --- a/src/Waves/Address.cpp +++ b/src/Waves/Address.cpp @@ -40,8 +40,6 @@ bool Address::isValid(const Data& decoded) { const auto data_checksum = Data(decoded.end() - 4, decoded.end()); const auto calculated_hash = secureHash(data); const auto calculated_checksum = Data(calculated_hash.begin(), calculated_hash.begin() + 4); - const auto h = hex(data); - const auto h2 = hex(calculated_hash); return std::memcmp(data_checksum.data(), calculated_checksum.data(), 4) == 0; } @@ -83,4 +81,4 @@ Address::Address(const PublicKey &publicKey) { std::string Address::string() const { return Base58::bitcoin.encode(bytes); -} \ No newline at end of file +} From f464e68232fd6bfdb04ab8e5072a9222ec144120 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 15 Jul 2022 09:45:07 +0200 Subject: [PATCH 027/497] [Wasm]: Change CMake logic (#2376) * feat(wasm): simplify wasm cmake logic / use toolchain * feat(cmake): simplify options name * feat(wasm): use TW_COMPILE_WASM for test check --- .github/workflows/linux-ci.yml | 2 +- CMakeLists.txt | 6 ++- cmake/StandardSettings.cmake | 8 +++- cmake/StaticAnalyzers.cmake | 4 +- cmake/Wasm.cmake | 79 ---------------------------------- tools/wasm-build | 6 +-- 6 files changed, 17 insertions(+), 88 deletions(-) delete mode 100644 cmake/Wasm.cmake diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 0d29b3f9eab..7c06e7a3504 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -37,7 +37,7 @@ jobs: - name: CMake (coverage/clang-tidy/clang-asan) if: github.ref == 'refs/heads/master' run: | - cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCODE_COVERAGE=ON -DTrustWalletCore_ENABLE_CLANG_TIDY=ON -DCLANG_ASAN=ON + cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCODE_COVERAGE=ON -DTW_ENABLE_CLANG_TIDY=ON -DCLANG_ASAN=ON env: CC: /usr/bin/clang CXX: /usr/bin/clang++ diff --git a/CMakeLists.txt b/CMakeLists.txt index 2838c20342a..29e2ac9f3dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,10 @@ include_directories(${PREFIX}/include) link_directories(${PREFIX}/lib) add_subdirectory(trezor-crypto) +if (TW_COMPILE_WASM) + message(STATUS "Wasm build enabled") + add_subdirectory(wasm) +endif() macro(find_host_package) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) @@ -112,7 +116,7 @@ target_include_directories(TrustWalletCore ${CMAKE_CURRENT_SOURCE_DIR}/build/local/include ) -if(NOT ANDROID AND NOT IOS_PLATFORM) +if(NOT ANDROID AND NOT IOS_PLATFORM AND NOT TW_COMPILE_WASM) add_subdirectory(tests) add_subdirectory(walletconsole/lib) add_subdirectory(walletconsole) diff --git a/cmake/StandardSettings.cmake b/cmake/StandardSettings.cmake index ad21616da1a..35b85c4a023 100644 --- a/cmake/StandardSettings.cmake +++ b/cmake/StandardSettings.cmake @@ -3,4 +3,10 @@ # # Currently supporting: Clang-Tidy. -option(${PROJECT_NAME}_ENABLE_CLANG_TIDY "Enable static analysis with Clang-Tidy." OFF) \ No newline at end of file +option(TW_ENABLE_CLANG_TIDY "Enable static analysis with Clang-Tidy." OFF) + +# +# Specific platforms support +# +# Currently supporting: Wasm. +option(TW_COMPILE_WASM "Target Wasm" OFF) diff --git a/cmake/StaticAnalyzers.cmake b/cmake/StaticAnalyzers.cmake index 07537ca88c4..37e7c2ecd5f 100644 --- a/cmake/StaticAnalyzers.cmake +++ b/cmake/StaticAnalyzers.cmake @@ -1,4 +1,4 @@ -if(${PROJECT_NAME}_ENABLE_CLANG_TIDY) +if(TW_ENABLE_CLANG_TIDY) find_program(CLANGTIDY clang-tidy) if(CLANGTIDY) set(CMAKE_CXX_CLANG_TIDY ${CLANGTIDY} -extra-arg=-Wno-unknown-warning-option) @@ -6,4 +6,4 @@ if(${PROJECT_NAME}_ENABLE_CLANG_TIDY) else() message(SEND_ERROR "Clang-Tidy requested but executable not found.") endif() -endif() \ No newline at end of file +endif() diff --git a/cmake/Wasm.cmake b/cmake/Wasm.cmake deleted file mode 100644 index 13535817e1d..00000000000 --- a/cmake/Wasm.cmake +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright © 2017-2022 Trust Wallet. -# -# This file is part of Trust. The full Trust copyright notice, including -# terms governing use, modification, and redistribution, is contained in the -# file LICENSE at the root of the source code distribution tree. - -cmake_minimum_required(VERSION 3.8 FATAL_ERROR) - -project(TrustWalletCore) - -include(GNUInstallDirs) - -message(STATUS "Building for emscripten") - -# Configure warnings -set(TW_CXX_WARNINGS "-Wshorten-64-to-32") -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TW_CXX_WARNINGS}") -set(CMAKE_EXPORT_COMPILE_COMMANDS 1) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) -set(CMAKE_CXX_VISIBILITY_PRESET hidden) - -if ("$ENV{PREFIX}" STREQUAL "") - set(PREFIX "${CMAKE_SOURCE_DIR}/build/local") -else() - set(PREFIX "$ENV{PREFIX}") -endif() - -# Configure CCache if available -find_program(CCACHE_FOUND ccache) -if(CCACHE_FOUND) - set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) - set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) -endif(CCACHE_FOUND) - -include_directories(${PREFIX}/include) -link_directories(${PREFIX}/lib) - -add_subdirectory(trezor-crypto) -add_subdirectory(wasm) - -find_package(Boost) - -include(cmake/Protobuf.cmake) - -file(GLOB_RECURSE sources src/*.c src/*.cc src/*.cpp src/*.h) -add_library(TrustWalletCore ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) - -target_link_libraries(TrustWalletCore PRIVATE TrezorCrypto protobuf Boost::boost) -target_compile_options(TrustWalletCore PRIVATE "-Wall") - -set_target_properties(TrustWalletCore - PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON -) - -target_include_directories(TrustWalletCore - PUBLIC - $ - $ - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/src - ${CMAKE_CURRENT_SOURCE_DIR}/build/local/include -) - -install(TARGETS TrustWalletCore - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -) - -install( - DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/WalletCore - FILES_MATCHING PATTERN "*.h" -) - -install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/tools/wasm-build b/tools/wasm-build index dd291ffab54..2fa483726a2 100755 --- a/tools/wasm-build +++ b/tools/wasm-build @@ -13,12 +13,10 @@ build_folder=${src_dir}/wasm-build boost_dir=${EMSDK}/upstream/emscripten/system/include pushd ${src_dir} -cp cmake/Wasm.cmake CMakeLists.txt - # cmake -emcmake cmake -Bwasm-build -DBoost_INCLUDE_DIR=${boost_dir} +cmake -Bwasm-build -DBoost_INCLUDE_DIR=${boost_dir} -DTW_COMPILE_WASM=ON -DCMAKE_TOOLCHAIN_FILE=${EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake # make -emmake make -Cwasm-build +make -j8 -Cwasm-build popd From 3736e95fc6a576b5e06fcc97e24c0a68e2fa83e1 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 21 Jul 2022 01:13:01 +0200 Subject: [PATCH 028/497] [Interface]: Expose TWCoinTypeDerivationPathWithDerivation to C Interface (#2394) * feat(tw_coin_type): add TWCoinTypeDerivationPathExplicit method - add TWCoinTypeDerivationPathExplicit method - add unit tests - Add solana test - Apply review fixes - Rename TWCoinTypeDerivationPathExplicit to TWCoinTypeDerivationPathWithDerivation * feat(derivation_path): add kotlin unit tests * style(derivation_path): import order * feat(derivation_path): add swift unit tests --- .../core/app/blockchains/TestCoinType.kt | 16 +++++++++++-- include/TrustWalletCore/TWCoinType.h | 5 ++++ src/interface/TWCoinType.cpp | 8 ++++++- swift/Tests/CoinTypeTests.swift | 6 +++++ tests/interface/TWCoinTypeTests.cpp | 23 ++++++++++++++++++- 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/TestCoinType.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/TestCoinType.kt index 7d4fe6bda0a..f8fc2f3a5bf 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/TestCoinType.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/TestCoinType.kt @@ -3,14 +3,16 @@ package com.trustwallet.core.app.blockchains import wallet.core.jni.CoinType import wallet.core.jni.Curve import wallet.core.jni.Purpose +import wallet.core.jni.Derivation + import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse import org.junit.Test + class TestCoinType { init { - System.loadLibrary("TrustWalletCore"); + System.loadLibrary("TrustWalletCore") } @Test @@ -43,4 +45,14 @@ class TestCoinType { fun testCoinCurve() { assertEquals(Curve.SECP256K1, CoinType.BITCOIN.curve()) } + + @Test + fun testDerivationPath() { + var res = CoinType.createFromValue(CoinType.BITCOIN.value()).derivationPath().toString() + assertEquals(res, "m/84'/0'/0'/0/0") + res = CoinType.createFromValue(CoinType.BITCOIN.value()).derivationPathWithDerivation(Derivation.BITCOINLEGACY).toString() + assertEquals(res, "m/44'/0'/0'/0/0") + res = CoinType.createFromValue(CoinType.SOLANA.value()).derivationPathWithDerivation(Derivation.SOLANASOLANA).toString() + assertEquals(res, "m/44'/501'/0'/0'") + } } diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 4751fea77e6..2a2f9ec21f6 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -14,6 +14,7 @@ #include "TWPrivateKey.h" #include "TWPurpose.h" #include "TWString.h" +#include "TWDerivation.h" TW_EXTERN_C_BEGIN @@ -142,6 +143,10 @@ bool TWCoinTypeValidate(enum TWCoinType coin, TWString* _Nonnull address); TW_EXPORT_METHOD TWString* _Nonnull TWCoinTypeDerivationPath(enum TWCoinType coin); +/// Returns the derivation path for a particular coin with the explicit given derivation. +TW_EXPORT_METHOD +TWString* _Nonnull TWCoinTypeDerivationPathWithDerivation(enum TWCoinType coin, enum TWDerivation derivation); + /// Derives the address for a particular coin from the private key. TW_EXPORT_METHOD TWString* _Nonnull TWCoinTypeDeriveAddress(enum TWCoinType coin, diff --git a/src/interface/TWCoinType.cpp b/src/interface/TWCoinType.cpp index a86e2a22c2c..2d58d5a7be5 100644 --- a/src/interface/TWCoinType.cpp +++ b/src/interface/TWCoinType.cpp @@ -39,6 +39,12 @@ TWString *_Nonnull TWCoinTypeDerivationPath(enum TWCoinType coin) { return TWStringCreateWithUTF8Bytes(string.c_str()); } +TWString* TWCoinTypeDerivationPathWithDerivation(enum TWCoinType coin, enum TWDerivation derivation) { + const auto path = TW::derivationPath(coin, derivation); + const auto string = path.string(); + return TWStringCreateWithUTF8Bytes(string.c_str()); +} + TWString *_Nonnull TWCoinTypeDeriveAddress(enum TWCoinType coin, struct TWPrivateKey *_Nonnull privateKey) { const auto string = TW::deriveAddress(coin, privateKey->impl); return TWStringCreateWithUTF8Bytes(string.c_str()); @@ -75,4 +81,4 @@ uint32_t TWCoinTypeSlip44Id(enum TWCoinType coin) { enum TWPublicKeyType TWCoinTypePublicKeyType(enum TWCoinType coin) { return TW::publicKeyType(coin); -} \ No newline at end of file +} diff --git a/swift/Tests/CoinTypeTests.swift b/swift/Tests/CoinTypeTests.swift index 5b49e9325d5..353b85cf729 100644 --- a/swift/Tests/CoinTypeTests.swift +++ b/swift/Tests/CoinTypeTests.swift @@ -30,4 +30,10 @@ class CoinTypeTests: XCTestCase { XCTAssertEqual(CoinType.avalancheCChain.rawValue, 10009000) XCTAssertEqual(CoinType.xdai.rawValue, 10000100) } + + func testCoinDerivation() { + XCTAssertEqual(CoinType.bitcoin.derivationPath(), "m/84'/0'/0'/0/0") + XCTAssertEqual(CoinType.bitcoin.derivationPathWithDerivation(derivation: Derivation.bitcoinLegacy), "m/44'/0'/0'/0/0") + XCTAssertEqual(CoinType.solana.derivationPathWithDerivation(derivation: Derivation.solanaSolana), "m/44'/501'/0'/0'") + } } diff --git a/tests/interface/TWCoinTypeTests.cpp b/tests/interface/TWCoinTypeTests.cpp index 4cc2fc3877b..ab02da2e41a 100644 --- a/tests/interface/TWCoinTypeTests.cpp +++ b/tests/interface/TWCoinTypeTests.cpp @@ -138,4 +138,25 @@ TEST(TWCoinType, TWPublicKeyType) { ASSERT_EQ(TWPublicKeyTypeSECP256k1, TWCoinTypePublicKeyType(TWCoinTypeRavencoin)); ASSERT_EQ(TWPublicKeyTypeCURVE25519, TWCoinTypePublicKeyType(TWCoinTypeWaves)); ASSERT_EQ(TWPublicKeyTypeNIST256p1, TWCoinTypePublicKeyType(TWCoinTypeNEO)); -} \ No newline at end of file +} + +TEST(TWCoinType, TWCoinTypeDerivationPath) { + auto res = TWCoinTypeDerivationPath(TWCoinTypeBitcoin); + auto result = *reinterpret_cast(res); + ASSERT_EQ(result, "m/84'/0'/0'/0/0"); + TWStringDelete(res); +} + +TEST(TWCoinType, TWCoinTypeDerivationPathWithDerivation) { + auto res = TWCoinTypeDerivationPathWithDerivation(TWCoinTypeBitcoin, TWDerivationBitcoinLegacy); + auto result = *reinterpret_cast(res); + ASSERT_EQ(result, "m/44'/0'/0'/0/0"); + TWStringDelete(res); +} + +TEST(TWCoinType, TWCoinTypeDerivationPathWithDerivationSolana) { + auto res = TWCoinTypeDerivationPathWithDerivation(TWCoinTypeSolana, TWDerivationSolanaSolana); + auto result = *reinterpret_cast(res); + ASSERT_EQ(result, "m/44'/501'/0'/0'"); + TWStringDelete(res); +} From b9162a4dbf685a3557d8f811115dab301c430d0e Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 21 Jul 2022 09:14:40 +0200 Subject: [PATCH 029/497] [Improvements]: Modernize CMake (#2380) * feat(cmake): first part modernize - Use Interface library - Move options to StandardSettings.cmake - Don't use harmfull link_directories and include_directories * feat(cmake): add CompilerWarnings.cmake * feat(cmake): add warning as error option * feat(cmake): add opt flags and compile features * feat(cmake): simplify coverage/sanitizer instruments * feat(cmake): add missing target * feat(cmake): add pvs studio options * feat(cmake): finalize pvs studio cfg * feat(cmake): clean * feat(cmake): apply DRY on targets that link against TrustWalletCore * feat(cmake): add helpers, variables for IDE * feat(cmake): add sarif vscode gen for pvs studio * feat(cmake): use option instead of set * feat(ci): add pvs-studio-analyze * Fix brew prefix for m1 mac Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- .github/workflows/linux-ci.yml | 4 +- .gitignore | 1 + CMakeLists.txt | 118 ++--- cmake/CompilerWarnings.cmake | 94 ++++ cmake/FindHostPackage.cmake | 9 + cmake/PVS-Studio.cmake | 615 ++++++++++++++++++++++ cmake/StandardSettings.cmake | 73 ++- cmake/StaticAnalyzers.cmake | 34 +- tools/pvs-studio-analyze | 25 + tools/pvs-studio/config.cfg | 11 + trezor-crypto/crypto/tests/CMakeLists.txt | 3 +- walletconsole/CMakeLists.txt | 7 - walletconsole/lib/CMakeLists.txt | 7 - 13 files changed, 902 insertions(+), 99 deletions(-) create mode 100644 cmake/CompilerWarnings.cmake create mode 100644 cmake/FindHostPackage.cmake create mode 100644 cmake/PVS-Studio.cmake create mode 100755 tools/pvs-studio-analyze create mode 100644 tools/pvs-studio/config.cfg diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 7c06e7a3504..6b493e72707 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -37,14 +37,14 @@ jobs: - name: CMake (coverage/clang-tidy/clang-asan) if: github.ref == 'refs/heads/master' run: | - cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCODE_COVERAGE=ON -DTW_ENABLE_CLANG_TIDY=ON -DCLANG_ASAN=ON + cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DTW_CODE_COVERAGE=ON -DTW_ENABLE_CLANG_TIDY=ON -DTW_CLANG_ASAN=ON env: CC: /usr/bin/clang CXX: /usr/bin/clang++ - name: CMake (coverage) if: github.ref != 'refs/heads/master' run: | - cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCODE_COVERAGE=ON + cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DTW_CODE_COVERAGE=ON env: CC: /usr/bin/clang CXX: /usr/bin/clang++ diff --git a/.gitignore b/.gitignore index 5686032fd60..412379628d7 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ cmake-build-debug/ .cquery_cache/ .cxx/ .cache/ +build_pvs_studio/ # Dependencies node_modules diff --git a/CMakeLists.txt b/CMakeLists.txt index 29e2ac9f3dc..44193b00e9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,60 +4,36 @@ # terms governing use, modification, and redistribution, is contained in the # file LICENSE at the root of the source code distribution tree. -cmake_minimum_required(VERSION 3.8 FATAL_ERROR) +cmake_minimum_required(VERSION 3.18 FATAL_ERROR) project(TrustWalletCore) -include(GNUInstallDirs) -include(cmake/StandardSettings.cmake) -include(cmake/StaticAnalyzers.cmake) - -# Configure warnings -set(TW_CXX_WARNINGS "-Wshorten-64-to-32") -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TW_CXX_WARNINGS}") -set(CMAKE_EXPORT_COMPILE_COMMANDS 1) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) -set(CMAKE_CXX_VISIBILITY_PRESET hidden) - -set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14" CACHE STRING "Minimum OS X deployment version" FORCE) - if (NOT ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) message(FATAL_ERROR "You should use clang compiler") -endif() +endif () if ("$ENV{PREFIX}" STREQUAL "") set(PREFIX "${CMAKE_SOURCE_DIR}/build/local") -else() +else () set(PREFIX "$ENV{PREFIX}") -endif() +endif () -# Configure CCache if available -find_program(CCACHE_FOUND ccache) -if(CCACHE_FOUND) - set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) - set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) -endif(CCACHE_FOUND) +include(GNUInstallDirs) +include(cmake/StandardSettings.cmake) +include(cmake/CompilerWarnings.cmake) +include(cmake/StaticAnalyzers.cmake) +include(cmake/FindHostPackage.cmake) -include_directories(${PREFIX}/include) -link_directories(${PREFIX}/lib) +add_library(${PROJECT_NAME}_INTERFACE INTERFACE) +target_include_directories(${PROJECT_NAME}_INTERFACE INTERFACE ${PREFIX}/include) +target_link_directories(${PROJECT_NAME}_INTERFACE INTERFACE ${PREFIX}/lib) +set_project_warnings(${PROJECT_NAME}_INTERFACE) add_subdirectory(trezor-crypto) if (TW_COMPILE_WASM) message(STATUS "Wasm build enabled") add_subdirectory(wasm) -endif() - -macro(find_host_package) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) - find_package(${ARGN}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endmacro(find_host_package) +endif () find_host_package(Boost REQUIRED) @@ -66,73 +42,65 @@ include(ExternalProject) # Dependencies include(cmake/Protobuf.cmake) -option(CODE_COVERAGE "Enable coverage reporting" OFF) -if(CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fprofile-arcs -ftest-coverage") - set(CMAKE_EXE_LINKER_FLAGS "-fprofile-arcs -ftest-coverage") -endif() - -option(CLANG_ASAN "Enable ASAN dynamic address sanitizer" OFF) -if(CLANG_ASAN) - # https://clang.llvm.org/docs/AddressSanitizer.html - # https://github.com/trustwallet/wallet-core/issues/1170 - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer") - set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer") - message("CLANG_ASAN on, ${CMAKE_CXX_FLAGS_DEBUG}") -endif() - # Source files -if(${ANDROID}) +if (${ANDROID}) message("Configuring for JNI") file(GLOB_RECURSE sources src/*.c src/*.cc src/*.cpp src/*.h jni/cpp/*.c jni/cpp/*.cpp jni/cpp/*.h jni/cpp/*.c) add_library(TrustWalletCore SHARED ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) - find_library(log-lib log) - target_link_libraries(TrustWalletCore PRIVATE TrezorCrypto protobuf ${log-lib} Boost::boost) -else() + target_link_libraries(TrustWalletCore PUBLIC ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf ${log-lib} Boost::boost) +else () message("Configuring standalone") file(GLOB_RECURSE sources src/*.c src/*.cc src/*.cpp src/*.h) add_library(TrustWalletCore ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) - target_link_libraries(TrustWalletCore PRIVATE TrezorCrypto protobuf Boost::boost) -endif() -target_compile_options(TrustWalletCore PRIVATE "-Wall") + target_link_libraries(TrustWalletCore PUBLIC ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf Boost::boost) +endif () -set_target_properties(TrustWalletCore - PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON -) +if (TW_CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + target_enable_coverage(TrustWalletCore) +endif () + +if (TW_CLANG_ASAN) + target_enable_asan(TrustWalletCore) +endif () # Define headers for this library. PUBLIC headers are used for compiling the # library, and will be added to consumers' build paths. target_include_directories(TrustWalletCore - PUBLIC + PUBLIC $ $ - PRIVATE + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/jni/cpp ${CMAKE_CURRENT_SOURCE_DIR}/build/local/include -) + ) -if(NOT ANDROID AND NOT IOS_PLATFORM AND NOT TW_COMPILE_WASM) +if (TW_UNIT_TESTS) add_subdirectory(tests) +endif () + +if (TW_BUILD_EXAMPLES) add_subdirectory(walletconsole/lib) add_subdirectory(walletconsole) endif() +if (TW_ENABLE_PVS_STUDIO) + tw_add_pvs_studio_target(TrustWalletCore) +endif() + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/swift/cpp.xcconfig.in ${CMAKE_CURRENT_SOURCE_DIR}/swift/cpp.xcconfig @ONLY) install(TARGETS TrustWalletCore - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -) + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) install( - DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/WalletCore - FILES_MATCHING PATTERN "*.h" + DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/WalletCore + FILES_MATCHING PATTERN "*.h" ) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake new file mode 100644 index 00000000000..c62632cdb71 --- /dev/null +++ b/cmake/CompilerWarnings.cmake @@ -0,0 +1,94 @@ +macro(target_enable_asan target) + message("-- ASAN Enabled, Configuring...") + target_compile_options(${target} PUBLIC + $<$,$>:-fsanitize=address -fno-omit-frame-pointer> + $<$,$>:-fsanitize=address -fno-omit-frame-pointer>) + target_link_options(${target} PUBLIC + $<$,$>:-fsanitize=address -fno-omit-frame-pointer> + $<$,$>:-fsanitize=address -fno-omit-frame-pointer>) +endmacro() + +macro(target_enable_coverage target) + message(STATUS "Code coverage ON") + # This option is used to compile and link code instrumented for coverage analysis. + # The option is a synonym for -fprofile-arcs -ftest-coverage (when compiling) and -lgcov (when linking). + # See the documentation for those options for more details. + # https://gcc.gnu.org/onlinedocs/gcc-9.3.0/gcc/Instrumentation-Options.html + if (TW_IDE_CLION) + message(STATUS "Code coverage for Clion ON") + target_compile_options(${target} PUBLIC + $<$,$>:-fprofile-instr-generate -fcoverage-mapping> + $<$,$>:-fprofile-instr-generate -fcoverage-mapping> + $<$,$>:-fprofile-instr-generate -fcoverage-mapping>) + target_link_options(${target} PUBLIC + $<$,$>:-fprofile-instr-generate -fcoverage-mapping> + $<$,$>:-fprofile-instr-generate -fcoverage-mapping> + $<$,$>:-fprofile-instr-generate -fcoverage-mapping>) + else() + target_compile_options(${target} PUBLIC + $<$,$>:--coverage> + $<$,$>:--coverage>) + target_link_options(${target} PUBLIC + $<$,$>:--coverage> + $<$,$>:--coverage>) + endif () +endmacro() + +add_library(tw_error_settings INTERFACE) +add_library(tw::error_settings ALIAS tw_error_settings) + +add_library(tw_defaults_features INTERFACE) +add_library(tw::defaults_features ALIAS tw_defaults_features) + +add_library(tw_optimize_settings INTERFACE) +add_library(tw::optimize_settings ALIAS tw_optimize_settings) + +target_compile_options( + tw_error_settings + INTERFACE + -Wall + #-Wextra # reasonable and standard + -Wfatal-errors # short error report + #-Wshadow # warn the user if a variable declaration shadows one from a + -Wshorten-64-to-32 + # parent context + #-Wnon-virtual-dtor # warn the user if a class with virtual functions has a + # non-virtual destructor. This helps catch hard to + # track down memory errors + #-Wold-style-cast # warn for c-style casts + #-Wcast-align # warn for potential performance problem casts + #-Wunused # warn on anything being unused + #-Woverloaded-virtual # warn if you overload (not override) a virtual + # function + #-Wpedantic # warn if non-standard C++ is used + #-Wconversion # warn on type conversions that may lose data + #-Wsign-conversion # warn on sign conversions + #-Wnull-dereference # warn if a null dereference is detected + #-Wdouble-promotion # warn if float is implicit promoted to double + -Wformat=2 # warn on security issues around functions that format output +) + +if (TW_WARNINGS_AS_ERRORS) + target_compile_options( + tw_error_settings + INTERFACE + -Werror + ) +endif () + +target_compile_features(tw_defaults_features INTERFACE cxx_std_20) + +target_compile_options(tw_optimize_settings INTERFACE + $<$,$>:-O0 -g> + $<$,$>:-O0 -g> + $<$,$>:-O2> + $<$,$>:-O2> + ) + +function(set_project_warnings project_name) + target_link_libraries(${project_name} INTERFACE tw::error_settings tw::defaults_features tw::optimize_settings) + + if (NOT TARGET ${project_name}) + message(AUTHOR_WARNING "${project_name} is not a target, thus no compiler warning were added.") + endif () +endfunction() diff --git a/cmake/FindHostPackage.cmake b/cmake/FindHostPackage.cmake new file mode 100644 index 00000000000..188a2ee7e9d --- /dev/null +++ b/cmake/FindHostPackage.cmake @@ -0,0 +1,9 @@ +macro(find_host_package) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) + find_package(${ARGN}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endmacro(find_host_package) diff --git a/cmake/PVS-Studio.cmake b/cmake/PVS-Studio.cmake new file mode 100644 index 00000000000..d19bc3b105e --- /dev/null +++ b/cmake/PVS-Studio.cmake @@ -0,0 +1,615 @@ +# 2006-2008 (c) Viva64.com Team +# 2008-2018 (c) OOO "Program Verification Systems" +# +# Version 12 + +cmake_minimum_required(VERSION 3.0.0) +cmake_policy(SET CMP0054 NEW) + +if (PVS_STUDIO_AS_SCRIPT) + # This code runs at build time. + # It executes pvs-studio-analyzer and propagates its return value. + + set(in_cl_params FALSE) + set(additional_args) + + foreach (arg ${PVS_STUDIO_COMMAND}) + if (NOT in_cl_params) + if ("${arg}" STREQUAL "--cl-params") + set(in_cl_params TRUE) + endif () + else () + # A workaround for macOS frameworks (e.g. QtWidgets.framework) + # You can test this workaround on this project: https://github.com/easyaspi314/MidiEditor/tree/gba + if (APPLE AND "${arg}" MATCHES "^-I(.*)\\.framework$") + STRING(REGEX REPLACE "^-I(.*)\\.framework$" "\\1.framework" framework "${arg}") + if (IS_ABSOLUTE "${framework}") + get_filename_component(framework "${framework}" DIRECTORY) + list(APPEND additional_args "-iframework") + list(APPEND additional_args "${framework}") + endif () + endif () + endif () + endforeach () + + file(REMOVE "${PVS_STUDIO_LOG_FILE}") + execute_process(COMMAND ${PVS_STUDIO_COMMAND} ${additional_args} + RESULT_VARIABLE result + OUTPUT_VARIABLE output + ERROR_VARIABLE error) + + if (result AND NOT output MATCHES "^No compilation units were found\\.") + message(FATAL_ERROR "PVS-Studio exited with non-zero code.\nStdout:\n${output}\nStderr:\n${error}\n") + endif() + + return() +endif () + +if(__PVS_STUDIO_INCLUDED) + return() +endif() +set(__PVS_STUDIO_INCLUDED TRUE) + +set(PVS_STUDIO_SCRIPT "${CMAKE_CURRENT_LIST_FILE}") + +function (pvs_studio_log TEXT) + if (PVS_STUDIO_DEBUG) + message("PVS-Studio: ${TEXT}") + endif () +endfunction () + +function (pvs_studio_relative_path VAR ROOT FILEPATH) + if (WIN32) + STRING(REGEX REPLACE "\\\\" "/" ROOT ${ROOT}) + STRING(REGEX REPLACE "\\\\" "/" FILEPATH ${FILEPATH}) + endif() + set("${VAR}" "${FILEPATH}" PARENT_SCOPE) + if (IS_ABSOLUTE "${FILEPATH}") + file(RELATIVE_PATH RPATH "${ROOT}" "${FILEPATH}") + if (NOT IS_ABSOLUTE "${RPATH}") + set("${VAR}" "${RPATH}" PARENT_SCOPE) + endif() + endif() +endfunction () + +function (pvs_studio_join_path VAR DIR1 DIR2) + if ("${DIR2}" MATCHES "^(/|~|.:/).*$" OR "${DIR1}" STREQUAL "") + set("${VAR}" "${DIR2}" PARENT_SCOPE) + else () + set("${VAR}" "${DIR1}/${DIR2}" PARENT_SCOPE) + endif () +endfunction () + +macro (pvs_studio_append_flags_from_property CXX C DIR PREFIX) + if (NOT "${PROPERTY}" STREQUAL "NOTFOUND" AND NOT "${PROPERTY}" STREQUAL "PROPERTY-NOTFOUND") + foreach (PROP ${PROPERTY}) + pvs_studio_join_path(PROP "${DIR}" "${PROP}") + + if (APPLE AND "${PREFIX}" STREQUAL "-I" AND IS_ABSOLUTE "${PROP}" AND "${PROP}" MATCHES "\\.framework$") + get_filename_component(FRAMEWORK "${PROP}" DIRECTORY) + list(APPEND "${CXX}" "-iframework") + list(APPEND "${CXX}" "${FRAMEWORK}") + list(APPEND "${C}" "-iframework") + list(APPEND "${C}" "${FRAMEWORK}") + pvs_studio_log("framework: ${FRAMEWORK}") + elseif (NOT "${PROP}" STREQUAL "") + list(APPEND "${CXX}" "${PREFIX}${PROP}") + list(APPEND "${C}" "${PREFIX}${PROP}") + endif() + endforeach () + endif () +endmacro () + +macro (pvs_studio_append_standard_flag FLAGS STANDARD) + if ("${STANDARD}" MATCHES "^(99|11|14|17|20)$") + if ("${PVS_STUDIO_PREPROCESSOR}" MATCHES "gcc|clang") + list(APPEND "${FLAGS}" "-std=c++${STANDARD}") + endif () + endif () +endmacro () + +function (pvs_studio_set_directory_flags DIRECTORY CXX C) + set(CXX_FLAGS "${${CXX}}") + set(C_FLAGS "${${C}}") + + get_directory_property(PROPERTY DIRECTORY "${DIRECTORY}" INCLUDE_DIRECTORIES) + pvs_studio_append_flags_from_property(CXX_FLAGS C_FLAGS "${DIRECTORY}" "-I") + + get_directory_property(PROPERTY DIRECTORY "${DIRECTORY}" COMPILE_DEFINITIONS) + pvs_studio_append_flags_from_property(CXX_FLAGS C_FLAGS "" "-D") + + set("${CXX}" "${CXX_FLAGS}" PARENT_SCOPE) + set("${C}" "${C_FLAGS}" PARENT_SCOPE) +endfunction () + +function (pvs_studio_set_target_flags TARGET CXX C) + set(CXX_FLAGS "${${CXX}}") + set(C_FLAGS "${${C}}") + + if (NOT MSVC) + list(APPEND CXX_FLAGS "$<$:--sysroot=${CMAKE_SYSROOT}>") + list(APPEND C_FLAGS "$<$:--sysroot=${CMAKE_SYSROOT}>") + endif () + + set(prop_incdirs "$") + list(APPEND CXX_FLAGS "$<$:-I$-I>>") + list(APPEND C_FLAGS "$<$:-I$-I>>") + + set(prop_compdefs "$") + list(APPEND CXX_FLAGS "$<$:-D$-D>>") + list(APPEND C_FLAGS "$<$:-D$-D>>") + + set(prop_compopt "$") + list(APPEND CXX_FLAGS "$<$:$>>") + list(APPEND C_FLAGS "$<$:$>>") + + set("${CXX}" "${CXX_FLAGS}" PARENT_SCOPE) + set("${C}" "${C_FLAGS}" PARENT_SCOPE) +endfunction () + +function (pvs_studio_set_source_file_flags SOURCE) + set(LANGUAGE "") + + string(TOLOWER "${SOURCE}" SOURCE_LOWER) + if ("${LANGUAGE}" STREQUAL "" AND "${SOURCE_LOWER}" MATCHES "^.*\\.(c|cpp|cc|cx|cxx|cp|c\\+\\+)$") + if ("${SOURCE}" MATCHES "^.*\\.c$") + set(LANGUAGE C) + else () + set(LANGUAGE CXX) + endif () + endif () + + if ("${LANGUAGE}" STREQUAL "C") + set(CL_PARAMS ${PVS_STUDIO_C_FLAGS} ${PVS_STUDIO_TARGET_C_FLAGS} -DPVS_STUDIO) + elseif ("${LANGUAGE}" STREQUAL "CXX") + set(CL_PARAMS ${PVS_STUDIO_CXX_FLAGS} ${PVS_STUDIO_TARGET_CXX_FLAGS} -DPVS_STUDIO) + endif () + + set(PVS_STUDIO_LANGUAGE "${LANGUAGE}" PARENT_SCOPE) + set(PVS_STUDIO_CL_PARAMS "${CL_PARAMS}" PARENT_SCOPE) +endfunction () + +function (pvs_studio_analyze_file SOURCE SOURCE_DIR BINARY_DIR) + set(PLOGS ${PVS_STUDIO_PLOGS}) + pvs_studio_set_source_file_flags("${SOURCE}") + + get_filename_component(SOURCE "${SOURCE}" REALPATH) + + get_source_file_property(PROPERTY "${SOURCE}" HEADER_FILE_ONLY) + if (PROPERTY) + return() + endif () + + pvs_studio_relative_path(SOURCE_RELATIVE "${SOURCE_DIR}" "${SOURCE}") + pvs_studio_join_path(SOURCE "${SOURCE_DIR}" "${SOURCE}") + + set(LOG "${BINARY_DIR}/PVS-Studio/${SOURCE_RELATIVE}.plog") + get_filename_component(LOG "${LOG}" REALPATH) + get_filename_component(PARENT_DIR "${LOG}" DIRECTORY) + + if (EXISTS "${SOURCE}" AND NOT TARGET "${LOG}" AND NOT "${PVS_STUDIO_LANGUAGE}" STREQUAL "") + # A workaround to support implicit dependencies for ninja generators. + set(depPvsArg) + set(depCommandArg) + if (CMAKE_VERSION VERSION_GREATER 3.6 AND "${CMAKE_GENERATOR}" STREQUAL "Ninja") + pvs_studio_relative_path(relLog "${CMAKE_BINARY_DIR}" "${LOG}") + set(depPvsArg --dep-file "${LOG}.d" --dep-file-target "${relLog}") + set(depCommandArg DEPFILE "${LOG}.d") + endif () + + # https://public.kitware.com/Bug/print_bug_page.php?bug_id=14353 + # https://public.kitware.com/Bug/file/5436/expand_command.cmake + # + # It is a workaround to expand generator expressions. + set(cmdline "${PVS_STUDIO_BIN}" analyze + --output-file "${LOG}" + --source-file "${SOURCE}" + ${depPvsArg} + ${PVS_STUDIO_ARGS} + --cl-params "${PVS_STUDIO_CL_PARAMS}" "${SOURCE}") + + string(REPLACE ";" "$" cmdline "${cmdline}") + set(pvscmd "${CMAKE_COMMAND}" + -D "PVS_STUDIO_AS_SCRIPT=TRUE" + -D "PVS_STUDIO_COMMAND=${cmdline}" + -D "PVS_STUDIO_LOG_FILE=${LOG}" + -P "${PVS_STUDIO_SCRIPT}" + ) + + add_custom_command(OUTPUT "${LOG}" + COMMAND "${CMAKE_COMMAND}" -E make_directory "${PARENT_DIR}" + COMMAND "${CMAKE_COMMAND}" -E remove_directory "${LOG}" + COMMAND ${pvscmd} + WORKING_DIRECTORY "${BINARY_DIR}" + DEPENDS "${SOURCE}" "${PVS_STUDIO_SUPPRESS_BASE}" "${PVS_STUDIO_DEPENDS}" + IMPLICIT_DEPENDS "${PVS_STUDIO_LANGUAGE}" "${SOURCE}" + ${depCommandArg} + VERBATIM + COMMENT "Analyzing ${PVS_STUDIO_LANGUAGE} file ${SOURCE_RELATIVE}") + list(APPEND PLOGS "${LOG}") + endif () + set(PVS_STUDIO_PLOGS "${PLOGS}" PARENT_SCOPE) +endfunction () + +function (pvs_studio_analyze_target TARGET DIR) + set(PVS_STUDIO_PLOGS "${PVS_STUDIO_PLOGS}") + set(PVS_STUDIO_TARGET_CXX_FLAGS "") + set(PVS_STUDIO_TARGET_C_FLAGS "") + + get_target_property(PROPERTY "${TARGET}" SOURCES) + pvs_studio_relative_path(BINARY_DIR "${CMAKE_SOURCE_DIR}" "${DIR}") + if ("${BINARY_DIR}" MATCHES "^/.*$") + pvs_studio_join_path(BINARY_DIR "${CMAKE_BINARY_DIR}" "PVS-Studio/__${BINARY_DIR}") + else () + pvs_studio_join_path(BINARY_DIR "${CMAKE_BINARY_DIR}" "${BINARY_DIR}") + endif () + + file(MAKE_DIRECTORY "${BINARY_DIR}") + + pvs_studio_set_directory_flags("${DIR}" PVS_STUDIO_TARGET_CXX_FLAGS PVS_STUDIO_TARGET_C_FLAGS) + pvs_studio_set_target_flags("${TARGET}" PVS_STUDIO_TARGET_CXX_FLAGS PVS_STUDIO_TARGET_C_FLAGS) + + if (NOT "${PROPERTY}" STREQUAL "NOTFOUND" AND NOT "${PROPERTY}" STREQUAL "PROPERTY-NOTFOUND") + foreach (SOURCE ${PROPERTY}) + pvs_studio_join_path(SOURCE "${DIR}" "${SOURCE}") + pvs_studio_analyze_file("${SOURCE}" "${DIR}" "${BINARY_DIR}") + endforeach () + endif () + + set(PVS_STUDIO_PLOGS "${PVS_STUDIO_PLOGS}" PARENT_SCOPE) +endfunction () + +set(PVS_STUDIO_RECURSIVE_TARGETS) +set(PVS_STUDIO_RECURSIVE_TARGETS_NEW) + +macro(pvs_studio_get_recursive_targets TARGET) + get_target_property(libs "${TARGET}" LINK_LIBRARIES) + foreach (lib IN LISTS libs) + list(FIND PVS_STUDIO_RECURSIVE_TARGETS "${lib}" index) + if (TARGET "${lib}" AND "${index}" STREQUAL -1) + get_target_property(target_type "${lib}" TYPE) + if (NOT "${target_type}" STREQUAL "INTERFACE_LIBRARY") + list(APPEND PVS_STUDIO_RECURSIVE_TARGETS "${lib}") + list(APPEND PVS_STUDIO_RECURSIVE_TARGETS_NEW "${lib}") + pvs_studio_get_recursive_targets("${lib}") + endif () + endif () + endforeach () +endmacro() + +option(PVS_STUDIO_DISABLE OFF "Disable PVS-Studio targets") +option(PVS_STUDIO_DEBUG OFF "Add debug info") + +# pvs_studio_add_target +# Target options: +# ALL add PVS-Studio target to default build (default: off) +# TARGET target name of analysis target (default: pvs) +# ANALYZE targets... targets to analyze +# RECURSIVE analyze target's dependencies (requires CMake 3.5+) +# COMPILE_COMMANDS use compile_commands.json instead of targets (specified by the 'ANALYZE' option) to determine files for analysis +# (set CMAKE_EXPORT_COMPILE_COMMANDS, available only for Makefile and Ninja generators) +# +# Output options: +# OUTPUT prints report to stdout +# LOG path path to report (default: ${CMAKE_CURRENT_BINARY_DIR}/PVS-Studio.log) +# FORMAT format format of report +# MODE mode analyzers/levels filter (default: GA:1,2) +# HIDE_HELP do not print help message +# +# Analyzer options: +# PLATFORM name linux32/linux64 (default: linux64) +# PREPROCESSOR name preprocessor type: gcc/clang (default: auto detected) +# LICENSE path path to PVS-Studio.lic (default: ~/.config/PVS-Studio/PVS-Studio.lic) +# CONFIG path path to PVS-Studio.cfg +# CFG_TEXT text embedded PVS-Studio.cfg +# SUPPRESS_BASE path to suppress base file +# KEEP_COMBINED_PLOG do not delete combined plog file *.pvs.raw for further processing with plog-converter +# +# Misc options: +# DEPENDS targets.. additional target dependencies +# SOURCES path... list of source files to analyze +# BIN path path to pvs-studio-analyzer (Unix) or CompilerCommandsAnalyzer.exe (Windows) +# CONVERTER path path to plog-converter (Unix) or HtmlGenerator.exe (Windows) +# C_FLAGS flags... additional C_FLAGS +# CXX_FLAGS flags... additional CXX_FLAGS +# ARGS args... additional pvs-studio-analyzer/CompilerCommandsAnalyzer.exe flags +# CONVERTER_ARGS args... additional plog-converter/HtmlGenerator.exe flags +function (pvs_studio_add_target) + macro (default VAR VALUE) + if ("${${VAR}}" STREQUAL "") + set("${VAR}" "${VALUE}") + endif () + endmacro () + + set(PVS_STUDIO_SUPPORTED_PREPROCESSORS "gcc|clang|visualcpp") + if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + set(DEFAULT_PREPROCESSOR "clang") + elseif (MSVC) + set(DEFAULT_PREPROCESSOR "visualcpp") + else () + set(DEFAULT_PREPROCESSOR "gcc") + endif () + + set(OPTIONAL OUTPUT ALL RECURSIVE HIDE_HELP KEEP_COMBINED_PLOG COMPILE_COMMANDS KEEP_INTERMEDIATE_FILES) + set(SINGLE LICENSE CONFIG TARGET LOG FORMAT BIN CONVERTER PLATFORM PREPROCESSOR CFG_TEXT SUPPRESS_BASE) + set(MULTI SOURCES C_FLAGS CXX_FLAGS ARGS DEPENDS ANALYZE MODE CONVERTER_ARGS) + cmake_parse_arguments(PVS_STUDIO "${OPTIONAL}" "${SINGLE}" "${MULTI}" ${ARGN}) + + + default(PVS_STUDIO_C_FLAGS "") + default(PVS_STUDIO_CXX_FLAGS "") + default(PVS_STUDIO_TARGET "pvs") + default(PVS_STUDIO_LOG "PVS-Studio.log") + + set(PATHS) + + if (WIN32) + # The registry value is only read when you do some cache operation on it. + # https://stackoverflow.com/questions/1762201/reading-registry-values-with-cmake + GET_FILENAME_COMPONENT(ROOT "[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\ProgramVerificationSystems\\PVS-Studio;installDir]" ABSOLUTE CACHE) + + if(EXISTS "${ROOT}") + set(PATHS "${ROOT}") + else() + set(ROOT "PROGRAMFILES(X86)") + set(ROOT "$ENV{${ROOT}}/PVS-Studio") + string(REPLACE \\ / ROOT "${ROOT}") + + if (EXISTS "${ROOT}") + set(PATHS "${ROOT}") + else() + set(ROOT "PATH") + set(ROOT "$ENV{${ROOT}}") + set(PATHS "${ROOT}") + endif () + endif() + + + + default(PVS_STUDIO_BIN "CompilerCommandsAnalyzer.exe") + default(PVS_STUDIO_CONVERTER "HtmlGenerator.exe") + else () + default(PVS_STUDIO_BIN "pvs-studio-analyzer") + default(PVS_STUDIO_CONVERTER "plog-converter") + endif () + + find_program(PVS_STUDIO_BIN_PATH "${PVS_STUDIO_BIN}" ${PATHS}) + set(PVS_STUDIO_BIN "${PVS_STUDIO_BIN_PATH}") + + if (NOT EXISTS "${PVS_STUDIO_BIN}") + message(FATAL_ERROR "pvs-studio-analyzer is not found") + endif () + + find_program(PVS_STUDIO_CONVERTER_PATH "${PVS_STUDIO_CONVERTER}" ${PATHS}) + set(PVS_STUDIO_CONVERTER "${PVS_STUDIO_CONVERTER_PATH}") + + if (NOT EXISTS "${PVS_STUDIO_CONVERTER}") + message(FATAL_ERROR "plog-converter is not found") + endif () + + default(PVS_STUDIO_MODE "GA:1,2") + default(PVS_STUDIO_PREPROCESSOR "${DEFAULT_PREPROCESSOR}") + if (WIN32) + default(PVS_STUDIO_PLATFORM "x64") + else () + default(PVS_STUDIO_PLATFORM "linux64") + endif () + + string(REPLACE ";" "+" PVS_STUDIO_MODE "${PVS_STUDIO_MODE}") + + if ("${PVS_STUDIO_CONFIG}" STREQUAL "" AND NOT "${PVS_STUDIO_CFG_TEXT}" STREQUAL "") + set(PVS_STUDIO_CONFIG "${CMAKE_BINARY_DIR}/PVS-Studio.cfg") + + set(PVS_STUDIO_CONFIG_COMMAND "${CMAKE_COMMAND}" -E echo "${PVS_STUDIO_CFG_TEXT}" > "${PVS_STUDIO_CONFIG}") + + add_custom_command(OUTPUT "${PVS_STUDIO_CONFIG}" + COMMAND ${PVS_STUDIO_CONFIG_COMMAND} + WORKING_DIRECTORY "${BINARY_DIR}" + COMMENT "Generating PVS-Studio.cfg") + + list(APPEND PVS_STUDIO_DEPENDS "${PVS_STUDIO_CONFIG}") + endif () + if (NOT "${PVS_STUDIO_PREPROCESSOR}" MATCHES "^${PVS_STUDIO_SUPPORTED_PREPROCESSORS}$") + message(FATAL_ERROR "Preprocessor ${PVS_STUDIO_PREPROCESSOR} isn't supported. Available options: ${PVS_STUDIO_SUPPORTED_PREPROCESSORS}.") + endif () + + pvs_studio_append_standard_flag(PVS_STUDIO_CXX_FLAGS "${CMAKE_CXX_STANDARD}") + pvs_studio_set_directory_flags("${CMAKE_CURRENT_SOURCE_DIR}" PVS_STUDIO_CXX_FLAGS PVS_STUDIO_C_FLAGS) + + if (NOT "${PVS_STUDIO_LICENSE}" STREQUAL "") + list(APPEND PVS_STUDIO_ARGS --lic-file "${PVS_STUDIO_LICENSE}") + endif () + + if (NOT ${PVS_STUDIO_CONFIG} STREQUAL "") + list(APPEND PVS_STUDIO_ARGS --cfg "${PVS_STUDIO_CONFIG}") + endif () + + list(APPEND PVS_STUDIO_ARGS --platform "${PVS_STUDIO_PLATFORM}" + --preprocessor "${PVS_STUDIO_PREPROCESSOR}") + + if (NOT "${PVS_STUDIO_SUPPRESS_BASE}" STREQUAL "") + pvs_studio_join_path(PVS_STUDIO_SUPPRESS_BASE "${CMAKE_CURRENT_SOURCE_DIR}" "${PVS_STUDIO_SUPPRESS_BASE}") + list(APPEND PVS_STUDIO_ARGS --suppress-file "${PVS_STUDIO_SUPPRESS_BASE}") + endif () + + if (NOT "${CMAKE_CXX_COMPILER}" STREQUAL "") + list(APPEND PVS_STUDIO_ARGS --cxx "${CMAKE_CXX_COMPILER}") + endif () + + if (NOT "${CMAKE_C_COMPILER}" STREQUAL "") + list(APPEND PVS_STUDIO_ARGS --cc "${CMAKE_C_COMPILER}") + endif () + + if (PVS_STUDIO_KEEP_INTERMEDIATE_FILES) + list(APPEND PVS_STUDIO_ARGS --dump-files) + endif() + + string(REGEX REPLACE [123,:] "" ANALYZER_MODE ${PVS_STUDIO_MODE}) + if (NOT "$ANALYZER_MODE" STREQUAL "GA") + list (APPEND PVS_STUDIO_ARGS -a "${ANALYZER_MODE}") + endif () + + set(PVS_STUDIO_PLOGS "") + + set(PVS_STUDIO_RECURSIVE_TARGETS_NEW) + if (${PVS_STUDIO_RECURSIVE}) + foreach (TARGET IN LISTS PVS_STUDIO_ANALYZE) + list(APPEND PVS_STUDIO_RECURSIVE_TARGETS_NEW "${TARGET}") + pvs_studio_get_recursive_targets("${TARGET}") + endforeach () + endif () + + set(inc_path) + + foreach (TARGET ${PVS_STUDIO_ANALYZE}) + set(DIR "${CMAKE_CURRENT_SOURCE_DIR}") + string(FIND "${TARGET}" ":" DELIM) + if ("${DELIM}" GREATER "-1") + math(EXPR DELIMI "${DELIM}+1") + string(SUBSTRING "${TARGET}" "${DELIMI}" "-1" DIR) + string(SUBSTRING "${TARGET}" "0" "${DELIM}" TARGET) + pvs_studio_join_path(DIR "${CMAKE_CURRENT_SOURCE_DIR}" "${DIR}") + else () + get_target_property(TARGET_SOURCE_DIR "${TARGET}" SOURCE_DIR) + if (EXISTS "${TARGET_SOURCE_DIR}") + set(DIR "${TARGET_SOURCE_DIR}") + endif () + endif () + pvs_studio_analyze_target("${TARGET}" "${DIR}") + list(APPEND PVS_STUDIO_DEPENDS "${TARGET}") + + if ("${inc_path}" STREQUAL "") + set(inc_path "$") + else () + set(inc_path "${inc_path}$$") + endif () + endforeach () + + foreach (TARGET ${PVS_STUDIO_RECURSIVE_TARGETS_NEW}) + set(DIR "${CMAKE_CURRENT_SOURCE_DIR}") + get_target_property(TARGET_SOURCE_DIR "${TARGET}" SOURCE_DIR) + if (EXISTS "${TARGET_SOURCE_DIR}") + set(DIR "${TARGET_SOURCE_DIR}") + endif () + pvs_studio_analyze_target("${TARGET}" "${DIR}") + list(APPEND PVS_STUDIO_DEPENDS "${TARGET}") + endforeach () + + set(PVS_STUDIO_TARGET_CXX_FLAGS "") + set(PVS_STUDIO_TARGET_C_FLAGS "") + foreach (SOURCE ${PVS_STUDIO_SOURCES}) + pvs_studio_analyze_file("${SOURCE}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") + endforeach () + + if (PVS_STUDIO_COMPILE_COMMANDS) + set(COMPILE_COMMANDS_LOG "${PVS_STUDIO_LOG}.pvs.analyzer.raw") + if (NOT CMAKE_EXPORT_COMPILE_COMMANDS) + message(FATAL_ERROR "You should set CMAKE_EXPORT_COMPILE_COMMANDS to TRUE") + endif () + add_custom_command( + OUTPUT "${COMPILE_COMMANDS_LOG}" + COMMAND "${PVS_STUDIO_BIN}" analyze -i + --output-file "${COMPILE_COMMANDS_LOG}.always" + ${PVS_STUDIO_ARGS} + COMMENT "Analyzing with PVS-Studio" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + DEPENDS "${PVS_STUDIO_SUPPRESS_BASE}" "${PVS_STUDIO_DEPENDS}" + ) + list(APPEND PVS_STUDIO_PLOGS_LOGS "${COMPILE_COMMANDS_LOG}.always") + list(APPEND PVS_STUDIO_PLOGS_DEPENDENCIES "${COMPILE_COMMANDS_LOG}") + endif () + + pvs_studio_relative_path(LOG_RELATIVE "${CMAKE_BINARY_DIR}" "${PVS_STUDIO_LOG}") + if (PVS_STUDIO_PLOGS OR PVS_STUDIO_COMPILE_COMMANDS) + if (WIN32) + string(REPLACE / \\ PVS_STUDIO_PLOGS "${PVS_STUDIO_PLOGS}") + endif () + if (WIN32) + set(COMMANDS COMMAND type ${PVS_STUDIO_PLOGS} ${PVS_STUDIO_PLOGS_LOGS} > "${PVS_STUDIO_LOG}" 2>nul || cd .) + else () + set(COMMANDS COMMAND cat ${PVS_STUDIO_PLOGS} ${PVS_STUDIO_PLOGS_LOGS} > "${PVS_STUDIO_LOG}" 2>/dev/null || true) + endif () + set(COMMENT "Generating ${LOG_RELATIVE}") + if (NOT "${PVS_STUDIO_FORMAT}" STREQUAL "" OR PVS_STUDIO_OUTPUT) + if ("${PVS_STUDIO_FORMAT}" STREQUAL "") + set(PVS_STUDIO_FORMAT "errorfile") + endif () + set(converter_no_help "") + if (PVS_STUDIO_HIDE_HELP) + set(converter_no_help "--noHelpMessages") + endif() + list(APPEND COMMANDS + COMMAND "${CMAKE_COMMAND}" -E remove -f "${PVS_STUDIO_LOG}.pvs.raw" + COMMAND "${CMAKE_COMMAND}" -E rename "${PVS_STUDIO_LOG}" "${PVS_STUDIO_LOG}.pvs.raw" + COMMAND "${PVS_STUDIO_CONVERTER}" "${PVS_STUDIO_CONVERTER_ARGS}" ${converter_no_help} -t "${PVS_STUDIO_FORMAT}" "${PVS_STUDIO_LOG}.pvs.raw" -o "${PVS_STUDIO_LOG}" -a "${PVS_STUDIO_MODE}" + ) + if(NOT PVS_STUDIO_KEEP_COMBINED_PLOG) + list(APPEND COMMANDS COMMAND "${CMAKE_COMMAND}" -E remove -f "${PVS_STUDIO_LOG}.pvs.raw") + endif() + endif () + else () + set(COMMANDS COMMAND "${CMAKE_COMMAND}" -E touch "${PVS_STUDIO_LOG}") + set(COMMENT "Generating ${LOG_RELATIVE}: no sources found") + endif () + + if (WIN32) + string(REPLACE / \\ PVS_STUDIO_LOG "${PVS_STUDIO_LOG}") + endif () + + if (CMAKE_GENERATOR STREQUAL "Unix Makefiles") + get_filename_component(LOG_NAME ${LOG_RELATIVE} NAME) + set(LOG_TARGET "${PVS_STUDIO_TARGET}-${LOG_NAME}-log") + add_custom_target("${LOG_TARGET}" + BYPRODUCTS "${PVS_STUDIO_LOG}" + ${COMMANDS} + COMMENT "${COMMENT}" + DEPENDS ${PVS_STUDIO_PLOGS} ${PVS_STUDIO_PLOGS_DEPENDENCIES} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") + else() + set(LOG_TARGET "${PVS_STUDIO_LOG}") + add_custom_command(OUTPUT "${LOG_TARGET}" + ${COMMANDS} + COMMENT "${COMMENT}" + DEPENDS ${PVS_STUDIO_PLOGS} ${PVS_STUDIO_PLOGS_DEPENDENCIES} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") + endif() + + if (PVS_STUDIO_ALL) + set(ALL "ALL") + else () + set(ALL "") + endif () + + if (PVS_STUDIO_OUTPUT) + if (WIN32) + set(COMMANDS COMMAND type "${PVS_STUDIO_LOG}" 1>&2) + else () + set(COMMANDS COMMAND cat "${PVS_STUDIO_LOG}" 1>&2) + endif() + else () + set(COMMANDS "") + endif () + + set(props_file "${CMAKE_BINARY_DIR}/${PVS_STUDIO_TARGET}.user.props") + file(WRITE "${props_file}" [=[ + + + + + + + + true + + + +]=]) + + add_custom_target("${PVS_STUDIO_TARGET}" ${ALL} ${COMMANDS} + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + DEPENDS ${PVS_STUDIO_DEPENDS} "${LOG_TARGET}") + set_target_properties("${PVS_STUDIO_TARGET}" PROPERTIES VS_USER_PROPS "${props_file}") + + # A workaround to add implicit dependencies of source files from include directories + set_target_properties("${PVS_STUDIO_TARGET}" PROPERTIES INCLUDE_DIRECTORIES "${inc_path}") +endfunction () diff --git a/cmake/StandardSettings.cmake b/cmake/StandardSettings.cmake index 35b85c4a023..6f20d870f1c 100644 --- a/cmake/StandardSettings.cmake +++ b/cmake/StandardSettings.cmake @@ -1,12 +1,81 @@ # -# Static analyzers +# Default settings +# +set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS 1) +set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14" CACHE STRING "Minimum OS X deployment version" FORCE) + +# +# IDE Settings # -# Currently supporting: Clang-Tidy. +option(TW_IDE_CLION "Enable if your IDE is CLion" OFF) +option(TW_IDE_VSCODE "Enable if your IDE is VSCode" OFF) +# +# Static analyzers +# +# Currently supporting: Clang-Tidy, PVS-Studio. option(TW_ENABLE_CLANG_TIDY "Enable static analysis with Clang-Tidy." OFF) +option(TW_ENABLE_PVS_STUDIO "Enable static analysis with PVS-Studio." OFF) + +# +# Runtime analyzers +# +# Currently supporting: Clang ASAN. +option(TW_CLANG_ASAN "Enable ASAN dynamic address sanitizer" OFF) # # Specific platforms support # # Currently supporting: Wasm. option(TW_COMPILE_WASM "Target Wasm" OFF) + +# +# Coverage +# +option(TW_CODE_COVERAGE "Enable coverage reporting" OFF) + +# +# Compiler warnings options +# +option(TW_WARNINGS_AS_ERRORS "Compiler Options as Error" OFF) + +# +# Compilation Speed options +# +option(TW_ENABLE_CCACHE "Enable the usage of Ccache, in order to speed up rebuild times." ON) + +if (TW_ENABLE_CCACHE) + find_program(CCACHE_FOUND ccache) + if (CCACHE_FOUND) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) + message(STATUS "ccache activated") + endif () +endif () + +# +# Tests/Examples options +# +option(TW_UNIT_TESTS "Enable the unit tests of the project" ON) +option(TW_BUILD_EXAMPLES "Enable the examples builds of the project" ON) + +if (ANDROID OR IOS_PLATFORM OR TW_COMPILE_WASM) + set(TW_UNIT_TESTS OFF) + set(TW_BUILD_EXAMPLES OFF) +endif() + +if (TW_UNIT_TESTS) + message(STATUS "Native unit tests activated") +else() + message(STATUS "Native unit tests skipped") +endif() + +if (TW_BUILD_EXAMPLES) + message(STATUS "Native examples activated") +else() + message(STATUS "Native examples skipped") +endif() + + diff --git a/cmake/StaticAnalyzers.cmake b/cmake/StaticAnalyzers.cmake index 37e7c2ecd5f..a6e32b5b406 100644 --- a/cmake/StaticAnalyzers.cmake +++ b/cmake/StaticAnalyzers.cmake @@ -1,9 +1,33 @@ -if(TW_ENABLE_CLANG_TIDY) +if (TW_ENABLE_CLANG_TIDY) find_program(CLANGTIDY clang-tidy) - if(CLANGTIDY) + if (CLANGTIDY) set(CMAKE_CXX_CLANG_TIDY ${CLANGTIDY} -extra-arg=-Wno-unknown-warning-option) message("Clang-Tidy finished setting up.") - else() + else () message(SEND_ERROR "Clang-Tidy requested but executable not found.") - endif() -endif() + endif () +endif () + +if (TW_ENABLE_PVS_STUDIO) + macro(tw_add_pvs_studio_target target) + message(STATUS "PVS-Studio analyzer enabled - ${CMAKE_SOURCE_DIR}/tools/pvs-studio/config.cfg") + include(cmake/PVS-Studio.cmake) + if (TW_IDE_VSCODE) + pvs_studio_add_target(TARGET TrustWalletCore.analyze ALL + OUTPUT FORMAT sarif-vscode + ANALYZE ${target} + MODE GA:1,2 + LOG result.sarif + CONFIG ${CMAKE_SOURCE_DIR}/tools/pvs-studio/config.cfg + ) + else () + pvs_studio_add_target(TARGET TrustWalletCore.analyze ALL + OUTPUT FORMAT json + ANALYZE ${target} + MODE GA:1,2 + LOG result.json + CONFIG ${CMAKE_SOURCE_DIR}/tools/pvs-studio/config.cfg + ) + endif () + endmacro() +endif () diff --git a/tools/pvs-studio-analyze b/tools/pvs-studio-analyze new file mode 100755 index 00000000000..c219fbefc52 --- /dev/null +++ b/tools/pvs-studio-analyze @@ -0,0 +1,25 @@ +#!/bin/bash +# +# This script generate a build folder with pvs studio enabled and run an analyze +# You need to have ninja, pvs-studio-analyzer and llvm installed +# If you are on macOS set CC/CXX to clang/clang++ from brew + +base_dir=$( + cd $(dirname $0) + pwd +) +src_dir=${base_dir}/.. + +mkdir -p "${src_dir}"/build_pvs_studio +cd "${src_dir}"/build_pvs_studio + +if [[ "$OSTYPE" == "linux-gnu"* ]]; then + cmake -GNinja -DTW_ENABLE_PVS_STUDIO=ON -DTW_IDE_VSCODE=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ../ +elif [[ "$OSTYPE" == "darwin"* ]]; then + llvm_bin="$(brew --prefix)/opt/llvm/bin" + cmake -GNinja -DTW_ENABLE_PVS_STUDIO=ON -DTW_IDE_VSCODE=ON -DCMAKE_C_COMPILER=$llvm_bin/clang -DCMAKE_CXX_COMPILER=$llvm_bin/clang++ ../ +fi + +ninja TrustWalletCore.analyze + +cd - diff --git a/tools/pvs-studio/config.cfg b/tools/pvs-studio/config.cfg new file mode 100644 index 00000000000..4823855e789 --- /dev/null +++ b/tools/pvs-studio/config.cfg @@ -0,0 +1,11 @@ +exclude-path=*/boost/* +exclude-path=*/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform* +exclude-path=*/src/proto* +exclude-path=*/src/Cosmos/Protobuf* +exclude-path=*/build/local/include* +exclude-path=*/build/local/* +exclude-path=*/build/local/src/google/protobuf/* +exclude-path=*/opt/homebrew/opt/llvm* +exclude-path=*/src/Zilliqa/Protobuf* +exclude-path=*/src/Tron/Protobuf* +exclude-path=*/opt/homebrew/Cellar/llvm* diff --git a/trezor-crypto/crypto/tests/CMakeLists.txt b/trezor-crypto/crypto/tests/CMakeLists.txt index 16acd1d0f0e..f2bf56bee5a 100644 --- a/trezor-crypto/crypto/tests/CMakeLists.txt +++ b/trezor-crypto/crypto/tests/CMakeLists.txt @@ -11,6 +11,7 @@ find_library(check PATH ${CMAKE_SOURCE_DIR}/build/local/lib/pkgconfig NO_DEFAULT # Test executable add_executable(TrezorCryptoTests test_check.c) target_link_libraries(TrezorCryptoTests TrezorCrypto check) -target_include_directories(TrezorCryptoTests PRIVATE ${CMAKE_SOURCE_DIR}/src) +target_link_directories(TrezorCryptoTests PRIVATE ${PREFIX}/lib) +target_include_directories(TrezorCryptoTests PRIVATE ${CMAKE_SOURCE_DIR}/src ${PREFIX}/include) add_test(NAME test_check COMMAND TrezorCryptoTests) diff --git a/walletconsole/CMakeLists.txt b/walletconsole/CMakeLists.txt index 8177f65d24f..f72134a29b9 100644 --- a/walletconsole/CMakeLists.txt +++ b/walletconsole/CMakeLists.txt @@ -9,12 +9,5 @@ file(GLOB walletconsole_sources *.cpp) add_executable(walletconsole ${walletconsole_sources}) target_link_libraries(walletconsole walletconsolelib TrezorCrypto TrustWalletCore protobuf Boost::boost) target_include_directories(walletconsole PRIVATE ${CMAKE_SOURCE_DIR}/walletconsole/lib ${CMAKE_SOURCE_DIR}/src) -target_compile_options(walletconsole PRIVATE "-Wall") - -set_target_properties(walletconsole - PROPERTIES - CXX_STANDARD 20 - CXX_STANDARD_REQUIRED ON -) INSTALL(TARGETS walletconsole DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/walletconsole/lib/CMakeLists.txt b/walletconsole/lib/CMakeLists.txt index 875ca6fb4c0..c3ee4a7f6d2 100644 --- a/walletconsole/lib/CMakeLists.txt +++ b/walletconsole/lib/CMakeLists.txt @@ -10,10 +10,3 @@ add_library(walletconsolelib ${walletconsolelib_sources}) #target_link_libraries(tests gtest_main TrezorCrypto TrustWalletCore protobuf Boost::boost) target_link_libraries(walletconsolelib TrezorCrypto TrustWalletCore protobuf Boost::boost) target_include_directories(walletconsolelib PRIVATE ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/src) -target_compile_options(walletconsolelib PRIVATE "-Wall") - -set_target_properties(walletconsolelib - PROPERTIES - CXX_STANDARD 20 - CXX_STANDARD_REQUIRED ON -) From 423f0e34725f69c0a9d535e1a32534c99682edea Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 21 Jul 2022 15:15:30 +0800 Subject: [PATCH 030/497] [Breaking Change] Remove public key from the ed25519 signing API (#2381) * Merge ed25519 public key fix from trezor * Fix trezor tests * Fix cardano tests * format HDWallet.cpp * Don't use static inside cardano.c (fix android tests) * Fix VerifyEd25519Extended test * implement cardano verify signature * Move PrivateKeyType out of HDWallet * Rename non standard ed25519 extended naming to cardano specific * Add Zilliqa prefix to schnorr sign/verify, ready to import secp256k1-zkp --- .../blockchains/cardano/TestCardanoAddress.kt | 2 +- include/TrustWalletCore/TWCurve.h | 2 +- include/TrustWalletCore/TWPrivateKey.h | 8 +- include/TrustWalletCore/TWPublicKey.h | 3 +- include/TrustWalletCore/TWPublicKeyType.h | 2 +- registry.json | 4 +- src/Cardano/AddressV2.cpp | 2 +- src/Cardano/AddressV3.cpp | 2 +- src/Cardano/Signer.cpp | 6 +- src/HDWallet.cpp | 125 +- src/HDWallet.h | 8 +- src/PrivateKey.cpp | 110 +- src/PrivateKey.h | 17 +- src/PublicKey.cpp | 22 +- src/PublicKey.h | 9 +- src/Zilliqa/Signer.cpp | 2 +- src/algorithm/to_array.h | 4 +- src/interface/TWPrivateKey.cpp | 8 +- src/interface/TWPublicKey.cpp | 4 +- swift/Tests/Blockchains/CardanoTests.swift | 2 +- swift/Tests/PrivateKeyTests.swift | 4 +- swift/common-xcframework.yml | 3 +- swift/project.yml | 3 +- tests/Cardano/AddressTests.cpp | 62 +- tests/Cardano/SigningTests.cpp | 6 +- tests/Cardano/TWCardanoAddressTests.cpp | 4 +- tests/Oasis/AddressTests.cpp | 4 +- tests/PrivateKeyTests.cpp | 18 +- tests/PublicKeyTests.cpp | 24 +- tests/Zilliqa/SignatureTests.cpp | 4 +- tests/Zilliqa/SignerTests.cpp | 2 +- tests/interface/TWCoinTypeTests.cpp | 2 +- trezor-crypto/CMakeLists.txt | 5 +- trezor-crypto/crypto/bip32.c | 244 +-- trezor-crypto/crypto/bip39.c | 9 +- trezor-crypto/crypto/blake256.c | 3 +- trezor-crypto/crypto/cardano.c | 307 ++++ trezor-crypto/crypto/chacha20poly1305/LICENSE | 21 + .../crypto/chacha20poly1305/chacha_merged.c | 7 + trezor-crypto/crypto/chacha_drbg.c | 90 +- trezor-crypto/crypto/curves.c | 7 +- trezor-crypto/crypto/ecdsa.c | 149 +- trezor-crypto/crypto/ed25519-donna/ed25519.c | 124 +- trezor-crypto/crypto/nem.c | 3 +- trezor-crypto/crypto/rfc6979.c | 22 +- trezor-crypto/crypto/slip39.c | 151 ++ trezor-crypto/crypto/tests/test_check.c | 1480 +++++++++-------- .../crypto/tests/test_check_cardano.h | 216 ++- .../crypto/tests/test_check_zilliqa.h | 214 +++ trezor-crypto/crypto/tests/test_openssl.c | 11 +- trezor-crypto/crypto/tests/test_speed.c | 14 +- trezor-crypto/crypto/{schnorr.c => zilliqa.c} | 62 +- trezor-crypto/include/TrezorCrypto/bip32.h | 17 +- trezor-crypto/include/TrezorCrypto/bip39.h | 33 +- trezor-crypto/include/TrezorCrypto/cardano.h | 63 + .../chacha20poly1305/ecrypt-sync.h | 11 +- .../include/TrezorCrypto/chacha_drbg.h | 31 +- trezor-crypto/include/TrezorCrypto/curves.h | 6 +- trezor-crypto/include/TrezorCrypto/ecdsa.h | 20 +- .../ed25519-donna/ed25519-blake2b.h | 2 +- .../ed25519-donna/ed25519-keccak.h | 2 +- .../TrezorCrypto/ed25519-donna/ed25519-sha3.h | 2 +- trezor-crypto/include/TrezorCrypto/ed25519.h | 10 +- trezor-crypto/include/TrezorCrypto/rfc6979.h | 3 +- trezor-crypto/include/TrezorCrypto/slip39.h | 47 + .../include/TrezorCrypto/slip39_wordlist.h | 1246 ++++++++++++++ .../TrezorCrypto/{schnorr.h => zilliqa.h} | 13 +- 67 files changed, 3680 insertions(+), 1443 deletions(-) create mode 100644 trezor-crypto/crypto/cardano.c create mode 100644 trezor-crypto/crypto/chacha20poly1305/LICENSE create mode 100644 trezor-crypto/crypto/slip39.c create mode 100644 trezor-crypto/crypto/tests/test_check_zilliqa.h rename trezor-crypto/crypto/{schnorr.c => zilliqa.c} (73%) create mode 100644 trezor-crypto/include/TrezorCrypto/cardano.h create mode 100644 trezor-crypto/include/TrezorCrypto/slip39.h create mode 100644 trezor-crypto/include/TrezorCrypto/slip39_wordlist.h rename trezor-crypto/include/TrezorCrypto/{schnorr.h => zilliqa.h} (77%) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoAddress.kt index 8a6a65cafbd..6ac0f1c4d63 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoAddress.kt @@ -21,7 +21,7 @@ class TestCardanoAddress { @Test fun testAddress() { val key = PrivateKey("b0884d248cb301edd1b34cf626ba6d880bb3ae8fd91b4696446999dc4f0b5744309941d56938e943980d11643c535e046653ca6f498c014b88f2ad9fd6e71effbf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4639aadd8b6499ae39b78018b79255fbd8f585cbda9cbb9e907a72af86afb7a05d41a57c2dec9a6a19d6bf3b1fa784f334f3a0048d25ccb7b78a7b44066f9ba7bed7f28be986cbe06819165f2ee41b403678a098961013cf4a2f3e9ea61fb6c1a".toHexByteArray()) - val pubkey = key.publicKeyEd25519Extended + val pubkey = key.publicKeyEd25519Cardano val address = AnyAddress(pubkey, CoinType.CARDANO) val expected = AnyAddress("addr1qx4z6twzknkkux0hhp0kq6hvdfutczp56g56y5em8r8mgvxalp7nkkk25vuspleke2zltaetmlwrfxv7t049cq9jmwjswmfw6t", CoinType.CARDANO) diff --git a/include/TrustWalletCore/TWCurve.h b/include/TrustWalletCore/TWCurve.h index 6ce6e645539..79d2891aa40 100644 --- a/include/TrustWalletCore/TWCurve.h +++ b/include/TrustWalletCore/TWCurve.h @@ -18,7 +18,7 @@ enum TWCurve { TWCurveED25519Blake2bNano /* "ed25519-blake2b-nano" */, TWCurveCurve25519 /* "curve25519" */, TWCurveNIST256p1 /* "nist256p1" */, - TWCurveED25519Extended /* "ed25519-cardano-seed" */, + TWCurveED25519ExtendedCardano /* "ed25519-cardano-seed" */, TWCurveNone }; diff --git a/include/TrustWalletCore/TWPrivateKey.h b/include/TrustWalletCore/TWPrivateKey.h index 8400050e654..ea77304de57 100644 --- a/include/TrustWalletCore/TWPrivateKey.h +++ b/include/TrustWalletCore/TWPrivateKey.h @@ -52,9 +52,9 @@ struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519(struct TWPrivateKey TW_EXPORT_METHOD struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519Blake2b(struct TWPrivateKey *_Nonnull pk); -/// Returns the public key associated with this private key. +/// Returns the Cardano style public key associated with this private key. TW_EXPORT_METHOD -struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519Extended(struct TWPrivateKey *_Nonnull pk); +struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519Cardano(struct TWPrivateKey *_Nonnull pk); /// Returns the public key associated with this private key. TW_EXPORT_METHOD @@ -73,8 +73,8 @@ TWData *_Nullable TWPrivateKeySign(struct TWPrivateKey *_Nonnull pk, TWData *_No TW_EXPORT_METHOD TWData *_Nullable TWPrivateKeySignAsDER(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull digest, enum TWCurve curve); -/// Signs a digest using ECDSA and given curve, returns schnoor signature. +/// Signs a digest using ECDSA and Zilliqa schnorr signature scheme. TW_EXPORT_METHOD -TWData *_Nullable TWPrivateKeySignSchnorr(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull message, enum TWCurve curve); +TWData *_Nullable TWPrivateKeySignZilliqaSchnorr(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull message); TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWPublicKey.h b/include/TrustWalletCore/TWPublicKey.h index 313dee28fb0..479115ce10b 100644 --- a/include/TrustWalletCore/TWPublicKey.h +++ b/include/TrustWalletCore/TWPublicKey.h @@ -46,8 +46,9 @@ bool TWPublicKeyVerify(struct TWPublicKey *_Nonnull pk, TWData *_Nonnull signatu TW_EXPORT_METHOD bool TWPublicKeyVerifyAsDER(struct TWPublicKey *_Nonnull pk, TWData *_Nonnull signature, TWData *_Nonnull message); +/// Verify a Zilliqa schnorr signature with a signature and message. TW_EXPORT_METHOD -bool TWPublicKeyVerifySchnorr(struct TWPublicKey *_Nonnull pk, TWData *_Nonnull signature, TWData *_Nonnull message); +bool TWPublicKeyVerifyZilliqaSchnorr(struct TWPublicKey *_Nonnull pk, TWData *_Nonnull signature, TWData *_Nonnull message); TW_EXPORT_PROPERTY enum TWPublicKeyType TWPublicKeyKeyType(struct TWPublicKey *_Nonnull publicKey); diff --git a/include/TrustWalletCore/TWPublicKeyType.h b/include/TrustWalletCore/TWPublicKeyType.h index 29d2b181064..e9d0e53b347 100644 --- a/include/TrustWalletCore/TWPublicKeyType.h +++ b/include/TrustWalletCore/TWPublicKeyType.h @@ -20,7 +20,7 @@ enum TWPublicKeyType { TWPublicKeyTypeED25519 = 4, TWPublicKeyTypeED25519Blake2b = 5, TWPublicKeyTypeCURVE25519 = 6, - TWPublicKeyTypeED25519Extended = 7, // used by Cardano + TWPublicKeyTypeED25519Cardano = 7, }; TW_EXTERN_C_END diff --git a/registry.json b/registry.json index a82e24d0dc6..152395ffd4a 100644 --- a/registry.json +++ b/registry.json @@ -1569,8 +1569,8 @@ "path": "m/1852'/1815'/0'/0/0" } ], - "curve": "ed25519Extended", - "publicKeyType": "ed25519Extended", + "curve": "ed25519ExtendedCardano", + "publicKeyType": "ed25519Cardano", "hrp": "addr", "explorer": { "url": "https://cardanoscan.io", diff --git a/src/Cardano/AddressV2.cpp b/src/Cardano/AddressV2.cpp index 2efba5e56f8..a6dba3d96a7 100644 --- a/src/Cardano/AddressV2.cpp +++ b/src/Cardano/AddressV2.cpp @@ -71,7 +71,7 @@ AddressV2::AddressV2(const std::string& string) { AddressV2::AddressV2(const PublicKey& publicKey) { // input is extended pubkey, 64-byte - if (publicKey.type != TWPublicKeyTypeED25519Extended || publicKey.bytes.size() != PublicKey::ed25519DoubleExtendedSize) { + if (publicKey.type != TWPublicKeyTypeED25519Cardano || publicKey.bytes.size() != PublicKey::cardanoKeySize) { throw std::invalid_argument("Invalid public key type"); } type = 0; // public key diff --git a/src/Cardano/AddressV3.cpp b/src/Cardano/AddressV3.cpp index 20f297bb33f..50ebb4ae7d7 100644 --- a/src/Cardano/AddressV3.cpp +++ b/src/Cardano/AddressV3.cpp @@ -110,7 +110,7 @@ AddressV3::AddressV3(const std::string& addr) { AddressV3::AddressV3(const PublicKey& publicKey) { // input is double extended pubkey - if (publicKey.type != TWPublicKeyTypeED25519Extended || publicKey.bytes.size() != PublicKey::ed25519DoubleExtendedSize) { + if (publicKey.type != TWPublicKeyTypeED25519Cardano || publicKey.bytes.size() != PublicKey::cardanoKeySize) { throw std::invalid_argument("Invalid public key type"); } kind = Kind_Base; diff --git a/src/Cardano/Signer.cpp b/src/Cardano/Signer.cpp index 3cdb0ebba88..bd89f279dd4 100644 --- a/src/Cardano/Signer.cpp +++ b/src/Cardano/Signer.cpp @@ -75,7 +75,7 @@ Common::Proto::SigningError Signer::assembleSignatures(vector>& return Common::Proto::Error_invalid_private_key; } const auto privateKey = PrivateKey(privateKeyData); - const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Extended); + const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); const auto address = AddressV3(publicKey); privateKeys[address.string()] = privateKeyData; } @@ -106,8 +106,8 @@ Common::Proto::SigningError Signer::assembleSignatures(vector>& } } const auto privateKey = PrivateKey(privateKeyData); - const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Extended); - const auto signature = privateKey.sign(txId, TWCurveED25519Extended); + const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); + const auto signature = privateKey.sign(txId, TWCurveED25519ExtendedCardano); // public key (first 32 bytes) and signature (64 bytes) signatures.emplace_back(subData(publicKey.bytes, 0, 32), signature); } diff --git a/src/HDWallet.cpp b/src/HDWallet.cpp index be42f46f6e9..11e8e7c0848 100644 --- a/src/HDWallet.cpp +++ b/src/HDWallet.cpp @@ -8,16 +8,19 @@ #include "Base58.h" #include "BinaryCoding.h" -#include "Bitcoin/SegwitAddress.h" #include "Bitcoin/CashAddress.h" +#include "Bitcoin/SegwitAddress.h" #include "Coin.h" #include "Mnemonic.h" #include #include +#include + #include #include +#include #include #include @@ -28,9 +31,9 @@ using namespace TW; namespace { -uint32_t fingerprint(HDNode *node, Hash::Hasher hasher); -std::string serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, bool use_public, Hash::Hasher hasher); -bool deserialize(const std::string& extended, TWCurve curve, Hash::Hasher hasher, HDNode *node); +uint32_t fingerprint(HDNode* node, Hash::Hasher hasher); +std::string serialize(const HDNode* node, uint32_t fingerprint, uint32_t version, bool use_public, Hash::Hasher hasher); +bool deserialize(const std::string& extended, TWCurve curve, Hash::Hasher hasher, HDNode* node); HDNode getNode(const HDWallet& wallet, TWCurve curve, const DerivationPath& derivationPath); HDNode getMasterNode(const HDWallet& wallet, TWCurve curve); @@ -120,34 +123,35 @@ DerivationPath HDWallet::cardanoStakingDerivationPath(const DerivationPath& path PrivateKey HDWallet::getKey(TWCoinType coin, const DerivationPath& derivationPath) const { const auto curve = TWCoinTypeCurve(coin); const auto privateKeyType = getPrivateKeyType(curve); - const auto node = getNode(*this, curve, derivationPath); + auto node = getNode(*this, curve, derivationPath); switch (privateKeyType) { - case PrivateKeyTypeDoubleExtended: // special handling for Cardano - { - if (derivationPath.indices.size() < 4 || derivationPath.indices[3].value > 1) { - // invalid derivation path - return PrivateKey(Data(192)); - } - const DerivationPath stakingPath = cardanoStakingDerivationPath(derivationPath); - - auto pkData = Data(node.private_key, node.private_key + PrivateKey::size); - auto extData = Data(node.private_key_extension, node.private_key_extension + PrivateKey::size); - auto chainCode = Data(node.chain_code, node.chain_code + PrivateKey::size); - - // repeat with staking path - const auto node2 = getNode(*this, curve, stakingPath); - auto pkData2 = Data(node2.private_key, node2.private_key + PrivateKey::size); - auto extData2 = Data(node2.private_key_extension, node2.private_key_extension + PrivateKey::size); - auto chainCode2 = Data(node2.chain_code, node2.chain_code + PrivateKey::size); - - return PrivateKey(pkData, extData, chainCode, pkData2, extData2, chainCode2); - } + case PrivateKeyTypeCardano: { + if (derivationPath.indices.size() < 4 || derivationPath.indices[3].value > 1) { + // invalid derivation path + return PrivateKey(Data(PrivateKey::cardanoKeySize)); + } + const DerivationPath stakingPath = cardanoStakingDerivationPath(derivationPath); - case PrivateKeyTypeDefault32: - default: - // default path - auto data = Data(node.private_key, node.private_key + PrivateKey::size); - return PrivateKey(data); + auto pkData = Data(node.private_key, node.private_key + PrivateKey::size); + auto extData = Data(node.private_key_extension, node.private_key_extension + PrivateKey::size); + auto chainCode = Data(node.chain_code, node.chain_code + PrivateKey::size); + + // repeat with staking path + const auto node2 = getNode(*this, curve, stakingPath); + auto pkData2 = Data(node2.private_key, node2.private_key + PrivateKey::size); + auto extData2 = Data(node2.private_key_extension, node2.private_key_extension + PrivateKey::size); + auto chainCode2 = Data(node2.chain_code, node2.chain_code + PrivateKey::size); + + memset(&node, 0, sizeof(HDNode)); + return PrivateKey(pkData, extData, chainCode, pkData2, extData2, chainCode2); + } + + case PrivateKeyTypeDefault32: + default: + // default path + auto data = Data(node.private_key, node.private_key + PrivateKey::size); + memset(&node, 0, sizeof(HDNode)); + return PrivateKey(data); } } @@ -170,7 +174,7 @@ std::string HDWallet::getExtendedPrivateKeyAccount(TWPurpose purpose, TWCoinType if (version == TWHDVersionNone) { return ""; } - + const auto curve = TWCoinTypeCurve(coin); const auto path = TW::derivationPath(coin, derivation); auto derivationPath = DerivationPath({DerivationPathIndex(purpose, true), DerivationPathIndex(path.coin(), true)}); @@ -184,7 +188,7 @@ std::string HDWallet::getExtendedPublicKeyAccount(TWPurpose purpose, TWCoinType if (version == TWHDVersionNone) { return ""; } - + const auto curve = TWCoinTypeCurve(coin); const auto path = TW::derivationPath(coin, derivation); auto derivationPath = DerivationPath({DerivationPathIndex(purpose, true), DerivationPathIndex(path.coin(), true)}); @@ -211,7 +215,7 @@ std::optional HDWallet::getPublicKeyFromExtended(const std::string& e hdnode_fill_public_key(&node); // These public key type are not applicable. Handled above, as node.curve->params is null - assert(curve != TWCurveED25519 && curve != TWCurveED25519Blake2bNano && curve != TWCurveED25519Extended && curve != TWCurveCurve25519); + assert(curve != TWCurveED25519 && curve != TWCurveED25519Blake2bNano && curve != TWCurveED25519ExtendedCardano && curve != TWCurveCurve25519); TWPublicKeyType keyType = TW::publicKeyType(coin); if (curve == TWCurveSECP256k1) { auto pubkey = PublicKey(Data(node.public_key, node.public_key + 33), TWPublicKeyTypeSECP256k1); @@ -245,26 +249,24 @@ std::optional HDWallet::getPrivateKeyFromExtended(const std::string& return PrivateKey(Data(node.private_key, node.private_key + 32)); } -HDWallet::PrivateKeyType HDWallet::getPrivateKeyType(TWCurve curve) { +PrivateKeyType HDWallet::getPrivateKeyType(TWCurve curve) { switch (curve) { - case TWCurve::TWCurveED25519Extended: - // used by Cardano - return PrivateKeyTypeDoubleExtended; + case TWCurve::TWCurveED25519ExtendedCardano: + return PrivateKeyTypeCardano; default: - // default return PrivateKeyTypeDefault32; } } namespace { -uint32_t fingerprint(HDNode *node, Hash::Hasher hasher) { +uint32_t fingerprint(HDNode* node, Hash::Hasher hasher) { hdnode_fill_public_key(node); auto digest = Hash::hash(hasher, node->public_key, 33); - return ((uint32_t) digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3]; + return ((uint32_t)digest[0] << 24) + (digest[1] << 16) + (digest[2] << 8) + digest[3]; } -std::string serialize(const HDNode *node, uint32_t fingerprint, uint32_t version, bool use_public, Hash::Hasher hasher) { +std::string serialize(const HDNode* node, uint32_t fingerprint, uint32_t version, bool use_public, Hash::Hasher hasher) { Data node_data; node_data.reserve(78); @@ -319,13 +321,13 @@ HDNode getNode(const HDWallet& wallet, TWCurve curve, const DerivationPath& deri auto node = getMasterNode(wallet, curve); for (auto& index : derivationPath.indices) { switch (privateKeyType) { - case HDWallet::PrivateKeyTypeDoubleExtended: // used by Cardano, special handling - hdnode_private_ckd_cardano(&node, index.derivationIndex()); - break; - case HDWallet::PrivateKeyTypeDefault32: - default: - hdnode_private_ckd(&node, index.derivationIndex()); - break; + case PrivateKeyTypeCardano: + hdnode_private_ckd_cardano(&node, index.derivationIndex()); + break; + case PrivateKeyTypeDefault32: + default: + hdnode_private_ckd(&node, index.derivationIndex()); + break; } } return node; @@ -333,17 +335,22 @@ HDNode getNode(const HDWallet& wallet, TWCurve curve, const DerivationPath& deri HDNode getMasterNode(const HDWallet& wallet, TWCurve curve) { const auto privateKeyType = HDWallet::getPrivateKeyType(curve); - auto node = HDNode(); + HDNode node; switch (privateKeyType) { - case HDWallet::PrivateKeyTypeDoubleExtended: // used by Cardano - // special handling for extended, use entropy (not seed) - hdnode_from_entropy_cardano_icarus((const uint8_t*)"", 0, wallet.getEntropy().data(), (int)wallet.getEntropy().size(), &node); - break; - - case HDWallet::PrivateKeyTypeDefault32: - default: - hdnode_from_seed(wallet.getSeed().data(), HDWallet::seedSize, curveName(curve), &node); - break; + case PrivateKeyTypeCardano: { + // Derives the root Cardano HDNode from a passphrase and the entropy encoded in + // a BIP-0039 mnemonic using the Icarus derivation (V2) scheme + const auto entropy = wallet.getEntropy(); + uint8_t secret[CARDANO_SECRET_LENGTH]; + secret_from_entropy_cardano_icarus((const uint8_t*)"", 0, entropy.data(), int(entropy.size()), secret, nullptr); + hdnode_from_secret_cardano(secret, &node); + memzero(secret, CARDANO_SECRET_LENGTH); + break; + } + case PrivateKeyTypeDefault32: + default: + hdnode_from_seed(wallet.getSeed().data(), HDWallet::seedSize, curveName(curve), &node); + break; } return node; } @@ -356,7 +363,7 @@ const char* curveName(TWCurve curve) { return ED25519_NAME; case TWCurveED25519Blake2bNano: return ED25519_BLAKE2B_NANO_NAME; - case TWCurveED25519Extended: + case TWCurveED25519ExtendedCardano: return ED25519_CARDANO_NAME; case TWCurveNIST256p1: return NIST256P1_NAME; diff --git a/src/HDWallet.h b/src/HDWallet.h index edeba904e99..549ee6e9ebd 100644 --- a/src/HDWallet.h +++ b/src/HDWallet.h @@ -123,19 +123,13 @@ class HDWallet { static std::optional getPrivateKeyFromExtended(const std::string& extended, TWCoinType coin, const DerivationPath& path); public: - // Private key type (later could be moved out of HDWallet) - enum PrivateKeyType { - PrivateKeyTypeDefault32 = 0, // 32-byte private key - PrivateKeyTypeDoubleExtended = 1, // used by Cardano - }; - // obtain privateKeyType used by the coin/curve static PrivateKeyType getPrivateKeyType(TWCurve curve); private: void updateSeedAndEntropy(bool check = true); - // For Cardano, derive 2nd, staking derivation path from the primary one + // For Cardano, derive 2nd staking derivation path from the primary one static DerivationPath cardanoStakingDerivationPath(const DerivationPath& path); }; diff --git a/src/PrivateKey.cpp b/src/PrivateKey.cpp index c7b71efa542..7a49cdfa7e4 100644 --- a/src/PrivateKey.cpp +++ b/src/PrivateKey.cpp @@ -15,18 +15,17 @@ #include #include #include -#include #include #include +#include #include using namespace TW; - bool PrivateKey::isValid(const Data& data) { // Check length - if (data.size() != size && data.size() != doubleExtendedSize) { + if (data.size() != size && data.size() != cardanoKeySize) { return false; } @@ -40,17 +39,15 @@ bool PrivateKey::isValid(const Data& data) { return false; } -bool PrivateKey::isValid(const Data& data, TWCurve curve) -{ +bool PrivateKey::isValid(const Data& data, TWCurve curve) { // check size bool valid = isValid(data); if (!valid) { return false; } - const ecdsa_curve *ec_curve = nullptr; - switch (curve) - { + const ecdsa_curve* ec_curve = nullptr; + switch (curve) { case TWCurveSECP256k1: ec_curve = &secp256k1; break; @@ -59,7 +56,7 @@ bool PrivateKey::isValid(const Data& data, TWCurve curve) break; case TWCurveED25519: case TWCurveED25519Blake2bNano: - case TWCurveED25519Extended: + case TWCurveED25519ExtendedCardano: case TWCurveCurve25519: case TWCurveNone: default: @@ -127,25 +124,24 @@ PublicKey PrivateKey::getPublicKey(TWPublicKeyType type) const { result.resize(PublicKey::ed25519Size); ed25519_publickey_blake2b(key().data(), result.data()); break; - case TWPublicKeyTypeED25519Extended: - { - // must be double extended key - if (bytes.size() != doubleExtendedSize) { - throw std::invalid_argument("Invalid extended key"); - } - Data tempPub(64); - ed25519_publickey_ext(key().data(), extension().data(), tempPub.data()); - result = Data(); - append(result, subData(tempPub, 0, 32)); - // copy chainCode - append(result, chainCode()); - - // second key - ed25519_publickey_ext(secondKey().data(), secondExtension().data(), tempPub.data()); - append(result, subData(tempPub, 0, 32)); - append(result, secondChainCode()); + case TWPublicKeyTypeED25519Cardano: { + // must be double extended key + if (bytes.size() != cardanoKeySize) { + throw std::invalid_argument("Invalid extended key"); } - break; + Data pubKey(PublicKey::ed25519Size); + + // first key + ed25519_publickey_ext(key().data(), pubKey.data()); + append(result, pubKey); + // copy chainCode + append(result, chainCode()); + + // second key + ed25519_publickey_ext(secondKey().data(), pubKey.data()); + append(result, pubKey); + append(result, secondChainCode()); + } break; case TWPublicKeyTypeCURVE25519: result.resize(PublicKey::ed25519Size); @@ -174,7 +170,7 @@ Data PrivateKey::getSharedKey(const PublicKey& pubKey, TWCurve curve) const { return {}; } -int ecdsa_sign_digest_checked(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, size_t digest_size, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { +int ecdsa_sign_digest_checked(const ecdsa_curve* curve, const uint8_t* priv_key, const uint8_t* digest, size_t digest_size, uint8_t* sig, uint8_t* pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])) { if (digest_size < 32) { return -1; } @@ -188,33 +184,27 @@ Data PrivateKey::sign(const Data& digest, TWCurve curve) const { switch (curve) { case TWCurveSECP256k1: { result.resize(65); - success = ecdsa_sign_digest_checked(&secp256k1, key().data(), digest.data(), digest.size(), result.data(), - result.data() + 64, nullptr) == 0; + success = ecdsa_sign_digest_checked(&secp256k1, key().data(), digest.data(), digest.size(), result.data(), result.data() + 64, nullptr) == 0; } break; case TWCurveED25519: { result.resize(64); - const auto publicKey = getPublicKey(TWPublicKeyTypeED25519); - ed25519_sign(digest.data(), digest.size(), key().data(), publicKey.bytes.data(), result.data()); + ed25519_sign(digest.data(), digest.size(), key().data(), result.data()); success = true; } break; case TWCurveED25519Blake2bNano: { result.resize(64); - const auto publicKey = getPublicKey(TWPublicKeyTypeED25519Blake2b); - ed25519_sign_blake2b(digest.data(), digest.size(), key().data(), - publicKey.bytes.data(), result.data()); + ed25519_sign_blake2b(digest.data(), digest.size(), key().data(), result.data()); success = true; } break; - case TWCurveED25519Extended: { + case TWCurveED25519ExtendedCardano: { result.resize(64); - const auto publicKey = getPublicKey(TWPublicKeyTypeED25519Extended); - ed25519_sign_ext(digest.data(), digest.size(), key().data(), extension().data(), publicKey.bytes.data(), result.data()); + ed25519_sign_ext(digest.data(), digest.size(), key().data(), extension().data(), result.data()); success = true; } break; case TWCurveCurve25519: { result.resize(64); const auto publicKey = getPublicKey(TWPublicKeyTypeED25519); - ed25519_sign(digest.data(), digest.size(), key().data(), publicKey.bytes.data(), - result.data()); + ed25519_sign(digest.data(), digest.size(), key().data(), result.data()); const auto sign_bit = publicKey.bytes[31] & 0x80; result[63] = result[63] & 127; result[63] |= sign_bit; @@ -222,11 +212,10 @@ Data PrivateKey::sign(const Data& digest, TWCurve curve) const { } break; case TWCurveNIST256p1: { result.resize(65); - success = ecdsa_sign_digest_checked(&nist256p1, key().data(), digest.data(), digest.size(), result.data(), - result.data() + 64, nullptr) == 0; + success = ecdsa_sign_digest_checked(&nist256p1, key().data(), digest.data(), digest.size(), result.data(), result.data() + 64, nullptr) == 0; } break; case TWCurveNone: - default: + default: break; } @@ -236,24 +225,22 @@ Data PrivateKey::sign(const Data& digest, TWCurve curve) const { return result; } -Data PrivateKey::sign(const Data& digest, TWCurve curve, int(*canonicalChecker)(uint8_t by, uint8_t sig[64])) const { +Data PrivateKey::sign(const Data& digest, TWCurve curve, int (*canonicalChecker)(uint8_t by, uint8_t sig[64])) const { Data result; bool success = false; switch (curve) { case TWCurveSECP256k1: { result.resize(65); - success = ecdsa_sign_digest_checked(&secp256k1, key().data(), digest.data(), digest.size(), result.data() + 1, - result.data(), canonicalChecker) == 0; + success = ecdsa_sign_digest_checked(&secp256k1, key().data(), digest.data(), digest.size(), result.data() + 1, result.data(), canonicalChecker) == 0; } break; - case TWCurveED25519: // not supported - case TWCurveED25519Blake2bNano: // not supported - case TWCurveED25519Extended: // not supported - case TWCurveCurve25519: // not supported + case TWCurveED25519: // not supported + case TWCurveED25519Blake2bNano: // not supported + case TWCurveED25519ExtendedCardano: // not supported + case TWCurveCurve25519: // not supported break; case TWCurveNIST256p1: { result.resize(65); - success = ecdsa_sign_digest_checked(&nist256p1, key().data(), digest.data(), digest.size(), result.data() + 1, - result.data(), canonicalChecker) == 0; + success = ecdsa_sign_digest_checked(&nist256p1, key().data(), digest.data(), digest.size(), result.data() + 1, result.data(), canonicalChecker) == 0; } break; case TWCurveNone: default: @@ -285,24 +272,9 @@ Data PrivateKey::signAsDER(const Data& digest, TWCurve curve) const { return result; } -Data PrivateKey::signSchnorr(const Data& message, TWCurve curve) const { - bool success = false; +Data PrivateKey::signZilliqa(const Data& message) const { Data sig(64); - switch (curve) { - case TWCurveSECP256k1: { - success = zil_schnorr_sign(&secp256k1, key().data(), message.data(), static_cast(message.size()), sig.data()) == 0; - } break; - - case TWCurveNIST256p1: - case TWCurveED25519: - case TWCurveED25519Blake2bNano: - case TWCurveED25519Extended: - case TWCurveCurve25519: - case TWCurveNone: - default: - // not support - break; - } + bool success = zil_schnorr_sign(&secp256k1, key().data(), message.data(), static_cast(message.size()), sig.data()) == 0; if (!success) { return {}; diff --git a/src/PrivateKey.h b/src/PrivateKey.h index 207c51a4a23..94c1ea2d2c2 100644 --- a/src/PrivateKey.h +++ b/src/PrivateKey.h @@ -13,16 +13,21 @@ namespace TW { +enum PrivateKeyType { + PrivateKeyTypeDefault32 = 0, // 32 bytes private key. + PrivateKeyTypeCardano = 1, // 96 bytes private key. +}; + class PrivateKey { public: /// The number of bytes in a private key. static const size_t size = 32; - /// The number of bytes in a double extended key (used by Cardano) - static const size_t doubleExtendedSize = 2 * 3 * 32; + /// The number of bytes in a Cardano key (two extended ed25519 keys + chain code) + static const size_t cardanoKeySize = 2 * 3 * 32; /// The private key bytes: /// - common case: 'size' bytes - /// - double extended case: 'doubleExtendedSize' bytes, key+extension+chainCode+second+secondExtension+secondChainCode + /// - double extended case: 'cardanoKeySize' bytes, key+extension+chainCode+second+secondExtension+secondChainCode Data bytes; /// Optional members for extended keys and second extended keys @@ -45,7 +50,7 @@ class PrivateKey { /// Initializes a private key from a string of bytes. explicit PrivateKey(const std::string& data) : PrivateKey(TW::data(data)) {} - /// Initializes a double extended private key with two extended keys + /// Initializes a Cardano style key explicit PrivateKey( const Data& bytes1, const Data& extension1, const Data& chainCode1, const Data& bytes2, const Data& extension2, const Data& chainCode2); @@ -76,8 +81,8 @@ class PrivateKey { /// DER. Data signAsDER(const Data& digest, TWCurve curve) const; - /// Signs a digest using given ECDSA curve, returns schnorr signature - Data signSchnorr(const Data& message, TWCurve curve) const; + /// Signs a digest using given ECDSA curve, returns Zilliqa schnorr signature + Data signZilliqa(const Data& message) const; /// Cleanup contents (fill with 0s), called before destruction void cleanup(); diff --git a/src/PublicKey.cpp b/src/PublicKey.cpp index 60327ffcaec..b1b1e40cc8d 100644 --- a/src/PublicKey.cpp +++ b/src/PublicKey.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -31,8 +32,8 @@ bool PublicKey::isValid(const Data& data, enum TWPublicKeyType type) { case TWPublicKeyTypeCURVE25519: case TWPublicKeyTypeED25519Blake2b: return size == ed25519Size; - case TWPublicKeyTypeED25519Extended: - return size == ed25519DoubleExtendedSize; + case TWPublicKeyTypeED25519Cardano: + return size == cardanoKeySize; case TWPublicKeyTypeSECP256k1: case TWPublicKeyTypeNIST256p1: return size == secp256k1Size && (data[0] == 0x02 || data[0] == 0x03); @@ -75,8 +76,8 @@ PublicKey::PublicKey(const Data& data, enum TWPublicKeyType type) assert(data.size() == ed25519Size); // ensured by isValid() above std::copy(std::begin(data), std::end(data), std::back_inserter(bytes)); break; - case TWPublicKeyTypeED25519Extended: - bytes.reserve(ed25519DoubleExtendedSize); + case TWPublicKeyTypeED25519Cardano: + bytes.reserve(cardanoKeySize); std::copy(std::begin(data), std::end(data), std::back_inserter(bytes)); } } @@ -119,7 +120,7 @@ PublicKey PublicKey::extended() const { case TWPublicKeyTypeED25519: case TWPublicKeyTypeCURVE25519: case TWPublicKeyTypeED25519Blake2b: - case TWPublicKeyTypeED25519Extended: + case TWPublicKeyTypeED25519Cardano: return *this; default: return *this; @@ -138,9 +139,10 @@ bool PublicKey::verify(const Data& signature, const Data& message) const { return ed25519_sign_open(message.data(), message.size(), bytes.data(), signature.data()) == 0; case TWPublicKeyTypeED25519Blake2b: return ed25519_sign_open_blake2b(message.data(), message.size(), bytes.data(), signature.data()) == 0; - case TWPublicKeyTypeED25519Extended: - throw std::logic_error("Not yet implemented"); - // ed25519_sign_open(message.data(), message.size(), bytes.data(), signature.data()) == 0; + case TWPublicKeyTypeED25519Cardano: { + const auto key = subData(bytes, 0, ed25519Size); + return ed25519_sign_open(message.data(), message.size(), key.data(), signature.data()) == 0; + } case TWPublicKeyTypeCURVE25519: { auto ed25519PublicKey = Data(); ed25519PublicKey.resize(PublicKey::ed25519Size); @@ -177,7 +179,7 @@ bool PublicKey::verifyAsDER(const Data& signature, const Data& message) const { } } -bool PublicKey::verifySchnorr(const Data& signature, const Data& message) const { +bool PublicKey::verifyZilliqa(const Data& signature, const Data& message) const { switch (type) { case TWPublicKeyTypeSECP256k1: case TWPublicKeyTypeSECP256k1Extended: @@ -186,7 +188,7 @@ bool PublicKey::verifySchnorr(const Data& signature, const Data& message) const case TWPublicKeyTypeNIST256p1Extended: case TWPublicKeyTypeED25519: case TWPublicKeyTypeED25519Blake2b: - case TWPublicKeyTypeED25519Extended: + case TWPublicKeyTypeED25519Cardano: case TWPublicKeyTypeCURVE25519: default: return false; diff --git a/src/PublicKey.h b/src/PublicKey.h index 9c4e2ac07dc..705469c0b9d 100644 --- a/src/PublicKey.h +++ b/src/PublicKey.h @@ -21,10 +21,11 @@ class PublicKey { /// The number of bytes in a secp256k1 and nist256p1 public key. static const size_t secp256k1Size = 33; - /// The number of bytes in a ed25519 public key. + /// The number of bytes in an ed25519 public key. static const size_t ed25519Size = 32; - static const size_t ed25519DoubleExtendedSize = 2 * 2 * 32; + /// The number of bytes in a Cardano public key (two ed25519 public key + chain code). + static const size_t cardanoKeySize = 2 * 2 * 32; /// The number of bytes in a secp256k1 and nist256p1 extended public key. static const size_t secp256k1ExtendedSize = 65; @@ -64,8 +65,8 @@ class PublicKey { /// Verifies a signature in DER format. bool verifyAsDER(const Data& signature, const Data& message) const; - /// Verifies a schnorr signature for the provided message. - bool verifySchnorr(const Data& signature, const Data& message) const; + /// Verifies a Zilliqa schnorr signature for the provided message. + bool verifyZilliqa(const Data& signature, const Data& message) const; /// Computes the public key hash. /// diff --git a/src/Zilliqa/Signer.cpp b/src/Zilliqa/Signer.cpp index 2de41566d73..1683d59c77f 100644 --- a/src/Zilliqa/Signer.cpp +++ b/src/Zilliqa/Signer.cpp @@ -95,7 +95,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { const auto preImage = Signer::getPreImage(input, address); const auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); const auto pubKey = key.getPublicKey(TWPublicKeyTypeSECP256k1); - const auto signature = key.signSchnorr(preImage, TWCurveSECP256k1); + const auto signature = key.signZilliqa(preImage); const auto transaction = input.transaction(); // build json diff --git a/src/algorithm/to_array.h b/src/algorithm/to_array.h index 9946f978551..06f302cd7e1 100644 --- a/src/algorithm/to_array.h +++ b/src/algorithm/to_array.h @@ -6,8 +6,8 @@ #pragma once -#include //< std::copy -#include //< std::array +#include +#include namespace TW { diff --git a/src/interface/TWPrivateKey.cpp b/src/interface/TWPrivateKey.cpp index e6d2a846d52..2440b47f0a7 100644 --- a/src/interface/TWPrivateKey.cpp +++ b/src/interface/TWPrivateKey.cpp @@ -81,8 +81,8 @@ struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519Blake2b(struct TWPri return new TWPublicKey{ pk->impl.getPublicKey(TWPublicKeyTypeED25519Blake2b) }; } -struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519Extended(struct TWPrivateKey *_Nonnull pk) { - return new TWPublicKey{ pk->impl.getPublicKey(TWPublicKeyTypeED25519Extended) }; +struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519Cardano(struct TWPrivateKey *_Nonnull pk) { + return new TWPublicKey{ pk->impl.getPublicKey(TWPublicKeyTypeED25519Cardano) }; } struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyCurve25519(struct TWPrivateKey *_Nonnull pk) { @@ -118,9 +118,9 @@ TWData *TWPrivateKeySignAsDER(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull } } -TWData *TWPrivateKeySignSchnorr(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull message, enum TWCurve curve) { +TWData *TWPrivateKeySignZilliqaSchnorr(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull message) { const auto& msg = *reinterpret_cast(message); - auto result = pk->impl.signSchnorr(msg, curve); + auto result = pk->impl.signZilliqa(msg); if (result.empty()) { return nullptr; diff --git a/src/interface/TWPublicKey.cpp b/src/interface/TWPublicKey.cpp index 4d08f0a2d50..61ada495ab1 100644 --- a/src/interface/TWPublicKey.cpp +++ b/src/interface/TWPublicKey.cpp @@ -60,10 +60,10 @@ bool TWPublicKeyVerifyAsDER(struct TWPublicKey *_Nonnull pk, TWData *_Nonnull si return pk->impl.verifyAsDER(s, m); } -bool TWPublicKeyVerifySchnorr(struct TWPublicKey *_Nonnull pk, TWData *_Nonnull signature, TWData *_Nonnull message) { +bool TWPublicKeyVerifyZilliqaSchnorr(struct TWPublicKey *_Nonnull pk, TWData *_Nonnull signature, TWData *_Nonnull message) { const auto& s = *reinterpret_cast(signature); const auto& m = *reinterpret_cast(message); - return pk->impl.verifySchnorr(s, m); + return pk->impl.verifyZilliqa(s, m); } enum TWPublicKeyType TWPublicKeyKeyType(struct TWPublicKey *_Nonnull publicKey) { diff --git a/swift/Tests/Blockchains/CardanoTests.swift b/swift/Tests/Blockchains/CardanoTests.swift index ef18ca9e65e..9a99cb186dd 100644 --- a/swift/Tests/Blockchains/CardanoTests.swift +++ b/swift/Tests/Blockchains/CardanoTests.swift @@ -10,7 +10,7 @@ import XCTest class CardanoTests: XCTestCase { func testAddress() { let key = PrivateKey(data: Data(hexString: "e8c8c5b2df13f3abed4e6b1609c808e08ff959d7e6fc3d849e3f2880550b574437aa559095324d78459b9bb2da069da32337e1cc5da78f48e1bd084670107f3110f3245ddf9132ecef98c670272ef39c03a232107733d4a1d28cb53318df26fae0d152bb611cb9ff34e945e4ff627e6fba81da687a601a879759cd76530b5744424db69a75edd4780a5fbc05d1a3c84ac4166ff8e424808481dd8e77627ce5f5bf2eea84515a4e16c4ff06c92381822d910b5cbf9e9c144e1fb76a6291af7276")!)! - let pubkey = key.getPublicKeyEd25519Extended() + let pubkey = key.getPublicKeyEd25519Cardano() let address = AnyAddress(publicKey: pubkey, coin: .cardano) let addressFromString = AnyAddress(string: "addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq", coin: .cardano)! diff --git a/swift/Tests/PrivateKeyTests.swift b/swift/Tests/PrivateKeyTests.swift index 6ecdf044344..ae363969f17 100644 --- a/swift/Tests/PrivateKeyTests.swift +++ b/swift/Tests/PrivateKeyTests.swift @@ -79,8 +79,8 @@ class PrivateKeyTests: XCTestCase { let message = "hello schnorr".data(using: .utf8)! - let sig = privateKey.signSchnorr(message: message, curve: .secp256k1)! - let verified = publicKey.verifySchnorr(signature: sig, message: message) + let sig = privateKey.signZilliqaSchnorr(message: message)! + let verified = publicKey.verifyZilliqaSchnorr(signature: sig, message: message) XCTAssertEqual(sig.hexString, "d166b1ae7892c5ef541461dc12a50214d0681b63d8037cda29a3fe6af8bb973e4ea94624d85bc0010bdc1b38d05198328fae21254adc2bf5feaf2804d54dba55") XCTAssertTrue(verified) diff --git a/swift/common-xcframework.yml b/swift/common-xcframework.yml index 3fb188cec67..cf3bf1d6840 100644 --- a/swift/common-xcframework.yml +++ b/swift/common-xcframework.yml @@ -109,7 +109,8 @@ targets: - trezor-crypto/crypto/groestl.c - trezor-crypto/crypto/hmac_drbg.c - trezor-crypto/crypto/rfc6979.c - - trezor-crypto/crypto/schnorr.c + - trezor-crypto/crypto/zilliqa.c + - trezor-crypto/crypto/cardano.c - trezor-crypto/crypto/shamir.c - trezor-crypto/crypto/sodium/private/fe_25_5/fe.c - trezor-crypto/crypto/sodium/private/ed25519_ref10.c diff --git a/swift/project.yml b/swift/project.yml index 81534762937..06541322c69 100644 --- a/swift/project.yml +++ b/swift/project.yml @@ -126,7 +126,8 @@ targets: - trezor-crypto/crypto/groestl.c - trezor-crypto/crypto/hmac_drbg.c - trezor-crypto/crypto/rfc6979.c - - trezor-crypto/crypto/schnorr.c + - trezor-crypto/crypto/zilliqa.c + - trezor-crypto/crypto/cardano.c - trezor-crypto/crypto/shamir.c - trezor-crypto/crypto/sodium/private/fe_25_5/fe.c - trezor-crypto/crypto/sodium/private/ed25519_ref10.c diff --git a/tests/Cardano/AddressTests.cpp b/tests/Cardano/AddressTests.cpp index 7e55bb15f28..a7cde0c7d60 100644 --- a/tests/Cardano/AddressTests.cpp +++ b/tests/Cardano/AddressTests.cpp @@ -6,19 +6,17 @@ #include "Cardano/AddressV3.h" +#include "Coin.h" #include "HDWallet.h" #include "HexCoding.h" #include "PrivateKey.h" -#include "Coin.h" #include - using namespace TW::Cardano; using namespace TW; using namespace std; - const auto dummyKey = parse_hex("1111111111111111111111111111111111111111111111111111111111111111"); TEST(CardanoAddress, V3NetworkIdKind) { @@ -97,8 +95,8 @@ TEST(CardanoAddress, MnemonicToAddressV3) { EXPECT_EQ("30a6f50aeb58ff7699b822d63e0ef27aeff17d9f", hex(wallet.getEntropy())); { - PrivateKey masterPrivKey = wallet.getMasterKey(TWCurve::TWCurveED25519Extended); - PrivateKey masterPrivKeyExt = wallet.getMasterKeyExtension(TWCurve::TWCurveED25519Extended); + PrivateKey masterPrivKey = wallet.getMasterKey(TWCurve::TWCurveED25519ExtendedCardano); + PrivateKey masterPrivKeyExt = wallet.getMasterKeyExtension(TWCurve::TWCurveED25519ExtendedCardano); // the two together matches first half of keypair ASSERT_EQ("a018cd746e128a0be0782b228c275473205445c33b9000a33dd5668b430b5744", hex(masterPrivKey.bytes)); ASSERT_EQ("26877cfe435fddda02409b839b7386f3738f10a30b95a225f4b720ee71d2505b", hex(masterPrivKeyExt.bytes)); @@ -113,7 +111,7 @@ TEST(CardanoAddress, MnemonicToAddressV3) { { const auto privateKey = wallet.getKey(coin, derivPath); EXPECT_EQ(hex(privateKey.bytes), "e8c8c5b2df13f3abed4e6b1609c808e08ff959d7e6fc3d849e3f2880550b574437aa559095324d78459b9bb2da069da32337e1cc5da78f48e1bd084670107f3110f3245ddf9132ecef98c670272ef39c03a232107733d4a1d28cb53318df26fae0d152bb611cb9ff34e945e4ff627e6fba81da687a601a879759cd76530b5744424db69a75edd4780a5fbc05d1a3c84ac4166ff8e424808481dd8e77627ce5f5bf2eea84515a4e16c4ff06c92381822d910b5cbf9e9c144e1fb76a6291af7276"); - const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Extended); + const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); const auto address = AddressV3(publicKey); EXPECT_EQ(address.string(), "addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq"); @@ -129,44 +127,44 @@ TEST(CardanoAddress, MnemonicToAddressV3) { EXPECT_EQ("e0d152bb611cb9ff34e945e4ff627e6fba81da687a601a879759cd76530b5744", hex(privateKey.secondKey())); EXPECT_EQ("424db69a75edd4780a5fbc05d1a3c84ac4166ff8e424808481dd8e77627ce5f5", hex(privateKey.secondExtension())); EXPECT_EQ("bf2eea84515a4e16c4ff06c92381822d910b5cbf9e9c144e1fb76a6291af7276", hex(privateKey.secondChainCode())); - PublicKey publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Extended); + PublicKey publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); EXPECT_EQ("fafa7eb4146220db67156a03a5f7a79c666df83eb31abbfbe77c85e06d40da3110f3245ddf9132ecef98c670272ef39c03a232107733d4a1d28cb53318df26faf4b8d5201961e68f2e177ba594101f513ee70fe70a41324e8ea8eb787ffda6f4bf2eea84515a4e16c4ff06c92381822d910b5cbf9e9c144e1fb76a6291af7276", hex(publicKey.bytes)); string addr = AddressV3(publicKey).string(); EXPECT_EQ("addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq", addr); } { PrivateKey privKey0 = wallet.getKey(TWCoinTypeCardano, DerivationPath("m/44'/1815'/0'/0/0")); - PublicKey pubKey0 = privKey0.getPublicKey(TWPublicKeyTypeED25519Extended); + PublicKey pubKey0 = privKey0.getPublicKey(TWPublicKeyTypeED25519Cardano); auto addr0 = AddressV2(pubKey0); EXPECT_EQ("Ae2tdPwUPEZ6RUCnjGHFqi59k5WZLiv3HoCCNGCW8SYc5H9srdTzn1bec4W", addr0.string()); } { PrivateKey privKey1 = wallet.getKey(TWCoinTypeCardano, DerivationPath("m/44'/1815'/0'/0/1")); - PublicKey pubKey1 = privKey1.getPublicKey(TWPublicKeyTypeED25519Extended); + PublicKey pubKey1 = privKey1.getPublicKey(TWPublicKeyTypeED25519Cardano); auto addr1 = AddressV2(pubKey1); EXPECT_EQ("Ae2tdPwUPEZ7dnds6ZyhQdmgkrDFFPSDh8jG9RAhswcXt1bRauNw5jczjpV", addr1.string()); } { PrivateKey privKey1 = wallet.getKey(TWCoinTypeCardano, DerivationPath("m/44'/1815'/0'/0/2")); - PublicKey pubKey1 = privKey1.getPublicKey(TWPublicKeyTypeED25519Extended); + PublicKey pubKey1 = privKey1.getPublicKey(TWPublicKeyTypeED25519Cardano); auto addr1 = AddressV2(pubKey1); EXPECT_EQ("Ae2tdPwUPEZ8LAVy21zj4BF97iWxKCmPv12W6a18zLX3V7rZDFFVgqUBkKw", addr1.string()); } { PrivateKey privKey0 = wallet.getKey(TWCoinTypeCardano, DerivationPath("m/1852'/1815'/0'/0/0")); - PublicKey pubKey0 = privKey0.getPublicKey(TWPublicKeyTypeED25519Extended); + PublicKey pubKey0 = privKey0.getPublicKey(TWPublicKeyTypeED25519Cardano); auto addr0 = AddressV3(pubKey0); EXPECT_EQ("addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq", addr0.string()); } { PrivateKey privKey1 = wallet.getKey(TWCoinTypeCardano, DerivationPath("m/1852'/1815'/0'/0/1")); - PublicKey pubKey1 = privKey1.getPublicKey(TWPublicKeyTypeED25519Extended); + PublicKey pubKey1 = privKey1.getPublicKey(TWPublicKeyTypeED25519Cardano); auto addr1 = AddressV3(pubKey1); EXPECT_EQ("addr1q9068st87h22h3l6w6t5evnlm067rag94llqya2hkjrsd3wvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qpmxzjt", addr1.string()); } { PrivateKey privKey1 = wallet.getKey(TWCoinTypeCardano, DerivationPath("m/1852'/1815'/0'/0/2")); - PublicKey pubKey1 = privKey1.getPublicKey(TWPublicKeyTypeED25519Extended); + PublicKey pubKey1 = privKey1.getPublicKey(TWPublicKeyTypeED25519Cardano); auto addr1 = AddressV3(pubKey1); EXPECT_EQ("addr1qxteqxsgxrs4he9d28lh70qu7qfz7saj6dmxwsqyle2yp3xvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35quehtx3", addr1.string()); } @@ -194,7 +192,7 @@ TEST(CardanoAddress, MnemonicToAddressV3) { auto mnemonicPlay1 = "youth away raise north opinion slice dash bus soldier dizzy bitter increase saddle live champion"; auto wallet = HDWallet(mnemonicPlay1, ""); PrivateKey privateKey = wallet.getKey(TWCoinTypeCardano, DerivationPath(TWPurposeBIP44, TWCoinTypeCardano, DerivationPathIndex(0, true).derivationIndex(), 0, 0)); - PublicKey publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Extended); + PublicKey publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); string addr = AddressV2(publicKey).string(); EXPECT_EQ("Ae2tdPwUPEZJYT9g1JgQWtLveUHavyRxQGi6hVzoQjct7yyCLGgk3pCyx7h", addr); } @@ -203,7 +201,7 @@ TEST(CardanoAddress, MnemonicToAddressV3) { auto mnemonicPlay2 = "return custom two home gain guilt kangaroo supply market current curtain tomorrow heavy blue robot"; auto wallet = HDWallet(mnemonicPlay2, ""); PrivateKey privateKey = wallet.getKey(TWCoinTypeCardano, DerivationPath(TWPurposeBIP44, TWCoinTypeCardano, DerivationPathIndex(0, true).derivationIndex(), 0, 0)); - PublicKey publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Extended); + PublicKey publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); string addr = AddressV2(publicKey).string(); EXPECT_EQ("Ae2tdPwUPEZLtJx7LA2XZ3zzwonH9x9ieX3dMzaTBD3TfXuKczjMSjTecr1", addr); } @@ -213,7 +211,7 @@ TEST(CardanoAddress, MnemonicToAddressV3) { auto mnemonicALDemo = "civil void tool perfect avocado sweet immense fluid arrow aerobic boil flash"; auto wallet = HDWallet(mnemonicALDemo, ""); PrivateKey privateKey = wallet.getKey(TWCoinTypeCardano, DerivationPath(TWPurposeBIP44, TWCoinTypeCardano, DerivationPathIndex(0, true).derivationIndex(), 0, 0)); - PublicKey publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Extended); + PublicKey publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); string addr = AddressV2(publicKey).string(); EXPECT_EQ("Ae2tdPwUPEZJbLcD8iLgN7hVGvq66WdR4zocntRekSP97Ds3MvCfmEDjJYu", addr); } @@ -248,36 +246,36 @@ TEST(CardanoAddress, FromPublicKeyV2) { { // caradano-crypto.js test auto publicKey = PublicKey(parse_hex( - "e6f04522f875c1563682ca876ddb04c2e2e3ae718e3ff9f11c03dd9f9dccf69869272d81c376382b8a87c21370a7ae9618df8da708d1a9490939ec54ebe43000" - "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" // dummy second - ), TWPublicKeyTypeED25519Extended); + "e6f04522f875c1563682ca876ddb04c2e2e3ae718e3ff9f11c03dd9f9dccf69869272d81c376382b8a87c21370a7ae9618df8da708d1a9490939ec54ebe43000" + "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" // dummy second + ), TWPublicKeyTypeED25519Cardano); auto address = AddressV2(publicKey); ASSERT_EQ(address.string(), "Ae2tdPwUPEZCxt4UV1Uj2AMMRvg5pYPypqZowVptz3GYpK4pkcvn3EjkuNH"); } { // Adalite test account addr0 auto publicKey = PublicKey(parse_hex( - "57fd54be7b38bb8952782c2f59aa276928a4dcbb66c8c62ce44f9d623ecd5a03bf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4" - "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" // dummy second - ), TWPublicKeyTypeED25519Extended); + "57fd54be7b38bb8952782c2f59aa276928a4dcbb66c8c62ce44f9d623ecd5a03bf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4" + "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" // dummy second + ), TWPublicKeyTypeED25519Cardano); auto address = AddressV2(publicKey); ASSERT_EQ(address.string(), "Ae2tdPwUPEZ6RUCnjGHFqi59k5WZLiv3HoCCNGCW8SYc5H9srdTzn1bec4W"); } { // Adalite test account addr1 auto publicKey = PublicKey(parse_hex( - "25af99056d600f7956312406bdd1cd791975bb1ae91c9d034fc65f326195fcdb247ee97ec351c0820dd12de4ca500232f73a35fe6f86778745bcd57f34d1048d" - "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" // dummy second - ), TWPublicKeyTypeED25519Extended); + "25af99056d600f7956312406bdd1cd791975bb1ae91c9d034fc65f326195fcdb247ee97ec351c0820dd12de4ca500232f73a35fe6f86778745bcd57f34d1048d" + "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" // dummy second + ), TWPublicKeyTypeED25519Cardano); auto address = AddressV2(publicKey); ASSERT_EQ(address.string(), "Ae2tdPwUPEZ7dnds6ZyhQdmgkrDFFPSDh8jG9RAhswcXt1bRauNw5jczjpV"); } { // Play1 addr0 auto publicKey = PublicKey(parse_hex( - "7cee0f30b9d536a786547dd77b35679b6830e945ffde768eb4f2a061b9dba016e513fa1290da1d22e83a41f17eed72d4489483b561fff36b9555ffdb91c430e2" - "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" // dummy second - ), TWPublicKeyTypeED25519Extended); + "7cee0f30b9d536a786547dd77b35679b6830e945ffde768eb4f2a061b9dba016e513fa1290da1d22e83a41f17eed72d4489483b561fff36b9555ffdb91c430e2" + "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" // dummy second + ), TWPublicKeyTypeED25519Cardano); auto address = AddressV2(publicKey); ASSERT_EQ(address.string(), "Ae2tdPwUPEZJYT9g1JgQWtLveUHavyRxQGi6hVzoQjct7yyCLGgk3pCyx7h"); } @@ -292,7 +290,7 @@ TEST(CardanoAddress, FromPrivateKeyV2) { parse_hex("bf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4"), dummyKey, dummyKey, dummyKey ); - auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Extended); + auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); ASSERT_EQ(hex(publicKey.bytes), "57fd54be7b38bb8952782c2f59aa276928a4dcbb66c8c62ce44f9d623ecd5a03" "bf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4" @@ -309,7 +307,7 @@ TEST(CardanoAddress, FromPrivateKeyV2) { parse_hex("e513fa1290da1d22e83a41f17eed72d4489483b561fff36b9555ffdb91c430e2"), dummyKey, dummyKey, dummyKey ); - auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Extended); + auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); ASSERT_EQ(hex(publicKey.bytes), "7cee0f30b9d536a786547dd77b35679b6830e945ffde768eb4f2a061b9dba016" "e513fa1290da1d22e83a41f17eed72d4489483b561fff36b9555ffdb91c430e2" @@ -326,7 +324,7 @@ TEST(CardanoAddress, FromPrivateKeyV2) { parse_hex("69272d81c376382b8a87c21370a7ae9618df8da708d1a9490939ec54ebe43000"), dummyKey, dummyKey, dummyKey ); - auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Extended); + auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); ASSERT_EQ(hex(publicKey.bytes), "e6f04522f875c1563682ca876ddb04c2e2e3ae718e3ff9f11c03dd9f9dccf698" "69272d81c376382b8a87c21370a7ae9618df8da708d1a9490939ec54ebe43000" @@ -345,7 +343,7 @@ TEST(CardanoAddress, PrivateKeyExtended) { parse_hex("bf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4"), dummyKey, dummyKey, dummyKey ); - auto publicKeyExt = privateKeyExt.getPublicKey(TWPublicKeyTypeED25519Extended); + auto publicKeyExt = privateKeyExt.getPublicKey(TWPublicKeyTypeED25519Cardano); ASSERT_EQ(128, publicKeyExt.bytes.size()); // Non-extended: both are 32 bytes. diff --git a/tests/Cardano/SigningTests.cpp b/tests/Cardano/SigningTests.cpp index 77fa4ad8d51..34edb07ca6b 100644 --- a/tests/Cardano/SigningTests.cpp +++ b/tests/Cardano/SigningTests.cpp @@ -438,7 +438,7 @@ TEST(CardanoSigning, SignTransferFromLegacy) { const auto privateKeyData = parse_hex("c031e942f6bf2b2864700e7da20964ee6bb6d716345ce2e24d8c00e6500b574411111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); { const auto privKey = PrivateKey(privateKeyData); - const auto pubKey = privKey.getPublicKey(TWPublicKeyTypeED25519Extended); + const auto pubKey = privKey.getPublicKey(TWPublicKeyTypeED25519Cardano); const auto addr = AddressV2(pubKey); EXPECT_EQ(addr.string(), "Ae2tdPwUPEZMRgecV9jV2e9RdbrmnWu7YgRie4de16xLdkWhy6q7ypmRhgn"); } @@ -760,7 +760,7 @@ TEST(CardanoSigning, SignMessageWithKey) { "1111111111111111111111111111111111111111111111111111111111111111" )); - const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Extended); + const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); EXPECT_EQ(hex(publicKey.bytes), "e6f04522f875c1563682ca876ddb04c2e2e3ae718e3ff9f11c03dd9f9dccf698" "69272d81c376382b8a87c21370a7ae9618df8da708d1a9490939ec54ebe43000" @@ -771,7 +771,7 @@ TEST(CardanoSigning, SignMessageWithKey) { const auto sampleMessageStr = "Hello world"; const auto sampleMessage = data(sampleMessageStr); - const auto signature = privateKey.sign(sampleMessage, TWCurveED25519Extended); + const auto signature = privateKey.sign(sampleMessage, TWCurveED25519ExtendedCardano); const auto sampleRightSignature = "1096ddcfb2ad21a4c0d861ef3fabe18841e8de88105b0d8e36430d7992c588634ead4100c32b2800b31b65e014d54a8238bdda63118d829bf0bcf1b631e86f0e"; EXPECT_EQ(hex(signature), sampleRightSignature); diff --git a/tests/Cardano/TWCardanoAddressTests.cpp b/tests/Cardano/TWCardanoAddressTests.cpp index 68a0c9a991d..be830e7f833 100644 --- a/tests/Cardano/TWCardanoAddressTests.cpp +++ b/tests/Cardano/TWCardanoAddressTests.cpp @@ -21,7 +21,7 @@ TEST(TWCardano, AddressFromPublicKey) { "639aadd8b6499ae39b78018b79255fbd8f585cbda9cbb9e907a72af86afb7a05d41a57c2dec9a6a19d6bf3b1fa784f334f3a0048d25ccb7b78a7b44066f9ba7bed7f28be986cbe06819165f2ee41b403678a098961013cf4a2f3e9ea61fb6c1a" ).get())); ASSERT_NE(nullptr, privateKey.get()); - auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyEd25519Extended(privateKey.get())); + auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyEd25519Cardano(privateKey.get())); ASSERT_NE(nullptr, publicKey.get()); ASSERT_EQ(128, publicKey.get()->impl.bytes.size()); auto address = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKey(publicKey.get(), TWCoinTypeCardano)); @@ -45,7 +45,7 @@ TEST(TWCardano, AddressFromWallet) { auto privateKeyData = WRAPD(TWPrivateKeyData(privateKey.get())); EXPECT_EQ(TWDataSize(privateKeyData.get()), 192); - auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyEd25519Extended(privateKey.get())); + auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyEd25519Cardano(privateKey.get())); auto publicKeyData = WRAPD(TWPublicKeyData(publicKey.get())); EXPECT_EQ(TWDataSize(publicKeyData.get()), 128); assertHexEqual(publicKeyData, "fafa7eb4146220db67156a03a5f7a79c666df83eb31abbfbe77c85e06d40da3110f3245ddf9132ecef98c670272ef39c03a232107733d4a1d28cb53318df26faf4b8d5201961e68f2e177ba594101f513ee70fe70a41324e8ea8eb787ffda6f4bf2eea84515a4e16c4ff06c92381822d910b5cbf9e9c144e1fb76a6291af7276"); diff --git a/tests/Oasis/AddressTests.cpp b/tests/Oasis/AddressTests.cpp index 543fb51fdcf..4d5cb972282 100644 --- a/tests/Oasis/AddressTests.cpp +++ b/tests/Oasis/AddressTests.cpp @@ -57,12 +57,12 @@ TEST(OasisAddress, FromPublicKey) { TEST(OasisAddress, WrongPublicKeyType) { try { - auto publicKey = PublicKey(parse_hex("aba52c0dcb80c2fe96ed4c3741af40c573a0500c0d73acda22795c37cb0f1739"), TWPublicKeyTypeED25519Extended); + auto publicKey = PublicKey(parse_hex("aba52c0dcb80c2fe96ed4c3741af40c573a0500c0d73acda22795c37cb0f1739"), TWPublicKeyTypeED25519Cardano); auto address = Address(publicKey); } catch( std::invalid_argument& e1 ) { return; } - FAIL() << "TWPublicKeyTypeED25519Extended should generate an exception as it an invalid publicKey type"; + FAIL() << "TWPublicKeyTypeED25519Cardano should generate an exception as it an invalid publicKey type"; } TEST(OasisAddress, FromString) { diff --git a/tests/PrivateKeyTests.cpp b/tests/PrivateKeyTests.cpp index bde1b2124a4..e020e83245f 100644 --- a/tests/PrivateKeyTests.cpp +++ b/tests/PrivateKeyTests.cpp @@ -193,7 +193,7 @@ TEST(PrivateKey, PrivateKeyExtended) { EXPECT_EQ("d41a57c2dec9a6a19d6bf3b1fa784f334f3a0048d25ccb7b78a7b44066f9ba7b", hex(privateKeyExt.secondExtension())); EXPECT_EQ("ed7f28be986cbe06819165f2ee41b403678a098961013cf4a2f3e9ea61fb6c1a", hex(privateKeyExt.secondChainCode())); - auto publicKeyExt = privateKeyExt.getPublicKey(TWPublicKeyTypeED25519Extended); + auto publicKeyExt = privateKeyExt.getPublicKey(TWPublicKeyTypeED25519Cardano); EXPECT_EQ(2*64, publicKeyExt.bytes.size()); // Try other constructor for extended key @@ -209,12 +209,12 @@ TEST(PrivateKey, PrivateKeyExtended) { } TEST(PrivateKey, PrivateKeyExtendedError) { - // TWPublicKeyTypeED25519Extended pubkey with non-extended private: error + // TWPublicKeyTypeED25519Cardano pubkey with non-extended private: error auto privateKeyNonext = PrivateKey(parse_hex( "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5" )); try { - auto publicKeyError = privateKeyNonext.getPublicKey(TWPublicKeyTypeED25519Extended); + auto publicKeyError = privateKeyNonext.getPublicKey(TWPublicKeyTypeED25519Cardano); } catch (invalid_argument& ex) { // expected exception return; @@ -315,7 +315,7 @@ TEST(PrivateKey, SignExtended) { )); Data messageData = TW::data("hello"); Data hash = Hash::keccak256(messageData); - Data actual = privateKeyExt.sign(hash, TWCurveED25519Extended); + Data actual = privateKeyExt.sign(hash, TWCurveED25519ExtendedCardano); EXPECT_EQ( "375df53b6a4931dcf41e062b1c64288ed4ff3307f862d5c1b1c71964ce3b14c99422d0fdfeb2807e9900a26d491d5e8a874c24f98eec141ed694d7a433a90f08", @@ -327,20 +327,12 @@ TEST(PrivateKey, SignSchnorr) { const auto privateKey = PrivateKey(parse_hex("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5")); const Data messageData = TW::data("hello schnorr"); const Data digest = Hash::sha256(messageData); - const auto signature = privateKey.signSchnorr(digest, TWCurveSECP256k1); + const auto signature = privateKey.signZilliqa(digest); EXPECT_EQ(hex(signature), "b8118ccb99563fe014279c957b0a9d563c1666e00367e9896fe541765246964f64a53052513da4e6dc20fdaf69ef0d95b4ca51c87ad3478986cf053c2dd0b853" ); } -TEST(PrivateKey, SignSchnorrWrongType) { - const auto privateKey = PrivateKey(parse_hex("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5")); - const Data messageData = TW::data("hello schnorr"); - const Data digest = Hash::sha256(messageData); - const auto signature = privateKey.signSchnorr(digest, TWCurveNIST256p1); - EXPECT_EQ(signature.size(), 0); -} - TEST(PrivateKey, SignNIST256p1) { Data privKeyData = parse_hex("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5"); auto privateKey = PrivateKey(privKeyData); diff --git a/tests/PublicKeyTests.cpp b/tests/PublicKeyTests.cpp index 47176838204..33f21c231d7 100644 --- a/tests/PublicKeyTests.cpp +++ b/tests/PublicKeyTests.cpp @@ -214,17 +214,15 @@ TEST(PublicKeyTests, VerifyAsDER) { } TEST(PublicKeyTests, VerifyEd25519Extended) { - const auto privateKey = PrivateKey(parse_hex("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5")); + const auto privateKey = PrivateKey(parse_hex("e8c8c5b2df13f3abed4e6b1609c808e08ff959d7e6fc3d849e3f2880550b574437aa559095324d78459b9bb2da069da32337e1cc5da78f48e1bd084670107f3110f3245ddf9132ecef98c670272ef39c03a232107733d4a1d28cb53318df26fae0d152bb611cb9ff34e945e4ff627e6fba81da687a601a879759cd76530b5744424db69a75edd4780a5fbc05d1a3c84ac4166ff8e424808481dd8e77627ce5f5bf2eea84515a4e16c4ff06c92381822d910b5cbf9e9c144e1fb76a6291af7276")); + const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); - const Data messageData = TW::data("Hello"); - const Data digest = Hash::sha256(messageData); + const auto message = TW::data("Hello"); + const auto digest = Hash::sha256(message); + const auto signature = privateKey.sign(digest, TWCurveED25519ExtendedCardano); + const auto valid = publicKey.verify(signature, digest); - try { - privateKey.sign(digest, TWCurveED25519Extended); - } catch (const std::invalid_argument&) { - return; // OK, not implemented - } - FAIL() << "Missing expected exception"; + EXPECT_TRUE(valid); } TEST(PublicKeyTests, VerifySchnorr) { @@ -234,9 +232,9 @@ TEST(PublicKeyTests, VerifySchnorr) { const Data messageData = TW::data("hello schnorr"); const Data digest = Hash::sha256(messageData); - const auto signature = privateKey.signSchnorr(digest, TWCurveSECP256k1); + const auto signature = privateKey.signZilliqa(digest); const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); - EXPECT_TRUE(publicKey.verifySchnorr(signature, digest)); + EXPECT_TRUE(publicKey.verifyZilliqa(signature, digest)); EXPECT_EQ(hex(signature), "b8118ccb99563fe014279c957b0a9d563c1666e00367e9896fe541765246964f64a53052513da4e6dc20fdaf69ef0d95b4ca51c87ad3478986cf053c2dd0b853"); } @@ -247,9 +245,9 @@ TEST(PublicKeyTests, VerifySchnorrWrongType) { const Data messageData = TW::data("hello schnorr"); const Data digest = Hash::sha256(messageData); - const auto signature = privateKey.signSchnorr(digest, TWCurveSECP256k1); + const auto signature = privateKey.signZilliqa(digest); const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeNIST256p1); - EXPECT_FALSE(publicKey.verifySchnorr(signature, digest)); + EXPECT_FALSE(publicKey.verifyZilliqa(signature, digest)); } TEST(PublicKeyTests, Recover) { diff --git a/tests/Zilliqa/SignatureTests.cpp b/tests/Zilliqa/SignatureTests.cpp index 386e655cfbf..cd3fe38e216 100644 --- a/tests/Zilliqa/SignatureTests.cpp +++ b/tests/Zilliqa/SignatureTests.cpp @@ -21,9 +21,9 @@ TEST(ZilliqaSignature, Signing) { auto message = "hello schnorr"; auto messageData = WRAPD(TWDataCreateWithBytes((uint8_t *)message, strnlen(message, 13))); - auto signatureData = WRAPD(TWPrivateKeySignSchnorr(privateKey.get(), messageData.get(), TWCurveSECP256k1)); + auto signatureData = WRAPD(TWPrivateKeySignZilliqaSchnorr(privateKey.get(), messageData.get())); auto signature = data(TWDataBytes(signatureData.get()), TWDataSize(signatureData.get())); - ASSERT_TRUE(TWPublicKeyVerifySchnorr(pubKey.get(), signatureData.get(), messageData.get())); + ASSERT_TRUE(TWPublicKeyVerifyZilliqaSchnorr(pubKey.get(), signatureData.get(), messageData.get())); EXPECT_EQ(hex(signature), "d166b1ae7892c5ef541461dc12a50214d0681b63d8037cda29a3fe6af8bb973e4ea94624d85bc0010bdc1b38d05198328fae21254adc2bf5feaf2804d54dba55"); } diff --git a/tests/Zilliqa/SignerTests.cpp b/tests/Zilliqa/SignerTests.cpp index f261634d650..b7b3b95ccd7 100644 --- a/tests/Zilliqa/SignerTests.cpp +++ b/tests/Zilliqa/SignerTests.cpp @@ -45,7 +45,7 @@ TEST(ZilliqaSigner, PreImage) { ASSERT_EQ(hex(preImage.begin(), preImage.end()), "0881800410041a149ca91eb535fb92fda5094110fdaeb752edb9b03922230a21034ae47910d58b9bde819c3cffa8de4441955508db00aa2540db8e6bf6e99abc1b2a120a10000000000000000000000da475abf00032120a100000000000000000000000003b9aca003801"); - ASSERT_TRUE(pubKey.verifySchnorr(Data(signature.begin(), signature.end()), preImage)); + ASSERT_TRUE(pubKey.verifyZilliqa(Data(signature.begin(), signature.end()), preImage)); } TEST(ZilliqaSigner, Signing) { diff --git a/tests/interface/TWCoinTypeTests.cpp b/tests/interface/TWCoinTypeTests.cpp index ab02da2e41a..0390b8ad1e0 100644 --- a/tests/interface/TWCoinTypeTests.cpp +++ b/tests/interface/TWCoinTypeTests.cpp @@ -99,7 +99,7 @@ TEST(TWCoinType, TWPublicKeyType) { ASSERT_EQ(TWPublicKeyTypeSECP256k1, TWCoinTypePublicKeyType(TWCoinTypeKava)); ASSERT_EQ(TWPublicKeyTypeSECP256k1, TWCoinTypePublicKeyType(TWCoinTypeBandChain)); ASSERT_EQ(TWPublicKeyTypeSECP256k1, TWCoinTypePublicKeyType(TWCoinTypeBluzelle)); - ASSERT_EQ(TWPublicKeyTypeED25519Extended, TWCoinTypePublicKeyType(TWCoinTypeCardano)); + ASSERT_EQ(TWPublicKeyTypeED25519Cardano, TWCoinTypePublicKeyType(TWCoinTypeCardano)); ASSERT_EQ(TWPublicKeyTypeED25519, TWCoinTypePublicKeyType(TWCoinTypeElrond)); ASSERT_EQ(TWPublicKeyTypeED25519, TWCoinTypePublicKeyType(TWCoinTypeOasis)); ASSERT_EQ(TWPublicKeyTypeSECP256k1, TWCoinTypePublicKeyType(TWCoinTypeTHORChain)); diff --git a/trezor-crypto/CMakeLists.txt b/trezor-crypto/CMakeLists.txt index be1eaa6defe..76f526bd984 100644 --- a/trezor-crypto/CMakeLists.txt +++ b/trezor-crypto/CMakeLists.txt @@ -26,7 +26,7 @@ set(TW_WARNING_FLAGS ) add_library(TrezorCrypto - crypto/bignum.c crypto/ecdsa.c crypto/curves.c crypto/secp256k1.c crypto/rand.c crypto/hmac.c crypto/bip32.c crypto/bip39.c crypto/pbkdf2.c crypto/base58.c crypto/base32.c + crypto/bignum.c crypto/ecdsa.c crypto/curves.c crypto/secp256k1.c crypto/rand.c crypto/hmac.c crypto/bip32.c crypto/bip39.c crypto/slip39.c crypto/pbkdf2.c crypto/base58.c crypto/base32.c crypto/address.c crypto/script.c crypto/ripemd160.c @@ -56,8 +56,9 @@ add_library(TrezorCrypto crypto/groestl.c crypto/hmac_drbg.c crypto/rfc6979.c - crypto/schnorr.c crypto/shamir.c + crypto/zilliqa.c + crypto/cardano.c ) if (EMSCRIPTEN) diff --git a/trezor-crypto/crypto/bip32.c b/trezor-crypto/crypto/bip32.c index 9c0da8217ae..4d821a8cf69 100644 --- a/trezor-crypto/crypto/bip32.c +++ b/trezor-crypto/crypto/bip32.c @@ -48,23 +48,12 @@ #include "nem.h" #endif #if USE_CARDANO -#include +#include #endif #include -#define CARDANO_MAX_NODE_DEPTH 1048576 - const curve_info ed25519_info = { - .bip32_name = "ed25519 seed", - .params = NULL, - .hasher_base58 = HASHER_SHA2D, - .hasher_sign = HASHER_SHA2D, - .hasher_pubkey = HASHER_SHA2_RIPEMD, - .hasher_script = HASHER_SHA2, -}; - -const curve_info ed25519_cardano_info = { - .bip32_name = "ed25519 cardano seed", + .bip32_name = ED25519_SEED_NAME, .params = NULL, .hasher_base58 = HASHER_SHA2D, .hasher_sign = HASHER_SHA2D, @@ -215,11 +204,17 @@ uint32_t hdnode_fingerprint(HDNode *node) { return fingerprint; } -int hdnode_private_ckd(HDNode *inout, uint32_t i) { +int hdnode_private_ckd_bip32(HDNode *inout, uint32_t i) { CONFIDENTIAL uint8_t data[1 + 32 + 4]; CONFIDENTIAL uint8_t I[32 + 32]; CONFIDENTIAL bignum256 a, b; +#if USE_CARDANO + if (inout->curve == &ed25519_cardano_info) { + return 0; + } +#endif + if (i & 0x80000000) { // private derivation data[0] = 0; memcpy(data + 1, inout->private_key, 32); @@ -227,7 +222,9 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) { if (!inout->curve->params) { return 0; } - hdnode_fill_public_key(inout); + if (hdnode_fill_public_key(inout) != 0) { + return 0; + } memcpy(data, inout->public_key, 33); } write_be(data + 33, i); @@ -281,156 +278,17 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i) { return 1; } +int hdnode_private_ckd(HDNode *inout, uint32_t i) { #if USE_CARDANO -static void scalar_multiply8(const uint8_t *src, int bytes, uint8_t *dst) { - uint8_t prev_acc = 0; - for (int i = 0; i < bytes; i++) { - dst[i] = (src[i] << 3) + (prev_acc & 0x7); - prev_acc = src[i] >> 5; - } - dst[bytes] = src[bytes - 1] >> 5; -} - -static void scalar_add_256bits(const uint8_t *src1, const uint8_t *src2, - uint8_t *dst) { - uint16_t r = 0; - for (int i = 0; i < 32; i++) { - r = r + (uint16_t)src1[i] + (uint16_t)src2[i]; - dst[i] = r & 0xff; - r >>= 8; - } -} - -int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) { - if (inout->depth >= CARDANO_MAX_NODE_DEPTH) { - return 0; - } - - // checks for hardened/non-hardened derivation, keysize 32 means we are - // dealing with public key and thus non-h, keysize 64 is for private key - int keysize = 32; - if (index & 0x80000000) { - keysize = 64; - } - - CONFIDENTIAL uint8_t data[1 + 64 + 4]; - CONFIDENTIAL uint8_t z[32 + 32]; - CONFIDENTIAL uint8_t priv_key[64]; - CONFIDENTIAL uint8_t res_key[64]; - - write_le(data + keysize + 1, index); - - memcpy(priv_key, inout->private_key, 32); - memcpy(priv_key + 32, inout->private_key_extension, 32); - - if (keysize == 64) { // private derivation - data[0] = 0; - memcpy(data + 1, inout->private_key, 32); - memcpy(data + 1 + 32, inout->private_key_extension, 32); - } else { // public derivation - hdnode_fill_public_key(inout); - data[0] = 2; - memcpy(data + 1, inout->public_key + 1, 32); - } - - CONFIDENTIAL HMAC_SHA512_CTX ctx; - hmac_sha512_Init(&ctx, inout->chain_code, 32); - hmac_sha512_Update(&ctx, data, 1 + keysize + 4); - hmac_sha512_Final(&ctx, z); - - CONFIDENTIAL uint8_t zl8[32]; - memzero(zl8, 32); - - /* get 8 * Zl */ - scalar_multiply8(z, 28, zl8); - /* Kl = 8*Zl + parent(K)l */ - scalar_add_256bits(zl8, priv_key, res_key); - - /* Kr = Zr + parent(K)r */ - scalar_add_256bits(z + 32, priv_key + 32, res_key + 32); - - memcpy(inout->private_key, res_key, 32); - memcpy(inout->private_key_extension, res_key + 32, 32); - - if (keysize == 64) { - data[0] = 1; - } else { - data[0] = 3; + if (inout->curve == &ed25519_cardano_info) { + return hdnode_private_ckd_cardano(inout, i); + } else +#endif + { + return hdnode_private_ckd_bip32(inout, i); } - hmac_sha512_Init(&ctx, inout->chain_code, 32); - hmac_sha512_Update(&ctx, data, 1 + keysize + 4); - hmac_sha512_Final(&ctx, z); - - memcpy(inout->chain_code, z + 32, 32); - inout->depth++; - inout->child_num = index; - memzero(inout->public_key, sizeof(inout->public_key)); - - // making sure to wipe our memory - memzero(z, sizeof(z)); - memzero(data, sizeof(data)); - memzero(priv_key, sizeof(priv_key)); - memzero(res_key, sizeof(res_key)); - return 1; -} - -static int hdnode_from_secret_cardano(const uint8_t *k, - const uint8_t *chain_code, HDNode *out) { - memzero(out, sizeof(HDNode)); - out->depth = 0; - out->child_num = 0; - out->curve = &ed25519_cardano_info; - memcpy(out->private_key, k, 32); - memcpy(out->private_key_extension, k + 32, 32); - memcpy(out->chain_code, chain_code, 32); - - out->private_key[0] &= 0xf8; - out->private_key[31] &= 0x1f; - out->private_key[31] |= 0x40; - - out->public_key[0] = 0; - hdnode_fill_public_key(out); - - return 1; -} - -// Derives the root Cardano HDNode from a master secret, aka seed, as defined in -// SLIP-0023. -int hdnode_from_seed_cardano(const uint8_t *seed, int seed_len, HDNode *out) { - CONFIDENTIAL uint8_t I[SHA512_DIGEST_LENGTH]; - CONFIDENTIAL uint8_t k[SHA512_DIGEST_LENGTH]; - CONFIDENTIAL HMAC_SHA512_CTX ctx; - - hmac_sha512_Init(&ctx, (const uint8_t *)ED25519_CARDANO_NAME, - strlen(ED25519_CARDANO_NAME)); - hmac_sha512_Update(&ctx, seed, seed_len); - hmac_sha512_Final(&ctx, I); - - sha512_Raw(I, 32, k); - - int ret = hdnode_from_secret_cardano(k, I + 32, out); - - memzero(I, sizeof(I)); - memzero(k, sizeof(k)); - memzero(&ctx, sizeof(ctx)); - return ret; } -// Derives the root Cardano HDNode from a passphrase and the entropy encoded in -// a BIP-0039 mnemonic using the Icarus derivation scheme, aka V2 derivation -// scheme. -int hdnode_from_entropy_cardano_icarus(const uint8_t *pass, int pass_len, - const uint8_t *entropy, int entropy_len, - HDNode *out) { - CONFIDENTIAL uint8_t secret[96]; - pbkdf2_hmac_sha512(pass, pass_len, entropy, entropy_len, 4096, secret, 96); - - int ret = hdnode_from_secret_cardano(secret, secret + 64, out); - memzero(secret, sizeof(secret)); - return ret; -} -#endif - int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code) { @@ -530,6 +388,13 @@ CONFIDENTIAL struct { HDNode node; } private_ckd_cache[BIP32_CACHE_SIZE]; +void bip32_cache_clear(void) { + private_ckd_cache_root_set = false; + private_ckd_cache_index = 0; + memzero(&private_ckd_cache_root, sizeof(private_ckd_cache_root)); + memzero(private_ckd_cache, sizeof(private_ckd_cache)); +} + int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint) { if (i_count == 0) { @@ -597,26 +462,34 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, } #endif -void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw) { - hdnode_fill_public_key(node); +int hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw) { + if (hdnode_fill_public_key(node) != 0) { + return 1; + } ecdsa_get_address_raw(node->public_key, version, node->curve->hasher_pubkey, addr_raw); + return 0; } -void hdnode_get_address(HDNode *node, uint32_t version, char *addr, - int addrsize) { - hdnode_fill_public_key(node); +int hdnode_get_address(HDNode *node, uint32_t version, char *addr, + int addrsize) { + if (hdnode_fill_public_key(node) != 0) { + return 1; + } ecdsa_get_address(node->public_key, version, node->curve->hasher_pubkey, node->curve->hasher_base58, addr, addrsize); + return 0; } -void hdnode_fill_public_key(HDNode *node) { - if (node->public_key[0] != 0) return; +int hdnode_fill_public_key(HDNode *node) { + if (node->public_key[0] != 0) return 0; #if USE_BIP32_25519_CURVES if (node->curve->params) { - ecdsa_get_public_key33(node->curve->params, node->private_key, - node->public_key); + if (ecdsa_get_public_key33(node->curve->params, node->private_key, + node->public_key) != 0) { + return 1; + } } else { node->public_key[0] = 1; if (node->curve == &ed25519_info) { @@ -631,16 +504,18 @@ void hdnode_fill_public_key(HDNode *node) { curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key); #if USE_CARDANO } else if (node->curve == &ed25519_cardano_info) { - ed25519_publickey_ext(node->private_key, node->private_key_extension, - node->public_key + 1); + ed25519_publickey_ext(node->private_key, node->public_key + 1); #endif } } #else - ecdsa_get_public_key33(node->curve->params, node->private_key, - node->public_key); + if (ecdsa_get_public_key33(node->curve->params, node->private_key, + node->public_key) != 0) { + return 1; + } #endif + return 0; } #if USE_ETHEREUM @@ -649,7 +524,10 @@ int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash) { SHA3_CTX ctx = {0}; /* get uncompressed public key */ - ecdsa_get_public_key65(node->curve->params, node->private_key, buf); + if (ecdsa_get_public_key65(node->curve->params, node->private_key, buf) != + 0) { + return 0; + } /* compute sha3 of x and y coordinate without 04 prefix */ sha3_256_Init(&ctx); @@ -669,7 +547,10 @@ int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address) { return 0; } - hdnode_fill_public_key(node); + if (hdnode_fill_public_key(node) != 0) { + return 0; + } + return nem_get_address(&node->public_key[1], version, address); } @@ -778,17 +659,12 @@ int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, return 1; // signatures are not supported } else { if (node->curve == &ed25519_info) { - hdnode_fill_public_key(node); - ed25519_sign(msg, msg_len, node->private_key, node->public_key + 1, sig); + ed25519_sign(msg, msg_len, node->private_key, sig); } else if (node->curve == &ed25519_sha3_info) { - hdnode_fill_public_key(node); - ed25519_sign_sha3(msg, msg_len, node->private_key, node->public_key + 1, - sig); + ed25519_sign_sha3(msg, msg_len, node->private_key, sig); #if USE_KECCAK } else if (node->curve == &ed25519_keccak_info) { - hdnode_fill_public_key(node); - ed25519_sign_keccak(msg, msg_len, node->private_key, node->public_key + 1, - sig); + ed25519_sign_keccak(msg, msg_len, node->private_key, sig); #endif } else { return 1; // unknown or unsupported curve diff --git a/trezor-crypto/crypto/bip39.c b/trezor-crypto/crypto/bip39.c index b64a75207c9..fc61539c938 100644 --- a/trezor-crypto/crypto/bip39.c +++ b/trezor-crypto/crypto/bip39.c @@ -44,6 +44,11 @@ CONFIDENTIAL struct { uint8_t seed[512 / 8]; } bip39_cache[BIP39_CACHE_SIZE]; +void bip39_cache_clear(void) { + memzero(bip39_cache, sizeof(bip39_cache)); + bip39_cache_index = 0; +} + #endif // [wallet-core] Added output buffer @@ -249,7 +254,7 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, // binary search for finding the word in the wordlist int mnemonic_find_word(const char *word) { - int lo = 0, hi = BIP39_WORDS - 1; + int lo = 0, hi = BIP39_WORD_COUNT - 1; while (lo <= hi) { int mid = lo + (hi - lo) / 2; int cmp = strcmp(word, wordlist[mid]); @@ -277,7 +282,7 @@ const char *mnemonic_complete_word(const char *prefix, int len) { } const char *mnemonic_get_word(int index) { - if (index >= 0 && index < BIP39_WORDS) { + if (index >= 0 && index < BIP39_WORD_COUNT) { return wordlist[index]; } else { return NULL; diff --git a/trezor-crypto/crypto/blake256.c b/trezor-crypto/crypto/blake256.c index 0da6918102a..a4e9b489c37 100644 --- a/trezor-crypto/crypto/blake256.c +++ b/trezor-crypto/crypto/blake256.c @@ -169,9 +169,8 @@ void blake256_Update( BLAKE256_CTX *S, const uint8_t *in, size_t inlen ) { memcpy( ( void * ) ( S->buf + left ), \ ( void * ) in, ( size_t ) inlen ); - S->buflen = left + ( int )inlen; } - else S->buflen = 0; + S->buflen = left + inlen; } diff --git a/trezor-crypto/crypto/cardano.c b/trezor-crypto/crypto/cardano.c new file mode 100644 index 00000000000..6b07f776c15 --- /dev/null +++ b/trezor-crypto/crypto/cardano.c @@ -0,0 +1,307 @@ +/** + * Copyright (c) 2013-2021 SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if USE_CARDANO + +#define CARDANO_MAX_NODE_DEPTH 1048576 + +const curve_info ed25519_cardano_info = { + .bip32_name = ED25519_CARDANO_NAME, + .params = NULL, + .hasher_base58 = HASHER_SHA2D, + .hasher_sign = HASHER_SHA2D, + .hasher_pubkey = HASHER_SHA2_RIPEMD, + .hasher_script = HASHER_SHA2, +}; + +static void scalar_multiply8(const uint8_t *src, int bytes, uint8_t *dst) { + uint8_t prev_acc = 0; + for (int i = 0; i < bytes; i++) { + dst[i] = (src[i] << 3) + (prev_acc & 0x7); + prev_acc = src[i] >> 5; + } + dst[bytes] = src[bytes - 1] >> 5; +} + +static void scalar_add_256bits(const uint8_t *src1, const uint8_t *src2, + uint8_t *dst) { + uint16_t r = 0; + for (int i = 0; i < 32; i++) { + r = r + (uint16_t)src1[i] + (uint16_t)src2[i]; + dst[i] = r & 0xff; + r >>= 8; + } +} + +static void cardano_ed25519_tweak_bits(uint8_t private_key[32]) { + private_key[0] &= 0xf8; + private_key[31] &= 0x1f; + private_key[31] |= 0x40; +} + +int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) { + if (inout->curve != &ed25519_cardano_info) { + return 0; + } + + if (inout->depth >= CARDANO_MAX_NODE_DEPTH) { + return 0; + } + + // checks for hardened/non-hardened derivation, keysize 32 means we are + // dealing with public key and thus non-h, keysize 64 is for private key + int keysize = 32; + if (index & 0x80000000) { + keysize = 64; + } + + CONFIDENTIAL uint8_t data[1 + 64 + 4]; + CONFIDENTIAL uint8_t z[32 + 32]; + CONFIDENTIAL uint8_t priv_key[64]; + CONFIDENTIAL uint8_t res_key[64]; + + write_le(data + keysize + 1, index); + + memcpy(priv_key, inout->private_key, 32); + memcpy(priv_key + 32, inout->private_key_extension, 32); + + if (keysize == 64) { // private derivation + data[0] = 0; + memcpy(data + 1, inout->private_key, 32); + memcpy(data + 1 + 32, inout->private_key_extension, 32); + } else { // public derivation + if (hdnode_fill_public_key(inout) != 0) { + return 0; + } + data[0] = 2; + memcpy(data + 1, inout->public_key + 1, 32); + } + + CONFIDENTIAL HMAC_SHA512_CTX ctx; + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, 1 + keysize + 4); + hmac_sha512_Final(&ctx, z); + + CONFIDENTIAL uint8_t zl8[32]; + memzero(zl8, 32); + + /* get 8 * Zl */ + scalar_multiply8(z, 28, zl8); + /* Kl = 8*Zl + parent(K)l */ + scalar_add_256bits(zl8, priv_key, res_key); + + /* Kr = Zr + parent(K)r */ + scalar_add_256bits(z + 32, priv_key + 32, res_key + 32); + + memcpy(inout->private_key, res_key, 32); + memcpy(inout->private_key_extension, res_key + 32, 32); + + if (keysize == 64) { + data[0] = 1; + } else { + data[0] = 3; + } + hmac_sha512_Init(&ctx, inout->chain_code, 32); + hmac_sha512_Update(&ctx, data, 1 + keysize + 4); + hmac_sha512_Final(&ctx, z); + + memcpy(inout->chain_code, z + 32, 32); + inout->depth++; + inout->child_num = index; + memzero(inout->public_key, sizeof(inout->public_key)); + + // making sure to wipe our memory + memzero(z, sizeof(z)); + memzero(data, sizeof(data)); + memzero(priv_key, sizeof(priv_key)); + memzero(res_key, sizeof(res_key)); + return 1; +} + +int hdnode_from_secret_cardano(const uint8_t secret[CARDANO_SECRET_LENGTH], + HDNode *out) { + memzero(out, sizeof(HDNode)); + out->depth = 0; + out->child_num = 0; + out->curve = &ed25519_cardano_info; + memcpy(out->private_key, secret, 32); + memcpy(out->private_key_extension, secret + 32, 32); + memcpy(out->chain_code, secret + 64, 32); + + cardano_ed25519_tweak_bits(out->private_key); + + out->public_key[0] = 0; + if (hdnode_fill_public_key(out) != 0) { + return 0; + } + + return 1; +} + +// Derives the root Cardano secret from a master secret, aka seed, as defined in +// SLIP-0023. +int secret_from_seed_cardano_slip23(const uint8_t *seed, int seed_len, + uint8_t secret_out[CARDANO_SECRET_LENGTH]) { + CONFIDENTIAL uint8_t I[SHA512_DIGEST_LENGTH]; + CONFIDENTIAL HMAC_SHA512_CTX ctx; + + hmac_sha512_Init(&ctx, (const uint8_t *)ED25519_CARDANO_NAME, + strlen(ED25519_CARDANO_NAME)); + hmac_sha512_Update(&ctx, seed, seed_len); + hmac_sha512_Final(&ctx, I); + + sha512_Raw(I, 32, secret_out); + + memcpy(secret_out + SHA512_DIGEST_LENGTH, I + 32, 32); + cardano_ed25519_tweak_bits(secret_out); + + memzero(I, sizeof(I)); + memzero(&ctx, sizeof(ctx)); + return 1; +} + +// Derives the root Cardano secret from a BIP-32 master secret via the Ledger +// derivation: +// https://github.com/cardano-foundation/CIPs/blob/09d7d8ee1bd64f7e6b20b5a6cae088039dce00cb/CIP-0003/Ledger.md +int secret_from_seed_cardano_ledger(const uint8_t *seed, int seed_len, + uint8_t secret_out[CARDANO_SECRET_LENGTH]) { + CONFIDENTIAL uint8_t chain_code[SHA256_DIGEST_LENGTH]; + CONFIDENTIAL uint8_t root_key[SHA512_DIGEST_LENGTH]; + CONFIDENTIAL HMAC_SHA256_CTX ctx; + CONFIDENTIAL HMAC_SHA512_CTX sctx; + + const uint8_t *intermediate_result = seed; + int intermediate_result_len = seed_len; + do { + // STEP 1: derive a master secret like in BIP-32/SLIP-10 + hmac_sha512_Init(&sctx, (const uint8_t *)ED25519_SEED_NAME, + strlen(ED25519_SEED_NAME)); + hmac_sha512_Update(&sctx, intermediate_result, intermediate_result_len); + hmac_sha512_Final(&sctx, root_key); + + // STEP 2: check that the resulting key does not have a particular bit set, + // otherwise iterate like in SLIP-10 + intermediate_result = root_key; + intermediate_result_len = sizeof(root_key); + } while (root_key[31] & 0x20); + + // STEP 3: calculate the chain code as a HMAC-SHA256 of "\x01" + seed, + // key is "ed25519 seed" + hmac_sha256_Init(&ctx, (const unsigned char *)ED25519_SEED_NAME, + strlen(ED25519_SEED_NAME)); + hmac_sha256_Update(&ctx, (const unsigned char *)"\x01", 1); + hmac_sha256_Update(&ctx, seed, seed_len); + hmac_sha256_Final(&ctx, chain_code); + + // STEP 4: extract information into output + _Static_assert( + SHA512_DIGEST_LENGTH + SHA256_DIGEST_LENGTH == CARDANO_SECRET_LENGTH, + "Invalid configuration of Cardano secret size"); + memcpy(secret_out, root_key, SHA512_DIGEST_LENGTH); + memcpy(secret_out + SHA512_DIGEST_LENGTH, chain_code, SHA256_DIGEST_LENGTH); + + // STEP 5: tweak bits of the private key + cardano_ed25519_tweak_bits(secret_out); + + memzero(&ctx, sizeof(ctx)); + memzero(&sctx, sizeof(sctx)); + memzero(root_key, sizeof(root_key)); + memzero(chain_code, sizeof(chain_code)); + return 1; +} + +#define CARDANO_ICARUS_STEPS 32 +_Static_assert( + CARDANO_ICARUS_PBKDF2_ROUNDS % CARDANO_ICARUS_STEPS == 0, + "CARDANO_ICARUS_STEPS does not divide CARDANO_ICARUS_PBKDF2_ROUNDS"); +#define CARDANO_ICARUS_ROUNDS_PER_STEP \ + (CARDANO_ICARUS_PBKDF2_ROUNDS / CARDANO_ICARUS_STEPS) + +// Derives the root Cardano HDNode from a passphrase and the entropy encoded in +// a BIP-0039 mnemonic using the Icarus derivation scheme, aka V2 derivation +// scheme: +// https://github.com/cardano-foundation/CIPs/blob/09d7d8ee1bd64f7e6b20b5a6cae088039dce00cb/CIP-0003/Icarus.md +int secret_from_entropy_cardano_icarus( + const uint8_t *pass, int pass_len, const uint8_t *entropy, int entropy_len, + uint8_t secret_out[CARDANO_SECRET_LENGTH], + void (*progress_callback)(uint32_t, uint32_t)) { + CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx; + CONFIDENTIAL uint8_t digest[SHA512_DIGEST_LENGTH]; + uint32_t progress = 0; + + // PASS 1: first 64 bytes + pbkdf2_hmac_sha512_Init(&pctx, pass, pass_len, entropy, entropy_len, 1); + if (progress_callback) { + progress_callback(progress, CARDANO_ICARUS_PBKDF2_ROUNDS * 2); + } + for (int i = 0; i < CARDANO_ICARUS_STEPS; i++) { + pbkdf2_hmac_sha512_Update(&pctx, CARDANO_ICARUS_ROUNDS_PER_STEP); + if (progress_callback) { + progress += CARDANO_ICARUS_ROUNDS_PER_STEP; + progress_callback(progress, CARDANO_ICARUS_PBKDF2_ROUNDS * 2); + } + } + pbkdf2_hmac_sha512_Final(&pctx, digest); + + memcpy(secret_out, digest, SHA512_DIGEST_LENGTH); + + // PASS 2: remaining 32 bytes + pbkdf2_hmac_sha512_Init(&pctx, pass, pass_len, entropy, entropy_len, 2); + if (progress_callback) { + progress_callback(progress, CARDANO_ICARUS_PBKDF2_ROUNDS * 2); + } + for (int i = 0; i < CARDANO_ICARUS_STEPS; i++) { + pbkdf2_hmac_sha512_Update(&pctx, CARDANO_ICARUS_ROUNDS_PER_STEP); + if (progress_callback) { + progress += CARDANO_ICARUS_ROUNDS_PER_STEP; + progress_callback(progress, CARDANO_ICARUS_PBKDF2_ROUNDS * 2); + } + } + pbkdf2_hmac_sha512_Final(&pctx, digest); + + memcpy(secret_out + SHA512_DIGEST_LENGTH, digest, + CARDANO_SECRET_LENGTH - SHA512_DIGEST_LENGTH); + + cardano_ed25519_tweak_bits(secret_out); + + memzero(&pctx, sizeof(pctx)); + memzero(digest, sizeof(digest)); + return 1; +} + +#endif // USE_CARDANO diff --git a/trezor-crypto/crypto/chacha20poly1305/LICENSE b/trezor-crypto/crypto/chacha20poly1305/LICENSE new file mode 100644 index 00000000000..95404966f07 --- /dev/null +++ b/trezor-crypto/crypto/chacha20poly1305/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (C) 2016 Will Glozer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/trezor-crypto/crypto/chacha20poly1305/chacha_merged.c b/trezor-crypto/crypto/chacha20poly1305/chacha_merged.c index 8d4ee90c755..3819b865a59 100644 --- a/trezor-crypto/crypto/chacha20poly1305/chacha_merged.c +++ b/trezor-crypto/crypto/chacha20poly1305/chacha_merged.c @@ -23,6 +23,7 @@ void ECRYPT_init(void) return; } +// [wallet-core][non static] rename to avoid duplicate symbol in blake256.c const char chacha_sigma[16] = "expand 32-byte k"; const char tau[16] = "expand 16-byte k"; @@ -59,6 +60,12 @@ void ECRYPT_ivsetup(ECRYPT_ctx *x,const u8 *iv) x->input[15] = U8TO32_LITTLE(iv + 4); } +void ECRYPT_ctrsetup(ECRYPT_ctx *x,const u8 *ctr) +{ + x->input[12] = U8TO32_LITTLE(ctr + 0); + x->input[13] = U8TO32_LITTLE(ctr + 4); +} + void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes) { u32 x0 = 0, x1 = 0, x2 = 0, x3 = 0, x4 = 0, x5 = 0, x6 = 0, x7 = 0, x8 = 0, x9 = 0, x10 = 0, x11 = 0, x12 = 0, x13 = 0, x14 = 0, x15 = 0; diff --git a/trezor-crypto/crypto/chacha_drbg.c b/trezor-crypto/crypto/chacha_drbg.c index c1bd5d08e6f..e8027ffe939 100644 --- a/trezor-crypto/crypto/chacha_drbg.c +++ b/trezor-crypto/crypto/chacha_drbg.c @@ -19,44 +19,108 @@ #include +#include #include +#include + +#include +#include +#include + +#define CHACHA_DRBG_KEY_LENGTH 32 +#define CHACHA_DRBG_COUNTER_LENGTH 8 +#define CHACHA_DRBG_IV_LENGTH 8 +#define CHACHA_DRBG_SEED_LENGTH \ + (CHACHA_DRBG_KEY_LENGTH + CHACHA_DRBG_COUNTER_LENGTH + CHACHA_DRBG_IV_LENGTH) #define MAX(a, b) (a) > (b) ? (a) : (b) -void chacha_drbg_init(CHACHA_DRBG_CTX *ctx, - const uint8_t entropy[CHACHA_DRBG_SEED_LENGTH]) { +static void derivation_function(const uint8_t *input1, size_t input1_length, + const uint8_t *input2, size_t input2_length, + uint8_t *output, size_t output_length) { + // Implementation of Hash_df from NIST SP 800-90A + uint32_t block_count = (output_length - 1) / SHA256_DIGEST_LENGTH + 1; + size_t partial_block_length = output_length % SHA256_DIGEST_LENGTH; + assert(block_count <= 255); + + uint32_t output_length_bits = output_length * 8; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(output_length_bits, output_length_bits); +#endif + + SHA256_CTX ctx = {0}; + + for (uint8_t counter = 1; counter <= block_count; counter++) { + sha256_Init(&ctx); + sha256_Update(&ctx, &counter, sizeof(counter)); + sha256_Update(&ctx, (uint8_t *)&output_length_bits, + sizeof(output_length_bits)); + sha256_Update(&ctx, input1, input1_length); + sha256_Update(&ctx, input2, input2_length); + + if (counter != block_count || partial_block_length == 0) { + sha256_Final(&ctx, output); + output += SHA256_DIGEST_LENGTH; + } else { // last block is partial + uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; + sha256_Final(&ctx, digest); + memcpy(output, digest, partial_block_length); + memzero(digest, sizeof(digest)); + } + } + + memzero(&ctx, sizeof(ctx)); +} + +void chacha_drbg_init(CHACHA_DRBG_CTX *ctx, const uint8_t *entropy, + size_t entropy_length, const uint8_t *nonce, + size_t nonce_length) { uint8_t buffer[MAX(CHACHA_DRBG_KEY_LENGTH, CHACHA_DRBG_IV_LENGTH)] = {0}; ECRYPT_keysetup(&ctx->chacha_ctx, buffer, CHACHA_DRBG_KEY_LENGTH * 8, CHACHA_DRBG_IV_LENGTH * 8); ECRYPT_ivsetup(&ctx->chacha_ctx, buffer); - chacha_drbg_reseed(ctx, entropy); + chacha_drbg_reseed(ctx, entropy, entropy_length, nonce, nonce_length); } static void chacha_drbg_update(CHACHA_DRBG_CTX *ctx, const uint8_t data[CHACHA_DRBG_SEED_LENGTH]) { - uint8_t buffer[CHACHA_DRBG_SEED_LENGTH] = {0}; + uint8_t seed[CHACHA_DRBG_SEED_LENGTH] = {0}; if (data) - ECRYPT_encrypt_bytes(&ctx->chacha_ctx, data, buffer, - CHACHA_DRBG_SEED_LENGTH); + ECRYPT_encrypt_bytes(&ctx->chacha_ctx, data, seed, CHACHA_DRBG_SEED_LENGTH); else - ECRYPT_keystream_bytes(&ctx->chacha_ctx, buffer, CHACHA_DRBG_SEED_LENGTH); + ECRYPT_keystream_bytes(&ctx->chacha_ctx, seed, CHACHA_DRBG_SEED_LENGTH); - ECRYPT_keysetup(&ctx->chacha_ctx, buffer, CHACHA_DRBG_KEY_LENGTH * 8, + ECRYPT_keysetup(&ctx->chacha_ctx, seed, CHACHA_DRBG_KEY_LENGTH * 8, CHACHA_DRBG_IV_LENGTH * 8); - ECRYPT_ivsetup(&ctx->chacha_ctx, buffer + CHACHA_DRBG_KEY_LENGTH); + + ECRYPT_ivsetup(&ctx->chacha_ctx, + seed + CHACHA_DRBG_KEY_LENGTH + CHACHA_DRBG_COUNTER_LENGTH); + + ECRYPT_ctrsetup(&ctx->chacha_ctx, seed + CHACHA_DRBG_KEY_LENGTH); + + memzero(seed, sizeof(seed)); } void chacha_drbg_generate(CHACHA_DRBG_CTX *ctx, uint8_t *output, - uint8_t output_length) { + size_t output_length) { + assert(output_length < 65536); + assert(ctx->reseed_counter + 1 != 0); + ECRYPT_keystream_bytes(&ctx->chacha_ctx, output, output_length); chacha_drbg_update(ctx, NULL); ctx->reseed_counter++; } -void chacha_drbg_reseed(CHACHA_DRBG_CTX *ctx, - const uint8_t entropy[CHACHA_DRBG_SEED_LENGTH]) { - chacha_drbg_update(ctx, entropy); +void chacha_drbg_reseed(CHACHA_DRBG_CTX *ctx, const uint8_t *entropy, + size_t entropy_length, const uint8_t *additional_input, + size_t additional_input_length) { + uint8_t seed[CHACHA_DRBG_SEED_LENGTH] = {0}; + derivation_function(entropy, entropy_length, additional_input, + additional_input_length, seed, sizeof(seed)); + chacha_drbg_update(ctx, seed); + memzero(seed, sizeof(seed)); + ctx->reseed_counter = 1; } diff --git a/trezor-crypto/crypto/curves.c b/trezor-crypto/crypto/curves.c index c95ac8b7512..a6221a9943f 100644 --- a/trezor-crypto/crypto/curves.c +++ b/trezor-crypto/crypto/curves.c @@ -21,6 +21,7 @@ */ #include +#include const char SECP256K1_NAME[] = "secp256k1"; const char SECP256K1_DECRED_NAME[] = "secp256k1-decred"; @@ -28,10 +29,14 @@ const char SECP256K1_GROESTL_NAME[] = "secp256k1-groestl"; const char SECP256K1_SMART_NAME[] = "secp256k1-smart"; const char NIST256P1_NAME[] = "nist256p1"; const char ED25519_NAME[] = "ed25519"; +const char ED25519_SEED_NAME[] = "ed25519 seed"; +#if USE_CARDANO const char ED25519_CARDANO_NAME[] = "ed25519 cardano seed"; -const char ED25519_BLAKE2B_NANO_NAME[] = "ed25519-blake2b-nano"; // [wallet-core] +#endif const char ED25519_SHA3_NAME[] = "ed25519-sha3"; #if USE_KECCAK const char ED25519_KECCAK_NAME[] = "ed25519-keccak"; #endif const char CURVE25519_NAME[] = "curve25519"; + +const char ED25519_BLAKE2B_NANO_NAME[] = "ed25519-blake2b-nano"; // [wallet-core] diff --git a/trezor-crypto/crypto/ecdsa.c b/trezor-crypto/crypto/ecdsa.c index 0f2198fbbc0..445f29aa549 100644 --- a/trezor-crypto/crypto/ecdsa.c +++ b/trezor-crypto/crypto/ecdsa.c @@ -36,7 +36,6 @@ #include #include #include -#include // Set cp2 = cp1 void point_copy(const curve_point *cp1, curve_point *cp2) { *cp2 = *cp1; } @@ -404,13 +403,16 @@ void point_jacobian_double(jacobian_curve_point *p, const ecdsa_curve *curve) { } // res = k * p -void point_multiply(const ecdsa_curve *curve, const bignum256 *k, - const curve_point *p, curve_point *res) { +// returns 0 on success +int point_multiply(const ecdsa_curve *curve, const bignum256 *k, + const curve_point *p, curve_point *res) { // this algorithm is loosely based on // Katsuyuki Okeya and Tsuyoshi Takagi, The Width-w NAF Method Provides // Small Memory and Fast Elliptic Scalar Multiplications Secure against // Side Channel Attacks. - assert(bn_is_less(k, &curve->order)); + if (!bn_is_less(k, &curve->order)) { + return 1; + } int i = 0, j = 0; CONFIDENTIAL bignum256 a; @@ -442,7 +444,7 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k, // special case 0*p: just return zero. We don't care about constant time. if (!is_non_zero) { point_set_infinity(res); - return; + return 1; } // Now a = k + 2^256 (mod curve->order) and a is odd. @@ -523,15 +525,20 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k, jacobian_to_curve(&jres, res, prime); memzero(&a, sizeof(a)); memzero(&jres, sizeof(jres)); + + return 0; } #if USE_PRECOMPUTED_CP // res = k * G // k must be a normalized number with 0 <= k < curve->order -void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, - curve_point *res) { - assert(bn_is_less(k, &curve->order)); +// returns 0 on success +int scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, + curve_point *res) { + if (!bn_is_less(k, &curve->order)) { + return 1; + } int i = {0}, j = {0}; CONFIDENTIAL bignum256 a; @@ -559,7 +566,7 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, // special case 0*G: just return zero. We don't care about constant time. if (!is_non_zero) { point_set_infinity(res); - return; + return 0; } // Now a = k + 2^256 (mod curve->order) and a is odd. @@ -612,13 +619,15 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, jacobian_to_curve(&jres, res, prime); memzero(&a, sizeof(a)); memzero(&jres, sizeof(jres)); + + return 0; } #else -void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, - curve_point *res) { - point_multiply(curve, k, &curve->G, res); +int scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, + curve_point *res) { + return point_multiply(curve, k, &curve->G, res); } #endif @@ -632,6 +641,11 @@ int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, bignum256 k = {0}; bn_read_be(priv_key, &k); + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + // Invalid private key. + return 2; + } + point_multiply(curve, &k, &point, &point); memzero(&k, sizeof(k)); @@ -673,10 +687,17 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, #if USE_RFC6979 rfc6979_state rng = {0}; - init_rfc6979(priv_key, digest, &rng); + init_rfc6979(priv_key, digest, curve, &rng); #endif bn_read_be(digest, &z); + if (bn_is_zero(&z)) { + // The probability of the digest being all-zero by chance is infinitesimal, + // so this is most likely an indication of a bug. Furthermore, the signature + // has no value, because in this case it can be easily forged for any public + // key, see ecdsa_verify_digest(). + return 1; + } for (i = 0; i < 10000; i++) { #if USE_RFC6979 @@ -704,11 +725,16 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, continue; } + bn_read_be(priv_key, s); + if (bn_is_zero(s) || !bn_is_less(s, &curve->order)) { + // Invalid private key. + return 2; + } + // randomize operations to counter side-channel attacks generate_k_random(&randk, &curve->order); bn_multiply(&randk, &k, &curve->order); // k*rand bn_inverse(&k, &curve->order); // (k*rand)^-1 - bn_read_be(priv_key, s); // priv bn_multiply(&R.x, s, &curve->order); // R.x*priv bn_add(s, &z); // R.x*priv + z bn_multiply(&k, s, &curve->order); // (k*rand)^-1 (R.x*priv + z) @@ -755,33 +781,55 @@ int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, return -1; } -void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, - uint8_t *pub_key) { +// returns 0 on success +int ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, + uint8_t *pub_key) { curve_point R = {0}; bignum256 k = {0}; bn_read_be(priv_key, &k); + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + // Invalid private key. + memzero(pub_key, 33); + return -1; + } + // compute k*G - scalar_multiply(curve, &k, &R); + if (scalar_multiply(curve, &k, &R) != 0) { + memzero(&k, sizeof(k)); + return 1; + } pub_key[0] = 0x02 | (R.y.val[0] & 0x01); bn_write_be(&R.x, pub_key + 1); memzero(&R, sizeof(R)); memzero(&k, sizeof(k)); + return 0; } -void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, - uint8_t *pub_key) { +// returns 0 on success +int ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, + uint8_t *pub_key) { curve_point R = {0}; bignum256 k = {0}; bn_read_be(priv_key, &k); + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + // Invalid private key. + memzero(pub_key, 65); + return -1; + } + // compute k*G - scalar_multiply(curve, &k, &R); + if (scalar_multiply(curve, &k, &R) != 0) { + memzero(&k, sizeof(k)); + return 1; + } pub_key[0] = 0x04; bn_write_be(&R.x, pub_key + 1); bn_write_be(&R.y, pub_key + 33); memzero(&R, sizeof(R)); memzero(&k, sizeof(k)); + return 0; } int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, @@ -1017,6 +1065,10 @@ int ecdsa_recover_pub_from_sig(const ecdsa_curve *curve, uint8_t *pub_key, scalar_multiply(curve, &e, &cp2); // cp = (s * r^-1 * k - digest * r^-1) * G = Pub point_add(curve, &cp2, &cp); + // The point at infinity is not considered to be a valid public key. + if (point_is_infinity(&cp)) { + return 1; + } pub_key[0] = 0x04; bn_write_be(&cp.x, pub_key + 1); bn_write_be(&cp.y, pub_key + 33); @@ -1107,7 +1159,7 @@ int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der) { // process R i = 0; - while (sig[i] == 0 && i < 32) { + while (i < 31 && sig[i] == 0) { i++; } // skip leading zeroes if (sig[i] >= 0x80) { // put zero in output if MSB set @@ -1130,7 +1182,7 @@ int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der) { // process S i = 32; - while (sig[i] == 0 && i < 64) { + while (i < 63 && sig[i] == 0) { i++; } // skip leading zeroes if (sig[i] >= 0x80) { // put zero in output if MSB set @@ -1197,56 +1249,3 @@ int ecdsa_sig_from_der(const uint8_t *der, size_t der_len, uint8_t sig[64]) { return 0; } - -// [wallet-core] -int zil_schnorr_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, const uint32_t msg_len, uint8_t *sig) -{ - int i; - bignum256 k; - - uint8_t hash[32]; - sha256_Raw(msg, msg_len, hash); - - rfc6979_state rng; - init_rfc6979(priv_key, hash, &rng); - - for (i = 0; i < 10000; i++) { - // generate K deterministically - generate_k_rfc6979(&k, &rng); - // if k is too big or too small, we don't like it - if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { - continue; - } - - schnorr_sign_pair sign; - if (schnorr_sign(curve, priv_key, &k, msg, msg_len, &sign) != 0) { - continue; - } - - // we're done - memcpy(sig, sign.r, 32); - memcpy(sig + 32, sign.s, 32); - - memzero(&k, sizeof(k)); - memzero(&rng, sizeof(rng)); - memzero(&sign, sizeof(sign)); - return 0; - } - - // Too many retries without a valid signature - // -> fail with an error - memzero(&k, sizeof(k)); - memzero(&rng, sizeof(rng)); - return -1; -} - -// [wallet-core] -int zil_schnorr_verify(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, const uint32_t msg_len) -{ - schnorr_sign_pair sign; - - memcpy(sign.r, sig, 32); - memcpy(sign.s, sig + 32, 32); - - return schnorr_verify(curve, pub_key, msg, msg_len, &sign); -} diff --git a/trezor-crypto/crypto/ed25519-donna/ed25519.c b/trezor-crypto/crypto/ed25519-donna/ed25519.c index 8c3b837fa4d..6e01c0c1e98 100644 --- a/trezor-crypto/crypto/ed25519-donna/ed25519.c +++ b/trezor-crypto/crypto/ed25519-donna/ed25519.c @@ -18,6 +18,7 @@ #include #include +#include /* Generates a (extsk[0..31]) and aExt (extsk[32..63]) @@ -31,10 +32,10 @@ ed25519_extsk(hash_512bits extsk, const ed25519_secret_key sk) { } static void -ed25519_hram(hash_512bits hram, const ed25519_signature RS, const ed25519_public_key pk, const unsigned char *m, size_t mlen) { +ed25519_hram(hash_512bits hram, const ed25519_public_key R, const ed25519_public_key pk, const unsigned char *m, size_t mlen) { ed25519_hash_context ctx; ed25519_hash_init(&ctx); - ed25519_hash_update(&ctx, RS, 32); + ed25519_hash_update(&ctx, R, 32); ed25519_hash_update(&ctx, pk, 32); ed25519_hash_update(&ctx, m, mlen); ed25519_hash_final(&ctx, hram); @@ -42,34 +43,11 @@ ed25519_hram(hash_512bits hram, const ed25519_signature RS, const ed25519_public void ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key pk) { - bignum256modm a = {0}; - ge25519 ALIGN(16) A; hash_512bits extsk = {0}; - - /* A = aB */ ed25519_extsk(extsk, sk); - - expand256_modm(a, extsk, 32); - ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); - ge25519_pack(pk, &A); -} - -#if USE_CARDANO -void -ED25519_FN(ed25519_publickey_ext) (const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_public_key pk) { - bignum256modm a = {0}; - ge25519 ALIGN(16) A; - hash_512bits extsk = {0}; - - /* we don't stretch the key through hashing first since its already 64 bytes */ - - memcpy(extsk, sk, 32); - memcpy(extsk+32, skext, 32); - expand256_modm(a, extsk, 32); - ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); - ge25519_pack(pk, &A); + ed25519_publickey_ext(extsk, pk); + memzero(&extsk, sizeof(extsk)); } -#endif void ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig) { @@ -81,6 +59,7 @@ ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed2551 /* r = nonce */ expand256_modm(r, extnonce, 32); + memzero(&extnonce, sizeof(extnonce)); /* S = H(R,A,m).. */ ed25519_hram(hram, R, pk, m, mlen); @@ -88,57 +67,25 @@ ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed2551 /* S = H(R,A,m)a */ expand256_modm(a, extsk, 32); + memzero(&extsk, sizeof(extsk)); mul256_modm(S, S, a); + memzero(&a, sizeof(a)); /* S = (r + H(R,A,m)a) */ add256_modm(S, S, r); + memzero(&r, sizeof(r)); /* S = (r + H(R,A,m)a) mod L */ contract256_modm(sig, S); } void -ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS) { - ed25519_hash_context ctx; - bignum256modm r = {0}, S = {0}, a = {0}; - ge25519 ALIGN(16) R = {0}; - hash_512bits extsk = {0}, hashr = {0}, hram = {0}; - - ed25519_extsk(extsk, sk); - - - /* r = H(aExt[32..64], m) */ - ed25519_hash_init(&ctx); - ed25519_hash_update(&ctx, extsk + 32, 32); - ed25519_hash_update(&ctx, m, mlen); - ed25519_hash_final(&ctx, hashr); - expand256_modm(r, hashr, 64); - - /* R = rB */ - ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); - ge25519_pack(RS, &R); - - /* S = H(R,A,m).. */ - ed25519_hram(hram, RS, pk, m, mlen); - expand256_modm(S, hram, 64); - - /* S = H(R,A,m)a */ - expand256_modm(a, extsk, 32); - mul256_modm(S, S, a); - - /* S = (r + H(R,A,m)a) */ - add256_modm(S, S, r); - - /* S = (r + H(R,A,m)a) mod L */ - contract256_modm(RS + 32, S); -} - -#if USE_CARDANO -void -ED25519_FN(ed25519_sign_ext) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, const ed25519_public_key pk, ed25519_signature RS) { +ED25519_FN(ed25519_sign_ext) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_signature RS) { ed25519_hash_context ctx; bignum256modm r = {0}, S = {0}, a = {0}; ge25519 ALIGN(16) R = {0}; + ge25519 ALIGN(16) A = {0}; + ed25519_public_key pk = {0}; hash_512bits extsk = {0}, hashr = {0}, hram = {0}; /* we don't stretch the key through hashing first since its already 64 bytes */ @@ -153,30 +100,47 @@ ED25519_FN(ed25519_sign_ext) (const unsigned char *m, size_t mlen, const ed25519 ed25519_hash_update(&ctx, m, mlen); ed25519_hash_final(&ctx, hashr); expand256_modm(r, hashr, 64); + memzero(&hashr, sizeof(hashr)); /* R = rB */ ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); ge25519_pack(RS, &R); + /* a = aExt[0..31] */ + expand256_modm(a, extsk, 32); + memzero(&extsk, sizeof(extsk)); + + /* A = aB */ + ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); + ge25519_pack(pk, &A); + /* S = H(R,A,m).. */ ed25519_hram(hram, RS, pk, m, mlen); expand256_modm(S, hram, 64); /* S = H(R,A,m)a */ - expand256_modm(a, extsk, 32); mul256_modm(S, S, a); + memzero(&a, sizeof(a)); /* S = (r + H(R,A,m)a) */ add256_modm(S, S, r); + memzero(&r, sizeof(r)); /* S = (r + H(R,A,m)a) mod L */ contract256_modm(RS + 32, S); } -#endif + +void +ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS) { + hash_512bits extsk = {0}; + ed25519_extsk(extsk, sk); + ED25519_FN(ed25519_sign_ext)(m, mlen, extsk, extsk + 32, RS); + memzero(&extsk, sizeof(extsk)); +} int ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS) { - ge25519 ALIGN(16) R, A; + ge25519 ALIGN(16) R = {0}, A = {0}; hash_512bits hash = {0}; bignum256modm hram = {0}, S = {0}; unsigned char checkR[32] = {0}; @@ -204,17 +168,19 @@ ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed2551 int ED25519_FN(ed25519_scalarmult) (ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk) { bignum256modm a = {0}; - ge25519 ALIGN(16) A, P; + ge25519 ALIGN(16) A = {0}, P = {0}; hash_512bits extsk = {0}; ed25519_extsk(extsk, sk); expand256_modm(a, extsk, 32); + memzero(&extsk, sizeof(extsk)); if (!ge25519_unpack_negative_vartime(&P, pk)) { return -1; } ge25519_scalarmult(&A, &P, a); + memzero(&a, sizeof(a)); curve25519_neg(A.x, A.x); ge25519_pack(res, &A); return 0; @@ -225,6 +191,19 @@ ED25519_FN(ed25519_scalarmult) (ed25519_public_key res, const ed25519_secret_key #include +void +ed25519_publickey_ext(const ed25519_secret_key extsk, ed25519_public_key pk) { + bignum256modm a = {0}; + ge25519 ALIGN(16) A = {0}; + + expand256_modm(a, extsk, 32); + + /* A = aB */ + ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a); + memzero(&a, sizeof(a)); + ge25519_pack(pk, &A); +} + int ed25519_cosi_combine_publickeys(ed25519_public_key res, CONST ed25519_public_key *pks, size_t n) { size_t i = 0; @@ -277,8 +256,8 @@ void curve25519_scalarmult_basepoint(curve25519_key pk, const curve25519_key e) { curve25519_key ec = {0}; bignum256modm s = {0}; - bignum25519 ALIGN(16) yplusz, zminusy; - ge25519 ALIGN(16) p; + bignum25519 ALIGN(16) yplusz = {0}, zminusy = {0}; + ge25519 ALIGN(16) p = {0}; size_t i = 0; /* clamp */ @@ -288,9 +267,11 @@ curve25519_scalarmult_basepoint(curve25519_key pk, const curve25519_key e) { ec[31] |= 64; expand_raw256_modm(s, ec); + memzero(&ec, sizeof(ec)); /* scalar * basepoint */ ge25519_scalarmult_base_niels(&p, ge25519_niels_base_multiples, s); + memzero(&s, sizeof(s)); /* u = (y + z) / (z - y) */ curve25519_add(yplusz, p.y, p.z); @@ -310,6 +291,7 @@ curve25519_scalarmult(curve25519_key mypublic, const curve25519_key secret, cons e[31] &= 0x7f; e[31] |= 0x40; curve25519_scalarmult_donna(mypublic, e, basepoint); + memzero(&e, sizeof(e)); } #endif // ED25519_SUFFIX diff --git a/trezor-crypto/crypto/nem.c b/trezor-crypto/crypto/nem.c index fd844156871..66de5cfa9e6 100644 --- a/trezor-crypto/crypto/nem.c +++ b/trezor-crypto/crypto/nem.c @@ -205,8 +205,7 @@ size_t nem_transaction_end(nem_transaction_ctx *ctx, const ed25519_secret_key private_key, ed25519_signature signature) { if (private_key != NULL && signature != NULL) { - ed25519_sign_keccak(ctx->buffer, ctx->offset, private_key, ctx->public_key, - signature); + ed25519_sign_keccak(ctx->buffer, ctx->offset, private_key, signature); } return ctx->offset; diff --git a/trezor-crypto/crypto/rfc6979.c b/trezor-crypto/crypto/rfc6979.c index 98491594bf5..c781e47b926 100644 --- a/trezor-crypto/crypto/rfc6979.c +++ b/trezor-crypto/crypto/rfc6979.c @@ -21,14 +21,30 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ +#include -#include #include #include +#include void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, - rfc6979_state *state) { - hmac_drbg_init(state, priv_key, 32, hash, 32); + const ecdsa_curve *curve, rfc6979_state *state) { + if (curve) { + bignum256 hash_bn = {0}; + bn_read_be(hash, &hash_bn); + + // Make sure hash is partly reduced modulo order + assert(bn_bitcount(&curve->order) >= 256); + bn_mod(&hash_bn, &curve->order); + + uint8_t hash_reduced[32] = {0}; + bn_write_be(&hash_bn, hash_reduced); + memzero(&hash_bn, sizeof(hash_bn)); + hmac_drbg_init(state, priv_key, 32, hash_reduced, 32); + memzero(hash_reduced, sizeof(hash_reduced)); + } else { + hmac_drbg_init(state, priv_key, 32, hash, 32); + } } // generate next number from deterministic random number generator diff --git a/trezor-crypto/crypto/slip39.c b/trezor-crypto/crypto/slip39.c new file mode 100644 index 00000000000..ec1adf20169 --- /dev/null +++ b/trezor-crypto/crypto/slip39.c @@ -0,0 +1,151 @@ +/** + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +/** + * Returns word at position `index`. + */ +const char* get_word(uint16_t index) { + if (index >= WORDS_COUNT) { + return NULL; + } + + return slip39_wordlist[index]; +} + +/** + * Finds the index of a given word. + * Returns true on success and stores result in `index`. + */ +bool word_index(uint16_t* index, const char* word, uint8_t word_length) { + uint16_t lo = 0; + uint16_t hi = WORDS_COUNT; + uint16_t mid = 0; + + while ((hi - lo) > 1) { + mid = (hi + lo) / 2; + if (strncmp(slip39_wordlist[mid], word, word_length) > 0) { + hi = mid; + } else { + lo = mid; + } + } + if (strncmp(slip39_wordlist[lo], word, word_length) != 0) { + return false; + } + *index = lo; + return true; +} + +/** + * Returns the index of the first sequence in words_button_seq[] which is not + * less than the given sequence. Returns WORDS_COUNT if there is no such + * sequence. + */ +static uint16_t find_sequence(uint16_t sequence) { + if (sequence <= words_button_seq[0].sequence) { + return 0; + } + + uint16_t lo = 0; + uint16_t hi = WORDS_COUNT; + + while (hi - lo > 1) { + uint16_t mid = (hi + lo) / 2; + if (words_button_seq[mid].sequence >= sequence) { + hi = mid; + } else { + lo = mid; + } + } + + return hi; +} + +/** + * Returns a word matching the button sequence prefix or NULL if no match is + * found. + */ +const char* button_sequence_to_word(uint16_t sequence) { + if (sequence == 0) { + return slip39_wordlist[words_button_seq[0].index]; + } + + uint16_t multiplier = 1; + while (sequence < 1000) { + sequence *= 10; + multiplier *= 10; + } + + uint16_t i = find_sequence(sequence); + if (i >= WORDS_COUNT || + words_button_seq[i].sequence - sequence >= multiplier) { + return NULL; + } + + return slip39_wordlist[words_button_seq[i].index]; +} + +/** + * Calculates which buttons on the T9 keyboard can still be pressed after the + * prefix was entered. Returns a 9-bit bitmask, where each bit specifies which + * buttons can be pressed (there are still words in this combination). The least + * significant bit corresponds to the first button. + * + * Example: 110000110 - second, third, eighth and ninth button still can be + * pressed. + */ +uint16_t slip39_word_completion_mask(uint16_t prefix) { + if (prefix >= 1000) { + // Four char prefix -> the mask is zero. + return 0; + } + + // Determine the range of sequences [min, max), which have the given prefix. + uint16_t min = prefix; + uint16_t max = prefix + 1; + uint16_t divider = 1; + while (max <= 1000) { + min *= 10; + max *= 10; + divider *= 10; + } + divider /= 10; + + // Determine the range we will be searching in words_button_seq[]. + min = find_sequence(min); + max = find_sequence(max); + + uint16_t bitmap = 0; + for (uint16_t i = min; i < max; ++i) { + uint8_t digit = (words_button_seq[i].sequence / divider) % 10; + bitmap |= 1 << (digit - 1); + } + + return bitmap; +} diff --git a/trezor-crypto/crypto/tests/test_check.c b/trezor-crypto/crypto/tests/test_check.c index 44239eca224..0227f0146a8 100644 --- a/trezor-crypto/crypto/tests/test_check.c +++ b/trezor-crypto/crypto/tests/test_check.c @@ -21,6 +21,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include #include @@ -31,7 +32,7 @@ #include -#if VALGRIND +#ifdef VALGRIND #include #include #endif @@ -48,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -70,11 +72,10 @@ #include #include #include -#include // [wallet-core] -//#include // [wallet-core] -//#include +#include +#include -#if VALGRIND +#ifdef VALGRIND /* * This is a clever trick to make Valgrind's Memcheck verify code * is constant-time with respect to secret data. @@ -139,7 +140,7 @@ START_TEST(test_bignum_read_be) { 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}}; for (int i = 0; i < 9; i++) { - ck_assert_int_eq(a.val[i], b.val[i]); + ck_assert_uint_eq(a.val[i], b.val[i]); } } END_TEST @@ -348,21 +349,21 @@ START_TEST(test_bignum_write_uint32) { fromhex( "000000000000000000000000000000000000000000000000000000001fffffff"), &a); - ck_assert_int_eq(bn_write_uint32(&a), 0x1fffffff); + ck_assert_uint_eq(bn_write_uint32(&a), 0x1fffffff); // lowest 30 bits set bn_read_be( fromhex( "000000000000000000000000000000000000000000000000000000003fffffff"), &a); - ck_assert_int_eq(bn_write_uint32(&a), 0x3fffffff); + ck_assert_uint_eq(bn_write_uint32(&a), 0x3fffffff); // bit 31 set bn_read_be( fromhex( "0000000000000000000000000000000000000000000000000000000040000000"), &a); - ck_assert_int_eq(bn_write_uint32(&a), 0x40000000); + ck_assert_uint_eq(bn_write_uint32(&a), 0x40000000); } END_TEST @@ -374,35 +375,35 @@ START_TEST(test_bignum_write_uint64) { fromhex( "000000000000000000000000000000000000000000000000000000003fffffff"), &a); - ck_assert_int_eq(bn_write_uint64(&a), 0x3fffffff); + ck_assert_uint_eq(bn_write_uint64(&a), 0x3fffffff); // bit 31 set bn_read_be( fromhex( "0000000000000000000000000000000000000000000000000000000040000000"), &a); - ck_assert_int_eq(bn_write_uint64(&a), 0x40000000); + ck_assert_uint_eq(bn_write_uint64(&a), 0x40000000); // bit 33 set bn_read_be( fromhex( "0000000000000000000000000000000000000000000000000000000100000000"), &a); - ck_assert_int_eq(bn_write_uint64(&a), 0x100000000LL); + ck_assert_uint_eq(bn_write_uint64(&a), 0x100000000LL); // bit 61 set bn_read_be( fromhex( "0000000000000000000000000000000000000000000000002000000000000000"), &a); - ck_assert_int_eq(bn_write_uint64(&a), 0x2000000000000000LL); + ck_assert_uint_eq(bn_write_uint64(&a), 0x2000000000000000LL); // all 64 bits set bn_read_be( fromhex( "000000000000000000000000000000000000000000000000ffffffffffffffff"), &a); - ck_assert_int_eq(bn_write_uint64(&a), 0xffffffffffffffffLL); + ck_assert_uint_eq(bn_write_uint64(&a), 0xffffffffffffffffLL); } END_TEST @@ -556,19 +557,19 @@ END_TEST START_TEST(test_bignum_format_uint64) { char buf[128], str[128]; - int r; + size_t r; // test for (10^i) and (10^i) - 1 uint64_t m = 1; for (int i = 0; i <= 19; i++, m *= 10) { sprintf(str, "%" PRIu64, m); r = bn_format_uint64(m, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, strlen(str)); + ck_assert_uint_eq(r, strlen(str)); ck_assert_str_eq(buf, str); uint64_t n = m - 1; sprintf(str, "%" PRIu64, n); r = bn_format_uint64(n, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, strlen(str)); + ck_assert_uint_eq(r, strlen(str)); ck_assert_str_eq(buf, str); } } @@ -577,14 +578,14 @@ END_TEST START_TEST(test_bignum_format) { bignum256 a; char buf[128]; - int r; + size_t r; bn_read_be( fromhex( "0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); + ck_assert_uint_eq(r, 1); ck_assert_str_eq(buf, "0"); bn_read_be( @@ -592,7 +593,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, NULL, NULL, 20, 0, true, buf, sizeof(buf)); - ck_assert_int_eq(r, 22); + ck_assert_uint_eq(r, 22); ck_assert_str_eq(buf, "0.00000000000000000000"); bn_read_be( @@ -600,7 +601,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, NULL, NULL, 0, 5, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); + ck_assert_uint_eq(r, 1); ck_assert_str_eq(buf, "0"); bn_read_be( @@ -608,7 +609,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, NULL, NULL, 0, -5, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); + ck_assert_uint_eq(r, 1); ck_assert_str_eq(buf, "0"); bn_read_be( @@ -616,7 +617,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, "", "", 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); + ck_assert_uint_eq(r, 1); ck_assert_str_eq(buf, "0"); bn_read_be( @@ -624,7 +625,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, NULL, "SFFX", 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1 + 4); + ck_assert_uint_eq(r, 1 + 4); ck_assert_str_eq(buf, "0SFFX"); bn_read_be( @@ -632,7 +633,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, "PRFX", NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 4 + 1); + ck_assert_uint_eq(r, 4 + 1); ck_assert_str_eq(buf, "PRFX0"); bn_read_be( @@ -640,7 +641,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, "PRFX", "SFFX", 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 4 + 1 + 4); + ck_assert_uint_eq(r, 4 + 1 + 4); ck_assert_str_eq(buf, "PRFX0SFFX"); bn_read_be( @@ -648,7 +649,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000000"), &a); r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); + ck_assert_uint_eq(r, 1); ck_assert_str_eq(buf, "0"); bn_read_be( @@ -656,7 +657,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000001"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); + ck_assert_uint_eq(r, 1); ck_assert_str_eq(buf, "1"); bn_read_be( @@ -664,7 +665,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000001"), &a); r = bn_format(&a, NULL, NULL, 6, 6, true, buf, sizeof(buf)); - ck_assert_int_eq(r, 8); + ck_assert_uint_eq(r, 8); ck_assert_str_eq(buf, "1.000000"); bn_read_be( @@ -672,7 +673,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000002"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); + ck_assert_uint_eq(r, 1); ck_assert_str_eq(buf, "2"); bn_read_be( @@ -680,7 +681,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000005"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); + ck_assert_uint_eq(r, 1); ck_assert_str_eq(buf, "5"); bn_read_be( @@ -688,7 +689,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000009"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); + ck_assert_uint_eq(r, 1); ck_assert_str_eq(buf, "9"); bn_read_be( @@ -696,7 +697,7 @@ START_TEST(test_bignum_format) { "000000000000000000000000000000000000000000000000000000000000000a"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 2); + ck_assert_uint_eq(r, 2); ck_assert_str_eq(buf, "10"); bn_read_be( @@ -704,7 +705,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000014"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 2); + ck_assert_uint_eq(r, 2); ck_assert_str_eq(buf, "20"); bn_read_be( @@ -712,7 +713,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000032"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 2); + ck_assert_uint_eq(r, 2); ck_assert_str_eq(buf, "50"); bn_read_be( @@ -720,7 +721,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000063"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 2); + ck_assert_uint_eq(r, 2); ck_assert_str_eq(buf, "99"); bn_read_be( @@ -728,7 +729,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000000064"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); + ck_assert_uint_eq(r, 3); ck_assert_str_eq(buf, "100"); bn_read_be( @@ -736,7 +737,7 @@ START_TEST(test_bignum_format) { "00000000000000000000000000000000000000000000000000000000000000c8"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); + ck_assert_uint_eq(r, 3); ck_assert_str_eq(buf, "200"); bn_read_be( @@ -744,7 +745,7 @@ START_TEST(test_bignum_format) { "00000000000000000000000000000000000000000000000000000000000001f4"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); + ck_assert_uint_eq(r, 3); ck_assert_str_eq(buf, "500"); bn_read_be( @@ -752,7 +753,7 @@ START_TEST(test_bignum_format) { "00000000000000000000000000000000000000000000000000000000000003e7"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 3); + ck_assert_uint_eq(r, 3); ck_assert_str_eq(buf, "999"); bn_read_be( @@ -760,7 +761,7 @@ START_TEST(test_bignum_format) { "00000000000000000000000000000000000000000000000000000000000003e8"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 4); + ck_assert_uint_eq(r, 4); ck_assert_str_eq(buf, "1000"); bn_read_be( @@ -768,7 +769,7 @@ START_TEST(test_bignum_format) { "0000000000000000000000000000000000000000000000000000000000989680"), &a); r = bn_format(&a, NULL, NULL, 7, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 1); + ck_assert_uint_eq(r, 1); ck_assert_str_eq(buf, "1"); bn_read_be( @@ -776,7 +777,7 @@ START_TEST(test_bignum_format) { "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); r = bn_format(&a, NULL, NULL, 0, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 78); + ck_assert_uint_eq(r, 78); ck_assert_str_eq(buf, "11579208923731619542357098500868790785326998466564056403945" "7584007913129639935"); @@ -786,7 +787,7 @@ START_TEST(test_bignum_format) { "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); r = bn_format(&a, NULL, NULL, 1, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 79); + ck_assert_uint_eq(r, 79); ck_assert_str_eq(buf, "11579208923731619542357098500868790785326998466564056403945" "758400791312963993.5"); @@ -796,7 +797,7 @@ START_TEST(test_bignum_format) { "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); r = bn_format(&a, NULL, NULL, 2, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 79); + ck_assert_uint_eq(r, 79); ck_assert_str_eq(buf, "11579208923731619542357098500868790785326998466564056403945" "75840079131296399.35"); @@ -806,7 +807,7 @@ START_TEST(test_bignum_format) { "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 79); + ck_assert_uint_eq(r, 79); ck_assert_str_eq(buf, "11579208923731619542357098500868790785326998466564056403945" "75840079131.29639935"); @@ -816,7 +817,7 @@ START_TEST(test_bignum_format) { "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3bbb00"), &a); r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 70); + ck_assert_uint_eq(r, 70); ck_assert_str_eq(buf, "11579208923731619542357098500868790785326998466564056403945" "75840079131"); @@ -826,7 +827,7 @@ START_TEST(test_bignum_format) { "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 79); + ck_assert_uint_eq(r, 79); ck_assert_str_eq(buf, "11579208923731619542357098500868790785326998466564056403945" "7.584007913129639935"); @@ -836,7 +837,7 @@ START_TEST(test_bignum_format) { "fffffffffffffffffffffffffffffffffffffffffffffffff7e52fe5afe40000"), &a); r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 60); + ck_assert_uint_eq(r, 60); ck_assert_str_eq( buf, "115792089237316195423570985008687907853269984665640564039457"); @@ -845,7 +846,7 @@ START_TEST(test_bignum_format) { "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); r = bn_format(&a, NULL, NULL, 78, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 80); + ck_assert_uint_eq(r, 80); ck_assert_str_eq(buf, "0." "11579208923731619542357098500868790785326998466564056403945" @@ -856,7 +857,7 @@ START_TEST(test_bignum_format) { "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), &a); r = bn_format(&a, NULL, NULL, 0, 10, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 88); + ck_assert_uint_eq(r, 88); ck_assert_str_eq(buf, "11579208923731619542357098500868790785326998466564056403945" "75840079131296399350000000000"); @@ -867,7 +868,7 @@ START_TEST(test_bignum_format) { &a); r = bn_format(&a, "quite a long prefix", "even longer suffix", 60, 0, false, buf, sizeof(buf)); - ck_assert_int_eq(r, 116); + ck_assert_uint_eq(r, 116); ck_assert_str_eq(buf, "quite a long " "prefix115792089237316195." @@ -881,11 +882,11 @@ START_TEST(test_bignum_format) { memset(buf, 'a', sizeof(buf)); r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 31); ck_assert_str_eq(buf, "prefix8198552.9216486895suffix"); - ck_assert_int_eq(r, 30); + ck_assert_uint_eq(r, 30); memset(buf, 'a', sizeof(buf)); r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 30); - ck_assert_int_eq(r, 0); + ck_assert_uint_eq(r, 0); ck_assert_str_eq(buf, ""); } END_TEST @@ -954,7 +955,7 @@ END_TEST // https://tools.ietf.org/html/rfc4648#section-10 START_TEST(test_base32_rfc4648) { - const struct { + static const struct { const char *decoded; const char *encoded; const char *encoded_lowercase; @@ -978,8 +979,8 @@ START_TEST(test_base32_rfc4648) { size_t inlen = strlen(in); size_t outlen = strlen(out); - ck_assert_int_eq(outlen, base32_encoded_length(inlen)); - ck_assert_int_eq(inlen, base32_decoded_length(outlen)); + ck_assert_uint_eq(outlen, base32_encoded_length(inlen)); + ck_assert_uint_eq(inlen, base32_decoded_length(outlen)); ck_assert(base32_encode((uint8_t *)in, inlen, buffer, sizeof(buffer), BASE32_ALPHABET_RFC4648) != NULL); @@ -1003,7 +1004,7 @@ END_TEST // from // https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json START_TEST(test_base58) { - const char *base58_vector[] = { + static const char *base58_vector[] = { "0065a16059864a2fdbc7c99a4723a8395bc6f188eb", "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", "0574f209f6ea907e2ea48f74fae05782ae8a665257", @@ -1134,7 +1135,7 @@ END_TEST // Graphene Base85CheckEncoding START_TEST(test_base58gph) { - const char *base58_vector[] = { + static const char *base58_vector[] = { "02e649f63f8e8121345fd7f47d0d185a3ccaa843115cd2e9392dcd9b82263bc680", "6dumtt9swxCqwdPZBGXh9YmHoEjFFnNfwHaTqRbQTghGAY2gRz", "021c7359cd885c0e319924d97e3980206ad64387aff54908241125b3a88b55ca16", @@ -1188,7 +1189,7 @@ START_TEST(test_bignum_divmod) { i = 0; while (!bn_is_zero(&a) && i < 44) { bn_divmod58(&a, &r); - ck_assert_int_eq(r, ar[i]); + ck_assert_uint_eq(r, ar[i]); i++; } ck_assert_int_eq(i, 44); @@ -1205,7 +1206,7 @@ START_TEST(test_bignum_divmod) { i = 0; while (!bn_is_zero(&b) && i < 26) { bn_divmod1000(&b, &r); - ck_assert_int_eq(r, br[i]); + ck_assert_uint_eq(r, br[i]); i++; } ck_assert_int_eq(i, 26); @@ -1226,7 +1227,7 @@ START_TEST(test_bip32_vector_1) { // [Chain m] fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_uint_eq(fingerprint, 0x00000000); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1237,7 +1238,7 @@ START_TEST(test_bip32_vector_1) { fromhex( "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1251,8 +1252,7 @@ START_TEST(test_bip32_vector_1) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1268,7 +1268,7 @@ START_TEST(test_bip32_vector_1) { // [Chain m/0'] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(fingerprint, 0x3442193e); + ck_assert_uint_eq(fingerprint, 0x3442193e); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1279,7 +1279,7 @@ START_TEST(test_bip32_vector_1) { fromhex( "edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1293,7 +1293,7 @@ START_TEST(test_bip32_vector_1) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1309,7 +1309,7 @@ START_TEST(test_bip32_vector_1) { // [Chain m/0'/1] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 1); - ck_assert_int_eq(fingerprint, 0x5c1bd648); + ck_assert_uint_eq(fingerprint, 0x5c1bd648); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1320,7 +1320,7 @@ START_TEST(test_bip32_vector_1) { fromhex( "3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1334,7 +1334,7 @@ START_TEST(test_bip32_vector_1) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1350,7 +1350,7 @@ START_TEST(test_bip32_vector_1) { // [Chain m/0'/1/2'] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd_prime(&node, 2); - ck_assert_int_eq(fingerprint, 0xbef5a2f9); + ck_assert_uint_eq(fingerprint, 0xbef5a2f9); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1361,7 +1361,7 @@ START_TEST(test_bip32_vector_1) { fromhex( "cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1375,7 +1375,7 @@ START_TEST(test_bip32_vector_1) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1391,7 +1391,7 @@ START_TEST(test_bip32_vector_1) { // [Chain m/0'/1/2'/2] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 2); - ck_assert_int_eq(fingerprint, 0xee7ab90c); + ck_assert_uint_eq(fingerprint, 0xee7ab90c); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1402,7 +1402,7 @@ START_TEST(test_bip32_vector_1) { fromhex( "0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1416,7 +1416,7 @@ START_TEST(test_bip32_vector_1) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1432,7 +1432,7 @@ START_TEST(test_bip32_vector_1) { // [Chain m/0'/1/2'/2/1000000000] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 1000000000); - ck_assert_int_eq(fingerprint, 0xd880d7d8); + ck_assert_uint_eq(fingerprint, 0xd880d7d8); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1443,7 +1443,7 @@ START_TEST(test_bip32_vector_1) { fromhex( "471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1457,7 +1457,7 @@ START_TEST(test_bip32_vector_1) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1489,7 +1489,7 @@ START_TEST(test_bip32_vector_2) { // [Chain m] fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_uint_eq(fingerprint, 0x00000000); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1500,7 +1500,7 @@ START_TEST(test_bip32_vector_2) { fromhex( "4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1514,7 +1514,7 @@ START_TEST(test_bip32_vector_2) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1531,7 +1531,7 @@ START_TEST(test_bip32_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 0); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0xbd16bee5); + ck_assert_uint_eq(fingerprint, 0xbd16bee5); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1542,7 +1542,7 @@ START_TEST(test_bip32_vector_2) { fromhex( "abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1556,7 +1556,7 @@ START_TEST(test_bip32_vector_2) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1573,7 +1573,7 @@ START_TEST(test_bip32_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 2147483647); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x5a61ff8e); + ck_assert_uint_eq(fingerprint, 0x5a61ff8e); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1584,7 +1584,7 @@ START_TEST(test_bip32_vector_2) { fromhex( "877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1598,7 +1598,7 @@ START_TEST(test_bip32_vector_2) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1615,7 +1615,7 @@ START_TEST(test_bip32_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 1); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0xd8ab4937); + ck_assert_uint_eq(fingerprint, 0xd8ab4937); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1626,7 +1626,7 @@ START_TEST(test_bip32_vector_2) { fromhex( "704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1640,7 +1640,7 @@ START_TEST(test_bip32_vector_2) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1657,7 +1657,7 @@ START_TEST(test_bip32_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 2147483646); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x78412e3a); + ck_assert_uint_eq(fingerprint, 0x78412e3a); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1668,7 +1668,7 @@ START_TEST(test_bip32_vector_2) { fromhex( "f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1682,7 +1682,7 @@ START_TEST(test_bip32_vector_2) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1699,7 +1699,7 @@ START_TEST(test_bip32_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 2); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x31a507b8); + ck_assert_uint_eq(fingerprint, 0x31a507b8); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1710,7 +1710,7 @@ START_TEST(test_bip32_vector_2) { fromhex( "bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1724,7 +1724,7 @@ START_TEST(test_bip32_vector_2) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1749,7 +1749,7 @@ START_TEST(test_bip32_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_public_ckd(&node, 0); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0xbd16bee5); + ck_assert_uint_eq(fingerprint, 0xbd16bee5); ck_assert_mem_eq( node.chain_code, fromhex( @@ -1760,7 +1760,7 @@ START_TEST(test_bip32_vector_2) { fromhex( "0000000000000000000000000000000000000000000000000000000000000000"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -1786,8 +1786,8 @@ START_TEST(test_bip32_vector_3) { // [Chain m] fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); - hdnode_fill_public_key(&node); + ck_assert_uint_eq(fingerprint, 0x00000000); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, @@ -1796,7 +1796,7 @@ START_TEST(test_bip32_vector_3) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1813,7 +1813,7 @@ START_TEST(test_bip32_vector_3) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 0); ck_assert_int_eq(r, 1); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, @@ -1822,7 +1822,7 @@ START_TEST(test_bip32_vector_3) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1854,7 +1854,7 @@ START_TEST(test_bip32_vector_4) { // [Chain m] fingerprint = 0; ck_assert_int_eq(fingerprint, 0x00000000); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, @@ -1863,7 +1863,7 @@ START_TEST(test_bip32_vector_4) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1880,7 +1880,7 @@ START_TEST(test_bip32_vector_4) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 0); ck_assert_int_eq(r, 1); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, sizeof(str)); ck_assert_str_eq(str, @@ -1889,7 +1889,7 @@ START_TEST(test_bip32_vector_4) { r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); ck_assert_str_eq(str, @@ -1901,6 +1901,32 @@ START_TEST(test_bip32_vector_4) { memcpy(&node3, &node, sizeof(HDNode)); memzero(&node3.private_key, 32); ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); + + // [Chain m/0'/1'] + fingerprint = hdnode_fingerprint(&node); + r = hdnode_private_ckd_prime(&node, 1); + ck_assert_int_eq(r, 1); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); + hdnode_serialize_private(&node, fingerprint, VERSION_PRIVATE, str, + sizeof(str)); + ck_assert_str_eq(str, + "xprv9xJocDuwtYCMNAo3Zw76WENQeAS6WGXQ55RCy7tDJ8oALr4FWkuVoHJ" + "eHVAcAqiZLE7Je3vZJHxspZdFHfnBEjHqU5hG1Jaj32dVoS6XLT1"); + r = hdnode_deserialize_private(str, VERSION_PRIVATE, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); + ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); + hdnode_serialize_public(&node, fingerprint, VERSION_PUBLIC, str, sizeof(str)); + ck_assert_str_eq(str, + "xpub6BJA1jSqiukeaesWfxe6sNK9CCGaujFFSJLomWHprUL9DePQ4JDkM5d" + "88n49sMGJxrhpjazuXYWdMf17C9T5XnxkopaeS7jGk1GyyVziaMt"); + r = hdnode_deserialize_public(str, VERSION_PUBLIC, SECP256K1_NAME, &node2, + NULL); + ck_assert_int_eq(r, 0); + memcpy(&node3, &node, sizeof(HDNode)); + memzero(&node3.private_key, 32); + ck_assert_mem_eq(&node2, &node3, sizeof(HDNode)); } END_TEST @@ -1917,20 +1943,20 @@ START_TEST(test_bip32_compare) { "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, SECP256K1_NAME, &node2); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); for (i = 0; i < 100; i++) { memcpy(&node3, &node1, sizeof(HDNode)); - hdnode_fill_public_key(&node3); + ck_assert_int_eq(hdnode_fill_public_key(&node3), 0); r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); r = hdnode_public_ckd(&node2, i); ck_assert_int_eq(r, 1); r = hdnode_public_ckd(&node3, i); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node1.depth, node2.depth); - ck_assert_int_eq(node1.depth, node3.depth); - ck_assert_int_eq(node1.child_num, node2.child_num); - ck_assert_int_eq(node1.child_num, node3.child_num); + ck_assert_uint_eq(node1.depth, node2.depth); + ck_assert_uint_eq(node1.depth, node3.depth); + ck_assert_uint_eq(node1.child_num, node2.child_num); + ck_assert_uint_eq(node1.child_num, node3.child_num); ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); ck_assert_mem_eq( @@ -1943,7 +1969,7 @@ START_TEST(test_bip32_compare) { fromhex( "0000000000000000000000000000000000000000000000000000000000000000"), 32); - hdnode_fill_public_key(&node1); + ck_assert_int_eq(hdnode_fill_public_key(&node1), 0); ck_assert_mem_eq(node1.public_key, node2.public_key, 33); ck_assert_mem_eq(node1.public_key, node3.public_key, 33); } @@ -1953,7 +1979,7 @@ END_TEST START_TEST(test_bip32_optimized) { HDNode root; hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); - hdnode_fill_public_key(&root); + ck_assert_int_eq(hdnode_fill_public_key(&root), 0); curve_point pub; ecdsa_read_pubkey(&secp256k1, root.public_key, &pub); @@ -1965,7 +1991,7 @@ START_TEST(test_bip32_optimized) { // unoptimized memcpy(&node, &root, sizeof(HDNode)); hdnode_public_ckd(&node, i); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ecdsa_get_address(node.public_key, 0, HASHER_SHA2_RIPEMD, HASHER_SHA2D, addr1, sizeof(addr1)); // optimized @@ -1978,7 +2004,8 @@ START_TEST(test_bip32_optimized) { } END_TEST -#if USE_BIP32_CACHE // [wallet-core] +#if USE_BIP32_CACHE + START_TEST(test_bip32_cache_1) { HDNode node1, node2; int i, r; @@ -2112,7 +2139,7 @@ START_TEST(test_bip32_nist_seed) { fromhex( "7762f9729fed06121fd13f326884c82f59aa95c57ac492ce8c9654e60efd130c"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2136,7 +2163,7 @@ START_TEST(test_bip32_nist_seed) { fromhex( "0e49dc46ce1d8c29d9b80a05e40f5d0cd68cbf02ae98572186f5343be18084bf"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2155,7 +2182,7 @@ START_TEST(test_bip32_nist_vector_1) { // [Chain m] fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_uint_eq(fingerprint, 0x00000000); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2166,7 +2193,7 @@ START_TEST(test_bip32_nist_vector_1) { fromhex( "612091aaa12e22dd2abef664f8a01a82cae99ad7441b7ef8110424915c268bc2"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2176,7 +2203,7 @@ START_TEST(test_bip32_nist_vector_1) { // [Chain m/0'] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(fingerprint, 0xbe6105b5); + ck_assert_uint_eq(fingerprint, 0xbe6105b5); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2187,7 +2214,7 @@ START_TEST(test_bip32_nist_vector_1) { fromhex( "6939694369114c67917a182c59ddb8cafc3004e63ca5d3b84403ba8613debc0c"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2197,7 +2224,7 @@ START_TEST(test_bip32_nist_vector_1) { // [Chain m/0'/1] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 1); - ck_assert_int_eq(fingerprint, 0x9b02312f); + ck_assert_uint_eq(fingerprint, 0x9b02312f); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2208,7 +2235,7 @@ START_TEST(test_bip32_nist_vector_1) { fromhex( "284e9d38d07d21e4e281b645089a94f4cf5a5a81369acf151a1c3a57f18b2129"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2218,7 +2245,7 @@ START_TEST(test_bip32_nist_vector_1) { // [Chain m/0'/1/2'] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd_prime(&node, 2); - ck_assert_int_eq(fingerprint, 0xb98005c1); + ck_assert_uint_eq(fingerprint, 0xb98005c1); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2229,7 +2256,7 @@ START_TEST(test_bip32_nist_vector_1) { fromhex( "694596e8a54f252c960eb771a3c41e7e32496d03b954aeb90f61635b8e092aa7"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2239,7 +2266,7 @@ START_TEST(test_bip32_nist_vector_1) { // [Chain m/0'/1/2'/2] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 2); - ck_assert_int_eq(fingerprint, 0x0e9f3274); + ck_assert_uint_eq(fingerprint, 0x0e9f3274); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2250,7 +2277,7 @@ START_TEST(test_bip32_nist_vector_1) { fromhex( "5996c37fd3dd2679039b23ed6f70b506c6b56b3cb5e424681fb0fa64caf82aaa"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2260,7 +2287,7 @@ START_TEST(test_bip32_nist_vector_1) { // [Chain m/0'/1/2'/2/1000000000] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 1000000000); - ck_assert_int_eq(fingerprint, 0x8b2b5c4b); + ck_assert_uint_eq(fingerprint, 0x8b2b5c4b); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2271,7 +2298,7 @@ START_TEST(test_bip32_nist_vector_1) { fromhex( "21c4f269ef0a5fd1badf47eeacebeeaa3de22eb8e5b0adcd0f27dd99d34d0119"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2294,7 +2321,7 @@ START_TEST(test_bip32_nist_vector_2) { // [Chain m] fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_uint_eq(fingerprint, 0x00000000); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2305,7 +2332,7 @@ START_TEST(test_bip32_nist_vector_2) { fromhex( "eaa31c2e46ca2962227cf21d73a7ef0ce8b31c756897521eb6c7b39796633357"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2316,7 +2343,7 @@ START_TEST(test_bip32_nist_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 0); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x607f628f); + ck_assert_uint_eq(fingerprint, 0x607f628f); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2327,7 +2354,7 @@ START_TEST(test_bip32_nist_vector_2) { fromhex( "d7d065f63a62624888500cdb4f88b6d59c2927fee9e6d0cdff9cad555884df6e"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2338,7 +2365,7 @@ START_TEST(test_bip32_nist_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 2147483647); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x946d2a54); + ck_assert_uint_eq(fingerprint, 0x946d2a54); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2349,7 +2376,7 @@ START_TEST(test_bip32_nist_vector_2) { fromhex( "96d2ec9316746a75e7793684ed01e3d51194d81a42a3276858a5b7376d4b94b9"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2360,7 +2387,7 @@ START_TEST(test_bip32_nist_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 1); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x218182d8); + ck_assert_uint_eq(fingerprint, 0x218182d8); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2371,7 +2398,7 @@ START_TEST(test_bip32_nist_vector_2) { fromhex( "974f9096ea6873a915910e82b29d7c338542ccde39d2064d1cc228f371542bbc"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2382,7 +2409,7 @@ START_TEST(test_bip32_nist_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 2147483646); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x931223e4); + ck_assert_uint_eq(fingerprint, 0x931223e4); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2393,7 +2420,7 @@ START_TEST(test_bip32_nist_vector_2) { fromhex( "da29649bbfaff095cd43819eda9a7be74236539a29094cd8336b07ed8d4eff63"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2404,7 +2431,7 @@ START_TEST(test_bip32_nist_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 2); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x956c4629); + ck_assert_uint_eq(fingerprint, 0x956c4629); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2415,7 +2442,7 @@ START_TEST(test_bip32_nist_vector_2) { fromhex( "bb0a77ba01cc31d77205d51d08bd313b979a71ef4de9b062f8958297e746bd67"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2434,7 +2461,7 @@ START_TEST(test_bip32_nist_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_public_ckd(&node, 0); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x607f628f); + ck_assert_uint_eq(fingerprint, 0x607f628f); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2466,20 +2493,20 @@ START_TEST(test_bip32_nist_compare) { "301133282ad079cbeb59bc446ad39d333928f74c46997d3609cd3e2801ca69d62788" "f9f174429946ff4e9be89f67c22fae28cb296a9b37734f75e73d1477af19"), 64, NIST256P1_NAME, &node2); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); for (i = 0; i < 100; i++) { memcpy(&node3, &node1, sizeof(HDNode)); - hdnode_fill_public_key(&node3); + ck_assert_int_eq(hdnode_fill_public_key(&node3), 0); r = hdnode_private_ckd(&node1, i); ck_assert_int_eq(r, 1); r = hdnode_public_ckd(&node2, i); ck_assert_int_eq(r, 1); r = hdnode_public_ckd(&node3, i); ck_assert_int_eq(r, 1); - ck_assert_int_eq(node1.depth, node2.depth); - ck_assert_int_eq(node1.depth, node3.depth); - ck_assert_int_eq(node1.child_num, node2.child_num); - ck_assert_int_eq(node1.child_num, node3.child_num); + ck_assert_uint_eq(node1.depth, node2.depth); + ck_assert_uint_eq(node1.depth, node3.depth); + ck_assert_uint_eq(node1.child_num, node2.child_num); + ck_assert_uint_eq(node1.child_num, node3.child_num); ck_assert_mem_eq(node1.chain_code, node2.chain_code, 32); ck_assert_mem_eq(node1.chain_code, node3.chain_code, 32); ck_assert_mem_eq( @@ -2492,7 +2519,7 @@ START_TEST(test_bip32_nist_compare) { fromhex( "0000000000000000000000000000000000000000000000000000000000000000"), 32); - hdnode_fill_public_key(&node1); + ck_assert_int_eq(hdnode_fill_public_key(&node1), 0); ck_assert_mem_eq(node1.public_key, node2.public_key, 33); ck_assert_mem_eq(node1.public_key, node3.public_key, 33); } @@ -2512,7 +2539,7 @@ START_TEST(test_bip32_nist_repeat) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 28578); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0xbe6105b5); + ck_assert_uint_eq(fingerprint, 0xbe6105b5); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2523,7 +2550,7 @@ START_TEST(test_bip32_nist_repeat) { fromhex( "06f0db126f023755d0b8d86d4591718a5210dd8d024e3e14b6159d63f53aa669"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2534,7 +2561,7 @@ START_TEST(test_bip32_nist_repeat) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node2, 33941); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x3e2b7bc6); + ck_assert_uint_eq(fingerprint, 0x3e2b7bc6); ck_assert_mem_eq( node2.chain_code, fromhex( @@ -2545,7 +2572,7 @@ START_TEST(test_bip32_nist_repeat) { fromhex( "092154eed4af83e078ff9b84322015aefe5769e31270f62c3f66c33888335f3a"), 32); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq( node2.public_key, fromhex( @@ -2556,13 +2583,13 @@ START_TEST(test_bip32_nist_repeat) { memzero(&node2.private_key, 32); r = hdnode_public_ckd(&node2, 33941); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x3e2b7bc6); + ck_assert_uint_eq(fingerprint, 0x3e2b7bc6); ck_assert_mem_eq( node2.chain_code, fromhex( "9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071"), 32); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq( node2.public_key, fromhex( @@ -2590,7 +2617,7 @@ START_TEST(test_bip32_ed25519_vector_1) { fromhex( "2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2609,7 +2636,7 @@ START_TEST(test_bip32_ed25519_vector_1) { fromhex( "68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2628,7 +2655,7 @@ START_TEST(test_bip32_ed25519_vector_1) { fromhex( "b1d0bad404bf35da785a64ca1ac54b2617211d2777696fbffaf208f746ae84f2"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2647,7 +2674,7 @@ START_TEST(test_bip32_ed25519_vector_1) { fromhex( "92a5b23c0b8a99e37d07df3fb9966917f5d06e02ddbd909c7e184371463e9fc9"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2666,7 +2693,7 @@ START_TEST(test_bip32_ed25519_vector_1) { fromhex( "30d1dc7e5fc04c31219ab25a27ae00b50f6fd66622f6e9c913253d6511d1e662"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2685,7 +2712,7 @@ START_TEST(test_bip32_ed25519_vector_1) { fromhex( "8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2717,7 +2744,7 @@ START_TEST(test_bip32_ed25519_vector_2) { fromhex( "171cb88b1b3c1db25add599712e36245d75bc65a1a5c9e18d76f9f2b1eab4012"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2737,7 +2764,7 @@ START_TEST(test_bip32_ed25519_vector_2) { fromhex( "1559eb2bbec5790b0c65d8693e4d0875b1747f4970ae8b650486ed7470845635"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2757,7 +2784,7 @@ START_TEST(test_bip32_ed25519_vector_2) { fromhex( "ea4f5bfe8694d8bb74b7b59404632fd5968b774ed545e810de9c32a4fb4192f4"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2777,7 +2804,7 @@ START_TEST(test_bip32_ed25519_vector_2) { fromhex( "3757c7577170179c7868353ada796c839135b3d30554bbb74a4b1e4a5a58505c"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2797,7 +2824,7 @@ START_TEST(test_bip32_ed25519_vector_2) { fromhex( "5837736c89570de861ebc173b1086da4f505d4adb387c6a1b1342d5e4ac9ec72"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2817,7 +2844,7 @@ START_TEST(test_bip32_ed25519_vector_2) { fromhex( "551d333177df541ad876a60ea71f00447931c0a9da16f227c11ea080d7391b8d"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2844,7 +2871,7 @@ START_TEST(test_bip32_decred_vector_1) { // [Chain m] fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_uint_eq(fingerprint, 0x00000000); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2855,7 +2882,7 @@ START_TEST(test_bip32_decred_vector_1) { fromhex( "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2870,7 +2897,7 @@ START_TEST(test_bip32_decred_vector_1) { SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); @@ -2887,7 +2914,7 @@ START_TEST(test_bip32_decred_vector_1) { // [Chain m/0'] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd_prime(&node, 0); - ck_assert_int_eq(fingerprint, 0xbc495588); + ck_assert_uint_eq(fingerprint, 0xbc495588); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2898,7 +2925,7 @@ START_TEST(test_bip32_decred_vector_1) { fromhex( "edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2912,7 +2939,7 @@ START_TEST(test_bip32_decred_vector_1) { r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); @@ -2929,7 +2956,7 @@ START_TEST(test_bip32_decred_vector_1) { // [Chain m/0'/1] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 1); - ck_assert_int_eq(fingerprint, 0xc67bc2ef); + ck_assert_uint_eq(fingerprint, 0xc67bc2ef); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2940,7 +2967,7 @@ START_TEST(test_bip32_decred_vector_1) { fromhex( "3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2954,7 +2981,7 @@ START_TEST(test_bip32_decred_vector_1) { r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); @@ -2971,7 +2998,7 @@ START_TEST(test_bip32_decred_vector_1) { // [Chain m/0'/1/2'] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd_prime(&node, 2); - ck_assert_int_eq(fingerprint, 0xe7072187); + ck_assert_uint_eq(fingerprint, 0xe7072187); ck_assert_mem_eq( node.chain_code, fromhex( @@ -2982,7 +3009,7 @@ START_TEST(test_bip32_decred_vector_1) { fromhex( "cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -2996,7 +3023,7 @@ START_TEST(test_bip32_decred_vector_1) { r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); @@ -3013,7 +3040,7 @@ START_TEST(test_bip32_decred_vector_1) { // [Chain m/0'/1/2'/2] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 2); - ck_assert_int_eq(fingerprint, 0xbcbbc1c4); + ck_assert_uint_eq(fingerprint, 0xbcbbc1c4); ck_assert_mem_eq( node.chain_code, fromhex( @@ -3024,7 +3051,7 @@ START_TEST(test_bip32_decred_vector_1) { fromhex( "0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -3038,7 +3065,7 @@ START_TEST(test_bip32_decred_vector_1) { r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); @@ -3055,7 +3082,7 @@ START_TEST(test_bip32_decred_vector_1) { // [Chain m/0'/1/2'/2/1000000000] fingerprint = hdnode_fingerprint(&node); hdnode_private_ckd(&node, 1000000000); - ck_assert_int_eq(fingerprint, 0xe58b52e4); + ck_assert_uint_eq(fingerprint, 0xe58b52e4); ck_assert_mem_eq( node.chain_code, fromhex( @@ -3066,7 +3093,7 @@ START_TEST(test_bip32_decred_vector_1) { fromhex( "471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -3080,7 +3107,7 @@ START_TEST(test_bip32_decred_vector_1) { r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); @@ -3117,7 +3144,7 @@ START_TEST(test_bip32_decred_vector_2) { // [Chain m] fingerprint = 0; - ck_assert_int_eq(fingerprint, 0x00000000); + ck_assert_uint_eq(fingerprint, 0x00000000); ck_assert_mem_eq( node.chain_code, fromhex( @@ -3128,7 +3155,7 @@ START_TEST(test_bip32_decred_vector_2) { fromhex( "4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -3142,7 +3169,7 @@ START_TEST(test_bip32_decred_vector_2) { r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); @@ -3160,7 +3187,7 @@ START_TEST(test_bip32_decred_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 0); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x2524c9d3); + ck_assert_uint_eq(fingerprint, 0x2524c9d3); ck_assert_mem_eq( node.chain_code, fromhex( @@ -3171,7 +3198,7 @@ START_TEST(test_bip32_decred_vector_2) { fromhex( "abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -3185,7 +3212,7 @@ START_TEST(test_bip32_decred_vector_2) { r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); @@ -3203,7 +3230,7 @@ START_TEST(test_bip32_decred_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 2147483647); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x6035c6ad); + ck_assert_uint_eq(fingerprint, 0x6035c6ad); ck_assert_mem_eq( node.chain_code, fromhex( @@ -3214,7 +3241,7 @@ START_TEST(test_bip32_decred_vector_2) { fromhex( "877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -3228,7 +3255,7 @@ START_TEST(test_bip32_decred_vector_2) { r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); @@ -3246,7 +3273,7 @@ START_TEST(test_bip32_decred_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 1); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x36fc7080); + ck_assert_uint_eq(fingerprint, 0x36fc7080); ck_assert_mem_eq( node.chain_code, fromhex( @@ -3257,7 +3284,7 @@ START_TEST(test_bip32_decred_vector_2) { fromhex( "704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -3271,7 +3298,7 @@ START_TEST(test_bip32_decred_vector_2) { r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); @@ -3289,7 +3316,7 @@ START_TEST(test_bip32_decred_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd_prime(&node, 2147483646); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x45309b4c); + ck_assert_uint_eq(fingerprint, 0x45309b4c); ck_assert_mem_eq( node.chain_code, fromhex( @@ -3300,7 +3327,7 @@ START_TEST(test_bip32_decred_vector_2) { fromhex( "f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -3314,7 +3341,7 @@ START_TEST(test_bip32_decred_vector_2) { r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); @@ -3332,7 +3359,7 @@ START_TEST(test_bip32_decred_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_private_ckd(&node, 2); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x3491a5e6); + ck_assert_uint_eq(fingerprint, 0x3491a5e6); ck_assert_mem_eq( node.chain_code, fromhex( @@ -3343,7 +3370,7 @@ START_TEST(test_bip32_decred_vector_2) { fromhex( "bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key, fromhex( @@ -3357,7 +3384,7 @@ START_TEST(test_bip32_decred_vector_2) { r = hdnode_deserialize_private(str, DECRED_VERSION_PRIVATE, SECP256K1_DECRED_NAME, &node2, NULL); ck_assert_int_eq(r, 0); - hdnode_fill_public_key(&node2); + ck_assert_int_eq(hdnode_fill_public_key(&node2), 0); ck_assert_mem_eq(&node, &node2, sizeof(HDNode)); hdnode_serialize_public(&node, fingerprint, DECRED_VERSION_PUBLIC, str, sizeof(str)); @@ -3382,7 +3409,7 @@ START_TEST(test_bip32_decred_vector_2) { fingerprint = hdnode_fingerprint(&node); r = hdnode_public_ckd(&node, 0); ck_assert_int_eq(r, 1); - ck_assert_int_eq(fingerprint, 0x6a19cfb3); + ck_assert_uint_eq(fingerprint, 0x6a19cfb3); ck_assert_mem_eq( node.chain_code, fromhex( @@ -3405,33 +3432,79 @@ START_TEST(test_bip32_decred_vector_2) { } END_TEST -START_TEST(test_ecdsa_signature) { - int res; - uint8_t digest[32]; - uint8_t pubkey[65]; - uint8_t sig[64]; +static void test_ecdsa_get_public_key33_helper(int (*ecdsa_get_public_key33_fn)( + const ecdsa_curve *, const uint8_t *, uint8_t *)) { + uint8_t privkey[32] = {0}; + uint8_t pubkey[65] = {0}; const ecdsa_curve *curve = &secp256k1; + int res = 0; - // Signature verification for a digest which is equal to the group order. - // https://github.com/trezor/trezor-firmware/pull/1374 memcpy( + privkey, + fromhex( + "c46f5b217f04ff28886a89d3c762ed84e5fa318d1c9a635d541131e69f1f49f5"), + 32); + res = ecdsa_get_public_key33_fn(curve, privkey, pubkey); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( pubkey, fromhex( - "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179848" - "3ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"), - sizeof(pubkey)); + "0232b062e9153f573c220b1be0299d6447e81577274bf11a7c08dff71384c6b6ec"), + 33); + memcpy( - digest, + privkey, fromhex( - "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), - sizeof(digest)); - memcpy(sig, - fromhex( - "a0b37f8fba683cc68f6574cd43b39f0343a50008bf6ccea9d13231d9e7e2e1e41" - "1edc8d307254296264aebfc3dc76cd8b668373a072fd64665b50000e9fcce52"), - sizeof(sig)); - res = ecdsa_verify_digest(curve, pubkey, sig, digest); + "3b90a4de80fb00d77795762c389d1279d4b4ab5992ae3cde6bc12ca63116f74c"), + 32); + res = ecdsa_get_public_key33_fn(curve, privkey, pubkey); ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "0332b062e9153f573c220b1be0299d6447e81577274bf11a7c08dff71384c6b6ec"), + 33); +} + +START_TEST(test_ecdsa_get_public_key33) { + test_ecdsa_get_public_key33_helper(ecdsa_get_public_key33); +} +END_TEST + +static void test_ecdsa_get_public_key65_helper(int (*ecdsa_get_public_key65_fn)( + const ecdsa_curve *, const uint8_t *, uint8_t *)) { + uint8_t privkey[32] = {0}; + uint8_t pubkey[65] = {0}; + const ecdsa_curve *curve = &secp256k1; + int res = 0; + + memcpy( + privkey, + fromhex( + "c46f5b217f04ff28886a89d3c762ed84e5fa318d1c9a635d541131e69f1f49f5"), + 32); + res = ecdsa_get_public_key65_fn(curve, privkey, pubkey); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq( + pubkey, + fromhex( + "0432b062e9153f573c220b1be0299d6447e81577274bf11a7c08dff71384c6b6ec" + "179ca56b637a57e0fcd28cefa10c9433dc30532682647f4daa053d43d5cc960a"), + 65); +} + +START_TEST(test_ecdsa_get_public_key65) { + test_ecdsa_get_public_key65_helper(ecdsa_get_public_key65); +} +END_TEST + +static void test_ecdsa_recover_pub_from_sig_helper(int ( + *ecdsa_recover_pub_from_sig_fn)(const ecdsa_curve *, uint8_t *, + const uint8_t *, const uint8_t *, int)) { + int res; + uint8_t digest[32]; + uint8_t pubkey[65]; + const ecdsa_curve *curve = &secp256k1; // sha2(sha2("\x18Bitcoin Signed Message:\n\x0cHello World!")) memcpy( @@ -3440,7 +3513,7 @@ START_TEST(test_ecdsa_signature) { "de4e9524586d6fce45667f9ff12f661e79870c4105fa0fb58af976619bb11432"), 32); // r = 2: Four points should exist - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "00000000000000000000000000000000000000000000000000000000000000020123" @@ -3453,7 +3526,7 @@ START_TEST(test_ecdsa_signature) { "043fc5bf5fec35b6ffe6fd246226d312742a8c296bfa57dd22da509a2e348529b7dd" "b9faf8afe1ecda3c05e7b2bda47ee1f5a87e952742b22afca560b29d972fcf"), 65); - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "00000000000000000000000000000000000000000000000000000000000000020123" @@ -3466,7 +3539,7 @@ START_TEST(test_ecdsa_signature) { "0456d8089137b1fd0d890f8c7d4a04d0fd4520a30b19518ee87bd168ea12ed809032" "9274c4c6c0d9df04515776f2741eeffc30235d596065d718c3973e19711ad0"), 65); - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "00000000000000000000000000000000000000000000000000000000000000020123" @@ -3479,7 +3552,7 @@ START_TEST(test_ecdsa_signature) { "04cee0e740f41aab39156844afef0182dea2a8026885b10454a2d539df6f6df9023a" "bfcb0f01c50bef3c0fa8e59a998d07441e18b1c60583ef75cc8b912fb21a15"), 65); - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "00000000000000000000000000000000000000000000000000000000000000020123" @@ -3492,6 +3565,14 @@ START_TEST(test_ecdsa_signature) { "0490d2bd2e9a564d6e1d8324fc6ad00aa4ae597684ecf4abea58bdfe7287ea4fa729" "68c2e5b0b40999ede3d7898d94e82c3f8dc4536a567a4bd45998c826a4c4b2"), 65); + // The point at infinity is not considered to be a valid public key. + res = ecdsa_recover_pub_from_sig_fn( + curve, pubkey, + fromhex( + "220cf4c7b6d568f2256a8c30cc1784a625a28c3627dac404aa9a9ecd08314ec81a88" + "828f20d69d102bab5de5f6ee7ef040cb0ff7b8e1ba3f29d79efb5250f47d"), + digest, 0); + ck_assert_int_eq(res, 1); memcpy( digest, @@ -3499,7 +3580,7 @@ START_TEST(test_ecdsa_signature) { "0000000000000000000000000000000000000000000000000000000000000000"), 32); // r = 7: No point P with P.x = 7, but P.x = (order + 7) exists - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "00000000000000000000000000000000000000000000000000000000000000070123" @@ -3512,7 +3593,7 @@ START_TEST(test_ecdsa_signature) { "044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b040" "de78f8dbda700f4d3cd7ee21b3651a74c7661809699d2be7ea0992b0d39797"), 65); - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "00000000000000000000000000000000000000000000000000000000000000070123" @@ -3525,7 +3606,7 @@ START_TEST(test_ecdsa_signature) { "044d81bb47a31ffc6cf1f780ecb1e201ec47214b651650867c07f13ad06e12a1b0bf" "21870724258ff0b2c32811de4c9ae58b3899e7f69662d41815f66c4f2c6498"), 65); - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "00000000000000000000000000000000000000000000000000000000000000070123" @@ -3539,7 +3620,7 @@ START_TEST(test_ecdsa_signature) { "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), 32); // r = 1: Two points P with P.x = 1, but P.x = (order + 7) doesn't exist - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "00000000000000000000000000000000000000000000000000000000000000010123" @@ -3552,7 +3633,7 @@ START_TEST(test_ecdsa_signature) { "045d330b2f89dbfca149828277bae852dd4aebfe136982cb531a88e9e7a89463fe71" "519f34ea8feb9490c707f14bc38c9ece51762bfd034ea014719b7c85d2871b"), 65); - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "00000000000000000000000000000000000000000000000000000000000000010123" @@ -3567,14 +3648,14 @@ START_TEST(test_ecdsa_signature) { 65); // r = 0 is always invalid - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "00000000000000000000000000000000000000000000000000000000000000010123" "456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), digest, 2); ck_assert_int_eq(res, 1); - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "00000000000000000000000000000000000000000000000000000000000000000123" @@ -3582,7 +3663,7 @@ START_TEST(test_ecdsa_signature) { digest, 0); ck_assert_int_eq(res, 1); // r >= order is always invalid - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410123" @@ -3590,7 +3671,7 @@ START_TEST(test_ecdsa_signature) { digest, 0); ck_assert_int_eq(res, 1); // check that overflow of r is handled - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "000000000000000000000000000000014551231950B75FC4402DA1722FC9BAEE0123" @@ -3598,7 +3679,7 @@ START_TEST(test_ecdsa_signature) { digest, 2); ck_assert_int_eq(res, 1); // s = 0 is always invalid - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "00000000000000000000000000000000000000000000000000000000000000020000" @@ -3606,7 +3687,7 @@ START_TEST(test_ecdsa_signature) { digest, 0); ck_assert_int_eq(res, 1); // s >= order is always invalid - res = ecdsa_recover_pub_from_sig( + res = ecdsa_recover_pub_from_sig_fn( curve, pubkey, fromhex( "0000000000000000000000000000000000000000000000000000000000000002ffff" @@ -3614,12 +3695,51 @@ START_TEST(test_ecdsa_signature) { digest, 0); ck_assert_int_eq(res, 1); } + +START_TEST(test_ecdsa_recover_pub_from_sig) { + test_ecdsa_recover_pub_from_sig_helper(ecdsa_recover_pub_from_sig); +} +END_TEST + +static void test_ecdsa_verify_digest_helper(int (*ecdsa_verify_digest_fn)( + const ecdsa_curve *, const uint8_t *, const uint8_t *, const uint8_t *)) { + int res; + uint8_t digest[32]; + uint8_t pubkey[65]; + uint8_t sig[64]; + const ecdsa_curve *curve = &secp256k1; + + // Signature verification for a digest which is equal to the group order. + // https://github.com/trezor/trezor-firmware/pull/1374 + memcpy( + pubkey, + fromhex( + "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179848" + "3ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"), + sizeof(pubkey)); + memcpy( + digest, + fromhex( + "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), + sizeof(digest)); + memcpy(sig, + fromhex( + "a0b37f8fba683cc68f6574cd43b39f0343a50008bf6ccea9d13231d9e7e2e1e41" + "1edc8d307254296264aebfc3dc76cd8b668373a072fd64665b50000e9fcce52"), + sizeof(sig)); + res = ecdsa_verify_digest_fn(curve, pubkey, sig, digest); + ck_assert_int_eq(res, 0); +} + +START_TEST(test_ecdsa_verify_digest) { + test_ecdsa_verify_digest_helper(ecdsa_verify_digest); +} END_TEST #define test_deterministic(KEY, MSG, K) \ do { \ sha256_Raw((uint8_t *)MSG, strlen(MSG), buf); \ - init_rfc6979(fromhex(KEY), buf, &rng); \ + init_rfc6979(fromhex(KEY), buf, NULL, &rng); \ generate_k_rfc6979(&k, &rng); \ bn_write_be(&k, buf); \ ck_assert_mem_eq(buf, fromhex(K), 32); \ @@ -3664,6 +3784,49 @@ START_TEST(test_rfc6979) { } END_TEST +static void test_ecdsa_sign_digest_deterministic_helper( + int (*ecdsa_sign_digest_fn)(const ecdsa_curve *, const uint8_t *, + const uint8_t *, uint8_t *, uint8_t *, + int (*)(uint8_t by, uint8_t sig[64]))) { + static struct { + const char *priv_key; + const char *digest; + const char *sig; + } tests[] = { + {"312155017c70a204106e034520e0cdf17b3e54516e2ece38e38e38e38e38e38e", + "ffffffffffffffffffffffffffffffff20202020202020202020202020202020", + "e3d70248ea2fc771fc8d5e62d76b9cfd5402c96990333549eaadce1ae9f737eb" + "5cfbdc7d1e0ec18cc9b57bbb18f0a57dc929ec3c4dfac9073c581705015f6a8a"}, + {"312155017c70a204106e034520e0cdf17b3e54516e2ece38e38e38e38e38e38e", + "2020202020202020202020202020202020202020202020202020202020202020", + "40666188895430715552a7e4c6b53851f37a93030fb94e043850921242db78e8" + "75aa2ac9fd7e5a19402973e60e64382cdc29a09ebf6cb37e92f23be5b9251aee"}, + }; + + const ecdsa_curve *curve = &secp256k1; + uint8_t priv_key[32] = {0}; + uint8_t digest[32] = {0}; + uint8_t expected_sig[64] = {0}; + uint8_t computed_sig[64] = {0}; + int res = 0; + + for (size_t i = 0; i < sizeof(tests) / sizeof(*tests); i++) { + memcpy(priv_key, fromhex(tests[i].priv_key), 32); + memcpy(digest, fromhex(tests[i].digest), 32); + memcpy(expected_sig, fromhex(tests[i].sig), 64); + + res = + ecdsa_sign_digest_fn(curve, priv_key, digest, computed_sig, NULL, NULL); + ck_assert_int_eq(res, 0); + ck_assert_mem_eq(expected_sig, computed_sig, 64); + } +} + +START_TEST(test_ecdsa_sign_digest_deterministic) { + test_ecdsa_sign_digest_deterministic_helper(ecdsa_sign_digest); +} +END_TEST + // test vectors from // http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors START_TEST(test_aes) { @@ -3673,7 +3836,7 @@ START_TEST(test_aes) { const char **ivp, **plainp, **cipherp; // ECB - const char *ecb_vector[] = { + static const char *ecb_vector[] = { // plain cipher "6bc1bee22e409f96e93d7e117393172a", "f3eed1bdb5d2a03c064b5a7e3db181f8", @@ -3710,7 +3873,7 @@ START_TEST(test_aes) { } // CBC - const char *cbc_vector[] = { + static const char *cbc_vector[] = { // iv plain cipher "000102030405060708090A0B0C0D0E0F", "6bc1bee22e409f96e93d7e117393172a", @@ -3756,7 +3919,7 @@ START_TEST(test_aes) { } // CFB - const char *cfb_vector[] = { + static const char *cfb_vector[] = { "000102030405060708090A0B0C0D0E0F", "6bc1bee22e409f96e93d7e117393172a", "DC7E84BFDA79164B7ECD8486985D3860", @@ -3801,7 +3964,7 @@ START_TEST(test_aes) { } // OFB - const char *ofb_vector[] = { + static const char *ofb_vector[] = { "000102030405060708090A0B0C0D0E0F", "6bc1bee22e409f96e93d7e117393172a", "dc7e84bfda79164b7ecd8486985d3860", @@ -3846,7 +4009,7 @@ START_TEST(test_aes) { } // CTR - const char *ctr_vector[] = { + static const char *ctr_vector[] = { // plain cipher "6bc1bee22e409f96e93d7e117393172a", "601ec313775789a5b7a7f504bbf3d228", @@ -4171,84 +4334,101 @@ END_TEST // test vectors from http://www.di-mgt.com.au/sha_testvectors.html START_TEST(test_sha3_256) { - uint8_t digest[SHA3_256_DIGEST_LENGTH]; - - sha3_256((uint8_t *)"", 0, digest); - ck_assert_mem_eq( - digest, - fromhex( - "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"), - SHA3_256_DIGEST_LENGTH); - - sha3_256((uint8_t *)"abc", 3, digest); - ck_assert_mem_eq( - digest, - fromhex( - "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"), - SHA3_256_DIGEST_LENGTH); - - sha3_256( - (uint8_t *)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, - digest); - ck_assert_mem_eq( - digest, - fromhex( - "41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376"), - SHA3_256_DIGEST_LENGTH); + static const struct { + const char *data; + const char *hash; + } tests[] = { + { + "", + "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", + }, + { + "abc", + "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", + }, + { + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376", + }, + { + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijkl" + "mnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", + }, + }; - sha3_256((uint8_t *)"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, digest); - ck_assert_mem_eq( - digest, - fromhex( - "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18"), - SHA3_256_DIGEST_LENGTH); + uint8_t digest[SHA3_256_DIGEST_LENGTH]; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t len = strlen(tests[i].data); + sha3_256((uint8_t *)tests[i].data, len, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); + + // Test progressive hashing. + size_t part_len = len; + SHA3_CTX ctx; + sha3_256_Init(&ctx); + sha3_Update(&ctx, (uint8_t *)tests[i].data, part_len); + sha3_Update(&ctx, NULL, 0); + sha3_Update(&ctx, (uint8_t *)tests[i].data + part_len, len - part_len); + sha3_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); + } } END_TEST // test vectors from http://www.di-mgt.com.au/sha_testvectors.html START_TEST(test_sha3_512) { - uint8_t digest[SHA3_512_DIGEST_LENGTH]; - - sha3_512((uint8_t *)"", 0, digest); - ck_assert_mem_eq( - digest, - fromhex( + static const struct { + const char *data; + const char *hash; + } tests[] = { + { + "", "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2" - "123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"), - SHA3_512_DIGEST_LENGTH); - - sha3_512((uint8_t *)"abc", 3, digest); - ck_assert_mem_eq( - digest, - fromhex( + "123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", + }, + { + "abc", "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e1" - "16e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"), - SHA3_512_DIGEST_LENGTH); - - sha3_512( - (uint8_t *)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, - digest); - ck_assert_mem_eq( - digest, - fromhex( + "16e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0", + }, + { + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee69" - "1fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e"), - SHA3_512_DIGEST_LENGTH); - - sha3_512((uint8_t *)"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, digest); - ck_assert_mem_eq( - digest, - fromhex( + "1fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e", + }, + { + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijkl" + "mnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3" - "261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185"), - SHA3_512_DIGEST_LENGTH); + "261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185", + }, + }; + + uint8_t digest[SHA3_512_DIGEST_LENGTH]; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t len = strlen(tests[i].data); + sha3_512((uint8_t *)tests[i].data, len, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), SHA3_512_DIGEST_LENGTH); + + // Test progressive hashing. + size_t part_len = len; + SHA3_CTX ctx; + sha3_512_Init(&ctx); + sha3_Update(&ctx, (const uint8_t *)tests[i].data, part_len); + sha3_Update(&ctx, NULL, 0); + sha3_Update(&ctx, (const uint8_t *)tests[i].data + part_len, + len - part_len); + sha3_Final(&ctx, digest); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), SHA3_512_DIGEST_LENGTH); + } } END_TEST // test vectors from // https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/0.test-sha3-256.dat START_TEST(test_keccak_256) { - const struct { + static const struct { const char *hash; size_t length; const char *data; @@ -4490,6 +4670,17 @@ START_TEST(test_keccak_256) { for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { keccak_256(fromhex(tests[i].data), tests[i].length, hash); ck_assert_mem_eq(hash, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); + + // Test progressive hashing. + size_t part_len = tests[i].length / 2; + SHA3_CTX ctx = {0}; + keccak_256_Init(&ctx); + keccak_Update(&ctx, fromhex(tests[i].data), part_len); + keccak_Update(&ctx, fromhex(tests[i].data), 0); + keccak_Update(&ctx, fromhex(tests[i].data) + part_len, + tests[i].length - part_len); + keccak_Final(&ctx, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), SHA3_256_DIGEST_LENGTH); } } END_TEST @@ -4497,7 +4688,7 @@ END_TEST // test vectors from // https://raw.githubusercontent.com/monero-project/monero/master/tests/hash/tests-extra-blake.txt START_TEST(test_blake256) { - struct { + static const struct { const char *hash; const char *data; } tests[] = { @@ -4586,7 +4777,18 @@ START_TEST(test_blake256) { uint8_t hash[BLAKE256_DIGEST_LENGTH]; for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { - blake256(fromhex(tests[i].data), i, hash); + size_t len = strlen(tests[i].data) / 2; + blake256(fromhex(tests[i].data), len, hash); + ck_assert_mem_eq(hash, fromhex(tests[i].hash), BLAKE256_DIGEST_LENGTH); + + // Test progressive hashing. + size_t part_len = len / 2; + BLAKE256_CTX ctx; + blake256_Init(&ctx); + blake256_Update(&ctx, fromhex(tests[i].data), part_len); + blake256_Update(&ctx, NULL, 0); + blake256_Update(&ctx, fromhex(tests[i].data) + part_len, len - part_len); + blake256_Final(&ctx, hash); ck_assert_mem_eq(hash, fromhex(tests[i].hash), BLAKE256_DIGEST_LENGTH); } } @@ -4595,6 +4797,36 @@ END_TEST // test vectors from // https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2b-kat.txt START_TEST(test_blake2b) { + static const struct { + const char *msg; + const char *hash; + } tests[] = { + { + "", + "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e9" + "96e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568", + }, + { + "000102", + "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e" + "364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f3031323334353637", + "f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e7684" + "2d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243" + "4445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465" + "666768696a6b6c6d6e6f", + "227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c5" + "28fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f", + }, + }; + uint8_t key[BLAKE2B_KEY_LENGTH]; memcpy(key, fromhex( @@ -4603,54 +4835,111 @@ START_TEST(test_blake2b) { BLAKE2B_KEY_LENGTH); uint8_t digest[BLAKE2B_DIGEST_LENGTH]; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t msg_len = strlen(tests[i].msg) / 2; + blake2b_Key(fromhex(tests[i].msg), msg_len, key, sizeof(key), digest, + sizeof(digest)); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), sizeof(digest)); + + // Test progressive hashing. + size_t part_len = msg_len / 2; + BLAKE2B_CTX ctx; + ck_assert_int_eq(blake2b_InitKey(&ctx, sizeof(digest), key, sizeof(key)), + 0); + ck_assert_int_eq(blake2b_Update(&ctx, fromhex(tests[i].msg), part_len), 0); + ck_assert_int_eq(blake2b_Update(&ctx, NULL, 0), 0); + ck_assert_int_eq(blake2b_Update(&ctx, fromhex(tests[i].msg) + part_len, + msg_len - part_len), + 0); + ck_assert_int_eq(blake2b_Final(&ctx, digest, sizeof(digest)), 0); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), BLAKE2B_DIGEST_LENGTH); + } +} +END_TEST - blake2b_Key((uint8_t *)"", 0, key, BLAKE2B_KEY_LENGTH, digest, - BLAKE2B_DIGEST_LENGTH); - ck_assert_mem_eq( - digest, - fromhex( - "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e9" - "96e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568"), - BLAKE2B_DIGEST_LENGTH); - - blake2b_Key(fromhex("000102"), 3, key, BLAKE2B_KEY_LENGTH, digest, - BLAKE2B_DIGEST_LENGTH); - ck_assert_mem_eq( - digest, - fromhex( - "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e" - "364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1"), - BLAKE2B_DIGEST_LENGTH); +// Blake2b-256 personalized, a la ZCash +// Test vectors from https://zips.z.cash/zip-0243 +START_TEST(test_blake2bp) { + static const struct { + const char *msg; + const char *personal; + const char *hash; + } tests[] = { + { + "", + "ZcashPrevoutHash", + "d53a633bbecf82fe9e9484d8a0e727c73bb9e68c96e72dec30144f6a84afa136", + }, + { + "", + "ZcashSequencHash", + "a5f25f01959361ee6eb56a7401210ee268226f6ce764a4f10b7f29e54db37272", - blake2b_Key( - fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f3031323334353637"), - 56, key, BLAKE2B_KEY_LENGTH, digest, BLAKE2B_DIGEST_LENGTH); - ck_assert_mem_eq( - digest, - fromhex( - "f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e7684" - "2d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2"), - BLAKE2B_DIGEST_LENGTH); + }, + { + "e7719811893e0000095200ac6551ac636565b2835a0805750200025151", + "ZcashOutputsHash", + "ab6f7f6c5ad6b56357b5f37e16981723db6c32411753e28c175e15589172194a", + }, + { + "0bbe32a598c22adfb48cef72ba5d4287c0cefbacfd8ce195b4963c34a94bba7a1" + "75dae4b090f47a068e227433f9e49d3aa09e356d8d66d0c0121e91a3c4aa3f27fa1b" + "63396e2b41d", + "ZcashPrevoutHash", + "cacf0f5210cce5fa65a59f314292b3111d299e7d9d582753cf61e1e408552ae4", + }}; - blake2b_Key( - fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" - "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" - "606162636465666768696a6b6c6d6e6f"), - 112, key, BLAKE2B_KEY_LENGTH, digest, BLAKE2B_DIGEST_LENGTH); - ck_assert_mem_eq( - digest, - fromhex( - "227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c5" - "28fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f"), - BLAKE2B_DIGEST_LENGTH); + uint8_t digest[32]; + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t msg_len = strlen(tests[i].msg) / 2; + + // Test progressive hashing. + size_t part_len = msg_len / 2; + BLAKE2B_CTX ctx; + ck_assert_int_eq( + blake2b_InitPersonal(&ctx, sizeof(digest), tests[i].personal, + strlen(tests[i].personal)), + 0); + ck_assert_int_eq(blake2b_Update(&ctx, fromhex(tests[i].msg), part_len), 0); + ck_assert_int_eq(blake2b_Update(&ctx, NULL, 0), 0); + ck_assert_int_eq(blake2b_Update(&ctx, fromhex(tests[i].msg) + part_len, + msg_len - part_len), + 0); + ck_assert_int_eq(blake2b_Final(&ctx, digest, sizeof(digest)), 0); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), sizeof(digest)); + } } END_TEST // test vectors from // https://raw.githubusercontent.com/BLAKE2/BLAKE2/master/testvectors/blake2s-kat.txt START_TEST(test_blake2s) { + static const struct { + const char *msg; + const char *hash; + } tests[] = { + { + "", + "48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49", + }, + { + "000102", + "1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f3031323334353637", + "2966b3cfae1e44ea996dc5d686cf25fa053fb6f67201b9e46eade85d0ad6b806", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" + "22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243" + "4445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465" + "666768696a6b6c6d6e6f", + "90a83585717b75f0e9b725e055eeeeb9e7a028ea7e6cbc07b20917ec0363e38c", + }, + }; + uint8_t key[BLAKE2S_KEY_LENGTH]; memcpy( key, @@ -4659,62 +4948,64 @@ START_TEST(test_blake2s) { BLAKE2S_KEY_LENGTH); uint8_t digest[BLAKE2S_DIGEST_LENGTH]; - - blake2s_Key((uint8_t *)"", 0, key, BLAKE2S_KEY_LENGTH, digest, - BLAKE2S_DIGEST_LENGTH); - ck_assert_mem_eq( - digest, - fromhex( - "48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49"), - BLAKE2S_DIGEST_LENGTH); - - blake2s_Key(fromhex("000102"), 3, key, BLAKE2S_KEY_LENGTH, digest, - BLAKE2S_DIGEST_LENGTH); - ck_assert_mem_eq( - digest, - fromhex( - "1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b"), - BLAKE2S_DIGEST_LENGTH); - - blake2s_Key( - fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f3031323334353637"), - 56, key, BLAKE2S_KEY_LENGTH, digest, BLAKE2S_DIGEST_LENGTH); - ck_assert_mem_eq( - digest, - fromhex( - "2966b3cfae1e44ea996dc5d686cf25fa053fb6f67201b9e46eade85d0ad6b806"), - BLAKE2S_DIGEST_LENGTH); - - blake2s_Key( - fromhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" - "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" - "606162636465666768696a6b6c6d6e6f"), - 112, key, BLAKE2S_KEY_LENGTH, digest, BLAKE2S_DIGEST_LENGTH); - ck_assert_mem_eq( - digest, - fromhex( - "90a83585717b75f0e9b725e055eeeeb9e7a028ea7e6cbc07b20917ec0363e38c"), - BLAKE2S_DIGEST_LENGTH); + for (size_t i = 0; i < (sizeof(tests) / sizeof(*tests)); i++) { + size_t msg_len = strlen(tests[i].msg) / 2; + blake2s_Key(fromhex(tests[i].msg), msg_len, key, sizeof(key), digest, + sizeof(digest)); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), sizeof(digest)); + + // Test progressive hashing. + size_t part_len = msg_len / 2; + BLAKE2S_CTX ctx; + ck_assert_int_eq(blake2s_InitKey(&ctx, sizeof(digest), key, sizeof(key)), + 0); + ck_assert_int_eq(blake2s_Update(&ctx, fromhex(tests[i].msg), part_len), 0); + ck_assert_int_eq(blake2s_Update(&ctx, NULL, 0), 0); + ck_assert_int_eq(blake2s_Update(&ctx, fromhex(tests[i].msg) + part_len, + msg_len - part_len), + 0); + ck_assert_int_eq(blake2s_Final(&ctx, digest, sizeof(digest)), 0); + ck_assert_mem_eq(digest, fromhex(tests[i].hash), BLAKE2S_DIGEST_LENGTH); + } } END_TEST +#include + START_TEST(test_chacha_drbg) { - char entropy[] = "8a09b482de30c12ee1d2eb69dd49753d4252b3d36128ee1e"; - char reseed[] = "9ec4b991f939dbb44355392d05cd793a2e281809d2ed7139"; + char entropy[] = + "06032cd5eed33f39265f49ecb142c511da9aff2af71203bffaf34a9ca5bd9c0d"; + char nonce[] = "0e66f71edc43e42a45ad3c6fc6cdc4df"; + char reseed[] = + "01920a4e669ed3a85ae8a33b35a74ad7fb2a6bb4cf395ce00334a9c9a5a5d552"; char expected[] = - "4caaeb7db073d34b37b5b26f8a3863849f298dab754966e0f75526823216057c2626e044" - "9f7ffda7c3dba8841c06af01029eebfd4d4cae951c19c9f6ff6812783e58438840883401" - "2a05cd24c38cd22d18296aceed6829299190ebb9455eb8fd8d1cac1d"; - uint8_t result[100]; + "e172c5d18f3e8c77e9f66f9e1c24560772117161a9a0a237ab490b0769ad5d910f5dfb36" + "22edc06c18be0495c52588b200893d90fd80ff2149ead0c45d062c90f5890149c0f9591c" + "41bf4110865129a0fe524f210cca1340bd16f71f57906946cbaaf1fa863897d70d203b5a" + "f9996f756eec08861ee5875f9d915adcddc38719"; + uint8_t result[128]; + uint8_t null_bytes[128] = {0}; + uint8_t nonce_bytes[16]; + memcpy(nonce_bytes, fromhex(nonce), sizeof(nonce_bytes)); CHACHA_DRBG_CTX ctx; - chacha_drbg_init(&ctx, fromhex(entropy)); - chacha_drbg_reseed(&ctx, fromhex(reseed)); + chacha_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, + strlen(nonce) / 2); + chacha_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); chacha_drbg_generate(&ctx, result, sizeof(result)); chacha_drbg_generate(&ctx, result, sizeof(result)); ck_assert_mem_eq(result, fromhex(expected), sizeof(result)); + + for (size_t i = 0; i <= sizeof(result); ++i) { + chacha_drbg_init(&ctx, fromhex(entropy), strlen(entropy) / 2, nonce_bytes, + strlen(nonce) / 2); + chacha_drbg_reseed(&ctx, fromhex(reseed), strlen(reseed) / 2, NULL, 0); + chacha_drbg_generate(&ctx, result, sizeof(result) - 13); + memset(result, 0, sizeof(result)); + chacha_drbg_generate(&ctx, result, i); + ck_assert_mem_eq(result, fromhex(expected), i); + ck_assert_mem_eq(result + i, null_bytes, sizeof(result) - i); + } } END_TEST @@ -4853,7 +5144,7 @@ START_TEST(test_hmac_drbg) { END_TEST START_TEST(test_mnemonic) { - const char *vectors[] = { + static const char *vectors[] = { "00000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon " "abandon abandon about", @@ -4990,10 +5281,10 @@ START_TEST(test_mnemonic) { a = vectors; b = vectors + 1; c = vectors + 2; - const size_t bufSize = 300; // large enough to hold 24 long words - char buf[bufSize]; + int buf_size = 308; + char buf[buf_size]; while (*a && *b && *c) { - m = mnemonic_from_data(fromhex(*a), strlen(*a) / 2, buf, bufSize); + m = mnemonic_from_data(fromhex(*a), strlen(*a) / 2, buf, buf_size); ck_assert_str_eq(m, *b); mnemonic_to_seed(m, "TREZOR", seed, 0); ck_assert_mem_eq(seed, fromhex(*c), strlen(*c) / 2); @@ -5005,17 +5296,13 @@ START_TEST(test_mnemonic) { a += 3; b += 3; c += 3; + memzero(buf, buf_size); } - - // [wallet-core] negative test: provided buffer invalid (too small or null) - ck_assert_int_eq((int)(mnemonic_from_data(fromhex(vectors[0]), strlen(vectors[0]) / 2, buf, 200)), 0); - ck_assert_int_eq((int)(mnemonic_from_data(fromhex(vectors[0]), strlen(vectors[0]) / 2, buf, 0)), 0); - ck_assert_int_eq((int)(mnemonic_from_data(fromhex(vectors[0]), strlen(vectors[0]) / 2, NULL, 240)), 0); } END_TEST START_TEST(test_mnemonic_check) { - const char *vectors_ok[] = { + static const char *vectors_ok[] = { "abandon abandon abandon abandon abandon abandon abandon abandon abandon " "abandon abandon about", "legal winner thank year wave sausage worth useful legal winner thank " @@ -5071,7 +5358,7 @@ START_TEST(test_mnemonic_check) { "away coconut", 0, }; - const char *vectors_fail[] = { + static const char *vectors_fail[] = { "above abandon abandon abandon abandon abandon abandon abandon abandon " "abandon abandon about", "above winner thank year wave sausage worth useful legal winner thank " @@ -5194,7 +5481,7 @@ START_TEST(test_mnemonic_check) { END_TEST START_TEST(test_mnemonic_to_bits) { - const char *vectors[] = { + static const char *vectors[] = { "00000000000000000000000000000000", "abandon abandon abandon abandon abandon abandon abandon abandon abandon " "abandon abandon about", @@ -5285,7 +5572,7 @@ START_TEST(test_mnemonic_to_bits) { int mnemonic_bits_len = mnemonic_to_bits(*b, mnemonic_bits); ck_assert_int_eq(mnemonic_bits_len % 33, 0); mnemonic_bits_len = mnemonic_bits_len * 4 / 33; - ck_assert_int_eq(mnemonic_bits_len, strlen(*a) / 2); + ck_assert_uint_eq((size_t)mnemonic_bits_len, strlen(*a) / 2); ck_assert_mem_eq(mnemonic_bits, fromhex(*a), mnemonic_bits_len); a += 2; b += 2; @@ -5296,7 +5583,7 @@ END_TEST START_TEST(test_mnemonic_find_word) { ck_assert_int_eq(-1, mnemonic_find_word("aaaa")); ck_assert_int_eq(-1, mnemonic_find_word("zzzz")); - for (int i = 0; i < BIP39_WORDS; i++) { + for (int i = 0; i < BIP39_WORD_COUNT; i++) { const char *word = mnemonic_get_word(i); int index = mnemonic_find_word(word); ck_assert_int_eq(i, index); @@ -5304,9 +5591,8 @@ START_TEST(test_mnemonic_find_word) { } END_TEST -/* // [wallet-core] START_TEST(test_slip39_get_word) { - const struct { + static const struct { const int index; const char *expected_word; } vectors[] = {{573, "member"}, @@ -5323,7 +5609,7 @@ END_TEST START_TEST(test_slip39_word_index) { uint16_t index; - const struct { + static const struct { const char *word; bool expected_result; uint16_t expected_index; @@ -5335,17 +5621,17 @@ START_TEST(test_slip39_word_index) { // 9999 value is never checked since the word is not in list {"fakeword", false, 9999}}; for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); i++) { - bool result = word_index(&index, vectors[i].word, sizeof(vectors[i].word)); + bool result = word_index(&index, vectors[i].word, strlen(vectors[i].word)); ck_assert_int_eq(result, vectors[i].expected_result); if (result) { - ck_assert_int_eq(index, vectors[i].expected_index); + ck_assert_uint_eq(index, vectors[i].expected_index); } } } END_TEST START_TEST(test_slip39_word_completion_mask) { - const struct { + static const struct { const uint16_t prefix; const uint16_t expected_mask; } vectors[] = { @@ -5364,13 +5650,13 @@ START_TEST(test_slip39_word_completion_mask) { }; for (size_t i = 0; i < (sizeof(vectors) / sizeof(*vectors)); i++) { uint16_t mask = slip39_word_completion_mask(vectors[i].prefix); - ck_assert_int_eq(mask, vectors[i].expected_mask); + ck_assert_uint_eq(mask, vectors[i].expected_mask); } } END_TEST START_TEST(test_slip39_sequence_to_word) { - const struct { + static const struct { const uint16_t prefix; const char *expected_word; } vectors[] = { @@ -5405,11 +5691,10 @@ START_TEST(test_slip39_word_completion) { } } END_TEST -*/ START_TEST(test_shamir) { #define SHAMIR_MAX_COUNT 16 - const struct { + static const struct { const uint8_t result[SHAMIR_MAX_LEN]; uint8_t result_index; const uint8_t share_indices[SHAMIR_MAX_COUNT]; @@ -5937,7 +6222,7 @@ START_TEST(test_address_decode) { END_TEST START_TEST(test_ecdsa_der) { - const struct { + static const struct { const char *r; const char *s; const char *der; @@ -5997,6 +6282,11 @@ START_TEST(test_ecdsa_der) { "00000000000000000000000000000000000000000000000000000000000000ff", "3008020200ee020200ff", }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + "3006020100020100", + }, }; uint8_t sig[64]; @@ -6146,11 +6436,11 @@ static void test_point_mult_curve(const ecdsa_curve *curve) { /* test distributivity: (a + b)P = aP + bP */ bn_mod(&a, &curve->order); bn_mod(&b, &curve->order); - point_multiply(curve, &a, &p, &p1); - point_multiply(curve, &b, &p, &p2); + ck_assert_int_eq(point_multiply(curve, &a, &p, &p1), 0); + ck_assert_int_eq(point_multiply(curve, &b, &p, &p2), 0); bn_addmod(&a, &b, &curve->order); bn_mod(&a, &curve->order); - point_multiply(curve, &a, &p, &p3); + ck_assert_int_eq(point_multiply(curve, &a, &p, &p3), 0); point_add(curve, &p1, &p2); ck_assert_mem_eq(&p2, &p3, sizeof(curve_point)); // new "random" numbers and a "random" point @@ -6177,17 +6467,17 @@ static void test_scalar_point_mult_curve(const ecdsa_curve *curve) { */ bn_mod(&a, &curve->order); bn_mod(&b, &curve->order); - scalar_multiply(curve, &a, &p1); - point_multiply(curve, &b, &p1, &p1); + ck_assert_int_eq(scalar_multiply(curve, &a, &p1), 0); + ck_assert_int_eq(point_multiply(curve, &b, &p1, &p1), 0); - scalar_multiply(curve, &b, &p2); - point_multiply(curve, &a, &p2, &p2); + ck_assert_int_eq(scalar_multiply(curve, &b, &p2), 0); + ck_assert_int_eq(point_multiply(curve, &a, &p2, &p2), 0); ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); bn_multiply(&a, &b, &curve->order); bn_mod(&b, &curve->order); - scalar_multiply(curve, &b, &p2); + ck_assert_int_eq(scalar_multiply(curve, &b, &p2), 0); ck_assert_mem_eq(&p1, &p2, sizeof(curve_point)); @@ -6209,7 +6499,7 @@ END_TEST START_TEST(test_ed25519) { // test vectors from // https://github.com/torproject/tor/blob/master/src/test/ed25519_vectors.inc - const char *vectors[] = { + static const char *vectors[] = { "26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d3" "6", // secret "c2247870536a192d142d056abefca68d6193158e7c1a59c1654c954eccaff89" @@ -6285,7 +6575,7 @@ START_TEST(test_ed25519) { UNMARK_SECRET_DATA(pk, sizeof(pk)); ck_assert_mem_eq(pk, fromhex(*spk), 32); - ed25519_sign(pk, 32, sk, pk, sig); + ed25519_sign(pk, 32, sk, sig); UNMARK_SECRET_DATA(sig, sizeof(sig)); ck_assert_mem_eq(sig, fromhex(*ssig), 64); @@ -6301,7 +6591,7 @@ END_TEST // test vectors from // https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/2.test-sign.dat START_TEST(test_ed25519_keccak) { - const struct { + static const struct { const char *private_key; const char *public_key; const char *signature; @@ -6503,7 +6793,7 @@ START_TEST(test_ed25519_keccak) { ck_assert_mem_eq(public_key, fromhex(tests[i].public_key), 32); ed25519_sign_keccak(fromhex(tests[i].data), tests[i].length, private_key, - public_key, signature); + signature); UNMARK_SECRET_DATA(signature, sizeof(signature)); ck_assert_mem_eq(signature, fromhex(tests[i].signature), 64); @@ -6528,7 +6818,7 @@ START_TEST(test_ed25519_cosi) { "26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36"), fromhex( "26659c1cf7321c178c07437150639ff0c5b7679c7ea195253ed9abda2e081a37"), - &rng); + NULL, &rng); for (int N = 1; N < 11; N++) { ed25519_public_key pk; @@ -6735,7 +7025,8 @@ START_TEST(test_ed25519_modl_sub) { } END_TEST -#if USE_MONERO // [wallet-core] +#if USE_MONERO + START_TEST(test_ge25519_double_scalarmult_vartime2) { char tests[][5][65] = { {"c537208ed4985e66e9f7a35c9a69448a732ba93960bbbd2823604f7ae9e3ed08", @@ -6859,13 +7150,14 @@ START_TEST(test_ge25519_double_scalarmult_vartime2) { } } END_TEST + #endif static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, const char *curve_name) { hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, node); - hdnode_fill_public_key(node); + ck_assert_int_eq(hdnode_fill_public_key(node), 0); if (node->public_key[0] == 1) { node->public_key[0] = 0x40; // Curve25519 public keys start with 0x40 byte } @@ -6933,7 +7225,7 @@ START_TEST(test_bip32_ecdh_errors) { END_TEST START_TEST(test_output_script) { - const char *vectors[] = { + static const char *vectors[] = { "76A914010966776006953D5567439E5E39F86A0D273BEE88AC", "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", "A914010966776006953D5567439E5E39F86A0D273BEE87", @@ -6952,7 +7244,7 @@ START_TEST(test_output_script) { while (*scr && *adr) { int r = script_output_to_address(fromhex(*scr), strlen(*scr) / 2, address, 60); - ck_assert_int_eq(r, (int)(strlen(*adr) + 1)); + ck_assert_uint_eq((size_t)r, strlen(*adr) + 1); ck_assert_str_eq(address, *adr); scr += 2; adr += 2; @@ -6961,6 +7253,7 @@ START_TEST(test_output_script) { END_TEST #if USE_ETHEREUM + START_TEST(test_ethereum_pubkeyhash) { uint8_t pubkeyhash[20]; int res; @@ -7062,25 +7355,25 @@ START_TEST(test_ethereum_pubkeyhash) { END_TEST START_TEST(test_ethereum_address) { - const char *vectors[] = {"52908400098527886E0F7030069857D2E4169EE7", - "8617E340B3D01FA5F11F306F4090FD50E238070D", - "de709f2102306220921060314715629080e2fb77", - "27b1fdb04752bbc536007a920d24acb045561c26", - "5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", - "fB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", - "dbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", - "D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", - "5A4EAB120fB44eb6684E5e32785702FF45ea344D", - "5be4BDC48CeF65dbCbCaD5218B1A7D37F58A0741", - "a7dD84573f5ffF821baf2205745f768F8edCDD58", - "027a49d11d118c0060746F1990273FcB8c2fC196", - "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", + static const char *vectors[] = {"0x52908400098527886E0F7030069857D2E4169EE7", + "0x8617E340B3D01FA5F11F306F4090FD50E238070D", + "0xde709f2102306220921060314715629080e2fb77", + "0x27b1fdb04752bbc536007a920d24acb045561c26", + "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", + "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", + "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", + "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", + "0x5A4EAB120fB44eb6684E5e32785702FF45ea344D", + "0x5be4BDC48CeF65dbCbCaD5218B1A7D37F58A0741", + "0xa7dD84573f5ffF821baf2205745f768F8edCDD58", + "0x027a49d11d118c0060746F1990273FcB8c2fC196", + "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", 0}; uint8_t addr[20]; - char address[41]; + char address[43]; const char **vec = vectors; while (*vec) { - memcpy(addr, fromhex(*vec), 20); + memcpy(addr, fromhex(*vec + 2), 20); ethereum_address_checksum(addr, address, false, 0); ck_assert_str_eq(address, *vec); vec++; @@ -7092,42 +7385,43 @@ END_TEST // https://github.com/rsksmart/RSKIPs/blob/master/IPs/RSKIP60.md START_TEST(test_rsk_address) { uint8_t addr[20]; - char address[41]; + char address[43]; - const char *rskip60_chain30[] = { - "5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD", - "Fb6916095cA1Df60bb79ce92cE3EA74c37c5d359", - "DBF03B407c01E7CD3cBea99509D93F8Dddc8C6FB", - "D1220A0Cf47c7B9BE7a2e6ba89F429762E7B9adB", 0}; + static const char *rskip60_chain30[] = { + "0x5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD", + "0xFb6916095cA1Df60bb79ce92cE3EA74c37c5d359", + "0xDBF03B407c01E7CD3cBea99509D93F8Dddc8C6FB", + "0xD1220A0Cf47c7B9BE7a2e6ba89F429762E7B9adB", 0}; const char **vec = rskip60_chain30; while (*vec) { - memcpy(addr, fromhex(*vec), 20); + memcpy(addr, fromhex(*vec + 2), 20); ethereum_address_checksum(addr, address, true, 30); ck_assert_str_eq(address, *vec); vec++; } - const char *rskip60_chain31[] = { - "5aAeb6053F3e94c9b9A09F33669435E7EF1BEaEd", - "Fb6916095CA1dF60bb79CE92ce3Ea74C37c5D359", - "dbF03B407C01E7cd3cbEa99509D93f8dDDc8C6fB", - "d1220a0CF47c7B9Be7A2E6Ba89f429762E7b9adB", 0}; + static const char *rskip60_chain31[] = { + "0x5aAeb6053F3e94c9b9A09F33669435E7EF1BEaEd", + "0xFb6916095CA1dF60bb79CE92ce3Ea74C37c5D359", + "0xdbF03B407C01E7cd3cbEa99509D93f8dDDc8C6fB", + "0xd1220a0CF47c7B9Be7A2E6Ba89f429762E7b9adB", 0}; vec = rskip60_chain31; while (*vec) { - memcpy(addr, fromhex(*vec), 20); + memcpy(addr, fromhex(*vec + 2), 20); ethereum_address_checksum(addr, address, true, 31); ck_assert_str_eq(address, *vec); vec++; } } END_TEST + #endif #if USE_NEM // test vectors from // https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/1.test-keys.dat START_TEST(test_nem_address) { - const struct { + static const struct { const char *private_key; const char *public_key; const char *address; @@ -7256,7 +7550,7 @@ END_TEST // test vectors from // https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/3.test-derive.dat START_TEST(test_nem_derive) { - const struct { + static const struct { const char *salt; const char *private_key; const char *public_key; @@ -7430,7 +7724,7 @@ END_TEST // test vectors from // https://raw.githubusercontent.com/NemProject/nem-test-vectors/master/4.test-cipher.dat START_TEST(test_nem_cipher) { - const struct { + static const struct { const char *private_key; const char *public_key; const char *salt; @@ -7691,13 +7985,13 @@ START_TEST(test_nem_cipher) { memcpy(iv, fromhex(tests[i].iv), sizeof(iv)); ck_assert(hdnode_nem_encrypt(&node, public_key, iv, salt, input, input_size, buffer)); - ck_assert_int_eq(output_size, NEM_ENCRYPTED_SIZE(input_size)); + ck_assert_uint_eq(output_size, NEM_ENCRYPTED_SIZE(input_size)); ck_assert_mem_eq(buffer, output, output_size); memcpy(iv, fromhex(tests[i].iv), sizeof(iv)); ck_assert(hdnode_nem_decrypt(&node, public_key, iv, salt, output, output_size, buffer)); - ck_assert_int_eq(input_size, NEM_DECRYPTED_SIZE(buffer, output_size)); + ck_assert_uint_eq(input_size, NEM_DECRYPTED_SIZE(buffer, output_size)); ck_assert_mem_eq(buffer, input, input_size); } } @@ -8401,11 +8695,11 @@ END_TEST // https://tools.ietf.org/html/rfc6229#section-2 START_TEST(test_rc4_rfc6229) { - const size_t offsets[] = { + static const size_t offsets[] = { 0x0, 0xf0, 0x1f0, 0x2f0, 0x3f0, 0x5f0, 0x7f0, 0xbf0, 0xff0, }; - const struct { + static const struct { char key[65]; char vectors[sizeof(offsets) / sizeof(*offsets)][65]; } tests[] = { @@ -8725,7 +9019,7 @@ static void test_compress_coord(const char *k_raw) { } START_TEST(test_compress_coords) { - const char *k_raw[] = { + static const char *k_raw[] = { "dc05960ac673fd59554c98655e26722d007bb7ada0c8ff00883fdee70783d0be", "41e41e0a218c980411108a0a58cf88f528c828b4d6f0d2c86234bc2504bdc3cd", "1d963ddcb79f6028a32cadd2421ff7fff969bff5774f73063dab41519b3da175", @@ -8743,219 +9037,6 @@ START_TEST(test_compress_coords) { } END_TEST -// [wallet-core] -START_TEST(test_schnorr_sign_verify) { - static struct { - const char *message; - const char *priv_key; - const char *k_hex; - const char *s_hex; - const char *r_hex; - } test_cases[] = { - { - "123", - "3382266517e2ebe6df51faf4bfe612236ad46fb8bd59ac982a223b045e080ac6", - "669301F724C555D7BB1185C04909E9CACA3EC7A292B3A1C92DDCCD5A5A7DDDD3", - "FFD72C290B98C93A4BCEDC0EDCDF040C35579BE962FE83E6821D4F3CB4B795D2", - "74AAE9C3E069E2806E1B0D890970BE387AEBED8040F37991AACAD70B27895E39", - }, - { - "1234", - "51a2758eed776c40b367364909c8a9c98cc969104f69ff316f7a287495c37c9b", - "A0A1A9B3570AAE963535B8D4376C58A61646C18182C9FDDA5FB13703F88D4D1E", - "99A0CB942C81571B77C682F79CD3CB663CE9E1C55BB425BA24B9F11A0DE84FE2", - "C3C10363E38158BBA20556A36DE9358DFD81A31C180ABC9E7617C1CC1CAF03B3", - }, - { - "12345", - "2685adffdbb4b2c515054cffc25cfcbfe2e462df65bbe82fb50f71e1e68dd285", - "38DE7B3315F201433D271E91FBE62966576CA05CBFEC1770B77D7EC9D6A01D6D", - "28982FA6C2B620CBC550F7EF9EAB605F409C584FBE5A765678877B79AB517086", - "9A0788E5B0947DEDEDE386DF57A006CF3FE43919A74D9CA630F8A1A9D97B4650", - }, - { - "fun", - "7457dc574d927e5dae84b05264a5b637b5a68e34a85b3965084ed6fed5b7f12d", - "E005ABD242C7C602AB5EED080C5083C7C5F8DAEC6D046A54F384A8B8CDECF740", - "51070ABCA039DAC294F6BA3BFC8C36CFC66020EDF66D1ACF1A9B545B0BF09F52", - "330A924525EF722FA20E8E25CB6E8BD7DF4394886FA4414E4A0B6812AA25BBC0", - }, - { - "funny", - "52c395a6d304de1a959e73e4604e32c5ad3f2bf01c8f730af426b38d7d5dd908", - "0CF28B5C40A8830F3195BB99A9F0E2808F576105F41D16ABCF596AC5A8CFE88A", - "3D60FB4664C994AD956378B9402BC68F7B4799D74F4783A6199C0D74865EA2B6", - "5ED5EDEE0314DFFBEE39EE4E9C76DE8BC3EB8CB891AEC32B83957514284B205B", - }, - { - "What is great in man is that he is a bridge and not a goal", - "52c395a6d304de1a959e73e4604e32c5ad3f2bf01c8f730af426b38d7d5dd908", - "000000000000000000000000000000000000000000000000000000000000007B", - "546F70AA1FEE3718C95508240CDC073B9FEFED05959C5319DD8E2BF07A1DD028", - "B8667BE5E10B113608BFE5327C44E9F0462BE26F789177E10DCE53019AA33DAA", - }, - { - "123456789147258369qwertyuiopasdfghjklzxcvbnm,", - "2685adffdbb4b2c515054cffc25cfcbfe2e462df65bbe82fb50f71e1e68dd285", - "1D0CB70310C4D793A4561FE592B7C156771E3E26283B28AB588E968243B52DD0", - "54D7A435E5E3F2811AA542F8895C20CCB760F2713DBDDB7291DAB6DA4E4F927E", - "20A3BDABFFF2C1BF8E2AF709F6CDCAFE70DA9A1DBC22305B6332E36844092984", - }, - { - "11111111111111111111111111111111111111111111111111111111111111111" - "11111111111111111111111111111111111111111111111111111111111111111" - "111111111111111111", - "3382266517e2ebe6df51faf4bfe612236ad46fb8bd59ac982a223b045e080ac6", - "A669F372B3C2EEA351210082CAEC3B96767A7B222D19FF2EE3D814860F0D703A", - "4890F9AC3A8D102EE3A2A473930C01CAD29DCE3860ACB7A5DADAEF16FE808991", - "979F088E58F1814D5E462CB9F935D2924ABD8D32211D8F02DD7E0991726DF573", - }, - { - "qwertyuiop[]asdfghjkl;'zxcvbnm,./1234567890-=", - "7457dc574d927e5dae84b05264a5b637b5a68e34a85b3965084ed6fed5b7f12d", - "000000000000000000000000000000000000000000000000000000000000007C", - "0AA595A649E517133D3448CA657424DD07BBED289030F0C0AA6738D26AB9A910", - "83812632F1443A70B198D112D075D886BE7BBC6EC6275AE52661E52B7358BB8B", - }, - }; - - const ecdsa_curve *curve = &secp256k1; - bignum256 k; - uint8_t priv_key[32]; - uint8_t pub_key[33]; - uint8_t buf_raw[32]; - schnorr_sign_pair result; - schnorr_sign_pair expected; - int res; - - for (size_t i = 0; i < sizeof(test_cases) / sizeof(*test_cases); i++) { - memcpy(priv_key, fromhex(test_cases[i].priv_key), 32); - memcpy(&buf_raw, fromhex(test_cases[i].k_hex), 32); - bn_read_be(buf_raw, &k); - schnorr_sign(curve, priv_key, &k, (const uint8_t *)test_cases[i].message, - strlen(test_cases[i].message), &result); - - memcpy(&expected.s, fromhex(test_cases[i].s_hex), 32); - memcpy(&expected.r, fromhex(test_cases[i].r_hex), 32); - - ck_assert_mem_eq(&expected.r, &result.r, 32); - ck_assert_mem_eq(&expected.s, &result.s, 32); - - ecdsa_get_public_key33(curve, priv_key, pub_key); - res = schnorr_verify(curve, pub_key, (const uint8_t *)test_cases[i].message, - strlen(test_cases[i].message), &result); - ck_assert_int_eq(res, 0); - } -} -END_TEST - -START_TEST(test_schnorr_fail_verify) { - static struct { - const char *message; - const char *priv_key; - const char *k_hex; - const char *s_hex; - const char *r_hex; - } test_case = { - "123", - "3382266517e2ebe6df51faf4bfe612236ad46fb8bd59ac982a223b045e080ac6", - "669301F724C555D7BB1185C04909E9CACA3EC7A292B3A1C92DDCCD5A5A7DDDD3", - "FFD72C290B98C93A4BCEDC0EDCDF040C35579BE962FE83E6821D4F3CB4B795D2", - "74AAE9C3E069E2806E1B0D890970BE387AEBED8040F37991AACAD70B27895E39", - }; - - const ecdsa_curve *curve = &secp256k1; - bignum256 k; - bignum256 bn_temp; - uint8_t priv_key[32]; - uint8_t pub_key[33]; - uint8_t buf_raw[32]; - schnorr_sign_pair result; - schnorr_sign_pair bad_result; - int res; - - memcpy(priv_key, fromhex(test_case.priv_key), 32); - memcpy(&buf_raw, fromhex(test_case.k_hex), 32); - bn_read_be(buf_raw, &k); - - schnorr_sign(curve, priv_key, &k, (const uint8_t *)test_case.message, - strlen(test_case.message), &result); - - ecdsa_get_public_key33(curve, priv_key, pub_key); - - // Test result = 0 (OK) - res = schnorr_verify(curve, pub_key, (const uint8_t *)test_case.message, - strlen(test_case.message), &result); - ck_assert_int_eq(res, 0); - - // Test result = 1 (empty message) - res = schnorr_verify(curve, pub_key, (const uint8_t *)test_case.message, 0, - &result); - ck_assert_int_eq(res, 1); - - // Test result = 2 (r = 0) - bn_zero(&bn_temp); - bn_write_be(&bn_temp, bad_result.r); - memcpy(bad_result.s, result.s, 32); - res = schnorr_verify(curve, pub_key, (const uint8_t *)test_case.message, - strlen(test_case.message), &bad_result); - ck_assert_int_eq(res, 2); - - // Test result = 3 (s = 0) - memcpy(bad_result.r, result.r, 32); - bn_zero(&bn_temp); - bn_write_be(&bn_temp, bad_result.s); - res = schnorr_verify(curve, pub_key, (const uint8_t *)test_case.message, - strlen(test_case.message), &bad_result); - ck_assert_int_eq(res, 3); - - // Test result = 4 (curve->order < r) - bn_copy(&curve->order, &bn_temp); - bn_addi(&bn_temp, 1); - bn_write_be(&bn_temp, bad_result.r); - memcpy(bad_result.s, result.s, 32); - res = schnorr_verify(curve, pub_key, (const uint8_t *)test_case.message, - strlen(test_case.message), &bad_result); - ck_assert_int_eq(res, 4); - - // Test result = 5 (curve->order < s) - memcpy(bad_result.r, result.r, 32); - bn_copy(&curve->order, &bn_temp); - bn_addi(&bn_temp, 1); - bn_write_be(&bn_temp, bad_result.s); - res = schnorr_verify(curve, pub_key, (const uint8_t *)test_case.message, - strlen(test_case.message), &bad_result); - ck_assert_int_eq(res, 5); - - // Test result = 6 (curve->order = r) - bn_copy(&curve->order, &bn_temp); - bn_write_be(&bn_temp, bad_result.r); - memcpy(bad_result.s, result.s, 32); - res = schnorr_verify(curve, pub_key, (const uint8_t *)test_case.message, - strlen(test_case.message), &bad_result); - ck_assert_int_eq(res, 6); - - // Test result = 7 (curve->order = s) - memcpy(bad_result.r, result.r, 32); - bn_copy(&curve->order, &bn_temp); - bn_write_be(&bn_temp, bad_result.s); - res = schnorr_verify(curve, pub_key, (const uint8_t *)test_case.message, - strlen(test_case.message), &bad_result); - ck_assert_int_eq(res, 7); - - // Test result = 8 (failed ecdsa_read_pubkey) - // TBD - - // Test result = 10 (r != r') - memcpy(bad_result.r, result.r, 32); - memcpy(bad_result.s, result.s, 32); - test_case.message = "12"; - res = schnorr_verify(curve, pub_key, (const uint8_t *)test_case.message, - strlen(test_case.message), &bad_result); - ck_assert_int_eq(res, 10); -} -END_TEST - static int my_strncasecmp(const char *s1, const char *s2, size_t n) { size_t i = 0; while (i < n) { @@ -8972,6 +9053,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) { } #include "test_check_cashaddr.h" +#include "test_check_zilliqa.h" // [wallet-core] #if USE_SEGWIT #include "test_check_segwit.h" #endif @@ -9069,7 +9151,13 @@ Suite *test_suite(void) { suite_add_tcase(s, tc); tc = tcase_create("ecdsa"); - tcase_add_test(tc, test_ecdsa_signature); + tcase_add_test(tc, test_ecdsa_get_public_key33); + tcase_add_test(tc, test_ecdsa_get_public_key65); + tcase_add_test(tc, test_ecdsa_recover_pub_from_sig); + tcase_add_test(tc, test_ecdsa_verify_digest); +#if USE_RFC6979 + tcase_add_test(tc, test_ecdsa_sign_digest_deterministic); +#endif suite_add_tcase(s, tc); tc = tcase_create("rfc6979"); @@ -9124,6 +9212,7 @@ Suite *test_suite(void) { tc = tcase_create("blake2"); tcase_add_test(tc, test_blake2b); + tcase_add_test(tc, test_blake2bp); tcase_add_test(tc, test_blake2s); suite_add_tcase(s, tc); @@ -9147,7 +9236,6 @@ Suite *test_suite(void) { tcase_add_test(tc, test_mnemonic_find_word); suite_add_tcase(s, tc); -/* tc = tcase_create("slip39"); tcase_add_test(tc, test_slip39_get_word); tcase_add_test(tc, test_slip39_word_index); @@ -9155,7 +9243,6 @@ Suite *test_suite(void) { tcase_add_test(tc, test_slip39_sequence_to_word); tcase_add_test(tc, test_slip39_word_completion); suite_add_tcase(s, tc); -*/ tc = tcase_create("shamir"); tcase_add_test(tc, test_shamir); @@ -9283,6 +9370,10 @@ Suite *test_suite(void) { tcase_add_test(tc, test_bip32_cardano_hdnode_vector_8); tcase_add_test(tc, test_bip32_cardano_hdnode_vector_9); + tcase_add_test(tc, test_cardano_ledger_vector_1); + tcase_add_test(tc, test_cardano_ledger_vector_2); + tcase_add_test(tc, test_cardano_ledger_vector_3); + tcase_add_test(tc, test_ed25519_cardano_sign_vectors); suite_add_tcase(s, tc); #endif @@ -9325,16 +9416,9 @@ Suite *test_suite(void) { tcase_add_test(tc, test_xmr_get_subaddress_secret_key); tcase_add_test(tc, test_xmr_gen_c); tcase_add_test(tc, test_xmr_varint); - tcase_add_test(tc, test_xmr_gen_range_sig); suite_add_tcase(s, tc); #endif - // [wallet-core] - tc = tcase_create("schnorr"); - tcase_add_test(tc, test_schnorr_sign_verify); - tcase_add_test(tc, test_schnorr_fail_verify); - suite_add_tcase(s, tc); - return s; } diff --git a/trezor-crypto/crypto/tests/test_check_cardano.h b/trezor-crypto/crypto/tests/test_check_cardano.h index 4fc03cb3ee1..4f31a55309f 100644 --- a/trezor-crypto/crypto/tests/test_check_cardano.h +++ b/trezor-crypto/crypto/tests/test_check_cardano.h @@ -5,7 +5,7 @@ START_TEST(test_ed25519_cardano_sign_vectors) { ed25519_secret_key secret_key_extension; ed25519_signature signature; - const char *vectors[] = { + static const char *vectors[] = { "6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea5" "3", // private key "60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8" @@ -89,14 +89,13 @@ START_TEST(test_ed25519_cardano_sign_vectors) { memcpy(secret_key_extension, fromhex(*(test_data + 1)), 32); MARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension)); - ed25519_publickey_ext(secret_key, secret_key_extension, public_key); + ed25519_publickey_ext(secret_key, public_key); UNMARK_SECRET_DATA(public_key, sizeof(public_key)); ck_assert_mem_eq(public_key, fromhex(*(test_data + 2)), 32); const uint8_t *message = (const uint8_t *)"Hello World"; - ed25519_sign_ext(message, 11, secret_key, secret_key_extension, public_key, - signature); + ed25519_sign_ext(message, 11, secret_key, secret_key_extension, signature); UNMARK_SECRET_DATA(signature, sizeof(signature)); ck_assert_mem_eq(signature, fromhex(*(test_data + 3)), 64); @@ -113,14 +112,24 @@ START_TEST(test_bip32_cardano_hdnode_vector_1) { HDNode node; uint8_t mnemonic_bits[66]; + uint8_t cardano_secret[CARDANO_SECRET_LENGTH]; int mnemonic_bits_len = mnemonic_to_bits( "ring crime symptom enough erupt lady behave ramp apart settle citizen " "junk", mnemonic_bits); ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); + secret_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, cardano_secret, + NULL); + hdnode_from_secret_cardano(cardano_secret, &node); + ck_assert_mem_eq( + cardano_secret, + fromhex( + "08a14df748e477a69d21c97c56db151fc19e2521f31dd0ac5360f269e5b6ea46" + "daeb991f2d2128e2525415c56a07f4366baa26c1e48572a5e073934b6de35fbc" + "affbc325d9027c0f2d9f925b1dcf6c12bf5c1dd08904474066a4f2c00db56173"), + 96); ck_assert_mem_eq( node.chain_code, fromhex( @@ -136,7 +145,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_1) { fromhex( "daeb991f2d2128e2525415c56a07f4366baa26c1e48572a5e073934b6de35fbc"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key + 1, fromhex( @@ -149,15 +158,18 @@ START_TEST(test_bip32_cardano_hdnode_vector_2) { HDNode node; uint8_t mnemonic_bits[66]; + uint8_t cardano_secret[CARDANO_SECRET_LENGTH]; int mnemonic_bits_len = mnemonic_to_bits( "ring crime symptom enough erupt lady behave ramp apart settle citizen " "junk", mnemonic_bits); ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); + secret_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, cardano_secret, + NULL); + hdnode_from_secret_cardano(cardano_secret, &node); - hdnode_private_ckd_cardano(&node, 0x80000000); + hdnode_private_ckd(&node, 0x80000000); ck_assert_mem_eq( node.chain_code, @@ -174,7 +186,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_2) { fromhex( "64aa9a16331f14c981b769efcf96addcc4c6db44047fe7a7feae0be23d33bf54"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key + 1, fromhex( @@ -187,15 +199,18 @@ START_TEST(test_bip32_cardano_hdnode_vector_3) { HDNode node; uint8_t mnemonic_bits[66]; + uint8_t cardano_secret[CARDANO_SECRET_LENGTH]; int mnemonic_bits_len = mnemonic_to_bits( "ring crime symptom enough erupt lady behave ramp apart settle citizen " "junk", mnemonic_bits); ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); + secret_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, cardano_secret, + NULL); + hdnode_from_secret_cardano(cardano_secret, &node); - hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd(&node, 0x80000001); ck_assert_mem_eq( node.chain_code, @@ -212,7 +227,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_3) { fromhex( "b4fc241feffe840b8a54a26ab447f5a5caa31032db3a8091fca14f38b86ed539"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key + 1, fromhex( @@ -225,16 +240,19 @@ START_TEST(test_bip32_cardano_hdnode_vector_4) { HDNode node; uint8_t mnemonic_bits[66]; + uint8_t cardano_secret[CARDANO_SECRET_LENGTH]; int mnemonic_bits_len = mnemonic_to_bits( "ring crime symptom enough erupt lady behave ramp apart settle citizen " "junk", mnemonic_bits); ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); + secret_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, cardano_secret, + NULL); + hdnode_from_secret_cardano(cardano_secret, &node); - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); + hdnode_private_ckd(&node, 0x80000000); + hdnode_private_ckd(&node, 0x80000001); ck_assert_mem_eq( node.chain_code, @@ -251,7 +269,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_4) { fromhex( "a3071959013af95aaecf78a7a2e1b9838bbbc4864d6a8a2295243782078345cd"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key + 1, fromhex( @@ -264,17 +282,20 @@ START_TEST(test_bip32_cardano_hdnode_vector_5) { HDNode node; uint8_t mnemonic_bits[66]; + uint8_t cardano_secret[CARDANO_SECRET_LENGTH]; int mnemonic_bits_len = mnemonic_to_bits( "ring crime symptom enough erupt lady behave ramp apart settle citizen " "junk", mnemonic_bits); ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); + secret_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, cardano_secret, + NULL); + hdnode_from_secret_cardano(cardano_secret, &node); - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd(&node, 0x80000000); + hdnode_private_ckd(&node, 0x80000001); + hdnode_private_ckd(&node, 0x80000002); ck_assert_mem_eq( node.chain_code, @@ -291,7 +312,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_5) { fromhex( "5bebf1eea68acd04932653d944b064b10baaf5886dd73c185cc285059bf93363"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key + 1, fromhex( @@ -304,18 +325,21 @@ START_TEST(test_bip32_cardano_hdnode_vector_6) { HDNode node; uint8_t mnemonic_bits[66]; + uint8_t cardano_secret[CARDANO_SECRET_LENGTH]; int mnemonic_bits_len = mnemonic_to_bits( "ring crime symptom enough erupt lady behave ramp apart settle citizen " "junk", mnemonic_bits); ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); + secret_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, cardano_secret, + NULL); + hdnode_from_secret_cardano(cardano_secret, &node); - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0x80000002); + hdnode_private_ckd(&node, 0x80000000); + hdnode_private_ckd(&node, 0x80000001); + hdnode_private_ckd(&node, 0x80000002); + hdnode_private_ckd(&node, 0x80000002); ck_assert_mem_eq( node.chain_code, @@ -332,7 +356,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_6) { fromhex( "466332cb097934b43008701e7e27044aa56c7859019e4eba18d91a3bea23dff7"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key + 1, fromhex( @@ -345,19 +369,22 @@ START_TEST(test_bip32_cardano_hdnode_vector_7) { HDNode node; uint8_t mnemonic_bits[66]; + uint8_t cardano_secret[CARDANO_SECRET_LENGTH]; int mnemonic_bits_len = mnemonic_to_bits( "ring crime symptom enough erupt lady behave ramp apart settle citizen " "junk", mnemonic_bits); ck_assert_int_eq(mnemonic_bits_len, 132); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); + secret_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, cardano_secret, + NULL); + hdnode_from_secret_cardano(cardano_secret, &node); - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0xBB9ACA00); + hdnode_private_ckd(&node, 0x80000000); + hdnode_private_ckd(&node, 0x80000001); + hdnode_private_ckd(&node, 0x80000002); + hdnode_private_ckd(&node, 0x80000002); + hdnode_private_ckd(&node, 0xBB9ACA00); ck_assert_mem_eq( node.chain_code, @@ -374,7 +401,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_7) { fromhex( "01eccef768a79859f824a1d3c3e35e131184e2940c3fca9a4c9b307741f65363"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key + 1, fromhex( @@ -387,19 +414,22 @@ START_TEST(test_bip32_cardano_hdnode_vector_8) { HDNode node; uint8_t mnemonic_bits[66]; + uint8_t cardano_secret[CARDANO_SECRET_LENGTH]; int mnemonic_bits_len = mnemonic_to_bits( "found differ bulb shadow wrist blue bind vessel deposit tip pelican " "action surprise weapon check fiction muscle this", mnemonic_bits); ck_assert_int_eq(mnemonic_bits_len, 198); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); + secret_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, cardano_secret, + NULL); + hdnode_from_secret_cardano(cardano_secret, &node); - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0xBB9ACA00); + hdnode_private_ckd(&node, 0x80000000); + hdnode_private_ckd(&node, 0x80000001); + hdnode_private_ckd(&node, 0x80000002); + hdnode_private_ckd(&node, 0x80000002); + hdnode_private_ckd(&node, 0xBB9ACA00); ck_assert_mem_eq( node.chain_code, @@ -416,7 +446,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_8) { fromhex( "170e0d3b65ba8d71f27a6db60d0ac26dcb16e52e08cc259db72066f206b258d5"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key + 1, fromhex( @@ -429,20 +459,23 @@ START_TEST(test_bip32_cardano_hdnode_vector_9) { HDNode node; uint8_t mnemonic_bits[66]; + uint8_t cardano_secret[CARDANO_SECRET_LENGTH]; int mnemonic_bits_len = mnemonic_to_bits( "balance exotic ranch knife glory slow tape favorite yard gym awake " "ill exist useless parent aim pig stay effort into square gasp credit " "butter", mnemonic_bits); ck_assert_int_eq(mnemonic_bits_len, 264); - hdnode_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, - mnemonic_bits_len / 8, &node); + secret_from_entropy_cardano_icarus((const uint8_t *)"", 0, mnemonic_bits, + mnemonic_bits_len / 8, cardano_secret, + NULL); + hdnode_from_secret_cardano(cardano_secret, &node); - hdnode_private_ckd_cardano(&node, 0x80000000); - hdnode_private_ckd_cardano(&node, 0x80000001); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0x80000002); - hdnode_private_ckd_cardano(&node, 0xBB9ACA00); + hdnode_private_ckd(&node, 0x80000000); + hdnode_private_ckd(&node, 0x80000001); + hdnode_private_ckd(&node, 0x80000002); + hdnode_private_ckd(&node, 0x80000002); + hdnode_private_ckd(&node, 0xBB9ACA00); ck_assert_mem_eq( node.chain_code, @@ -459,7 +492,7 @@ START_TEST(test_bip32_cardano_hdnode_vector_9) { fromhex( "80d2c677638e5dbd4395cdec279bf2a42077f2797c9e887949d37cdb317fce6a"), 32); - hdnode_fill_public_key(&node); + ck_assert_int_eq(hdnode_fill_public_key(&node), 0); ck_assert_mem_eq( node.public_key + 1, fromhex( @@ -467,3 +500,72 @@ START_TEST(test_bip32_cardano_hdnode_vector_9) { 32); } END_TEST + +START_TEST(test_cardano_ledger_vector_1) { + uint8_t seed[512 / 8]; + uint8_t cardano_secret[CARDANO_SECRET_LENGTH]; + + const char *mnemonic = + "recall grace sport punch exhibit mad harbor stand obey " + "short width stem awkward used stairs wool ugly " + "trap season stove worth toward congress jaguar"; + + mnemonic_to_seed(mnemonic, "", seed, NULL); + const int res = + secret_from_seed_cardano_ledger(seed, sizeof(seed), cardano_secret); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + cardano_secret, + fromhex( + "a08cf85b564ecf3b947d8d4321fb96d70ee7bb760877e371899b14e2ccf88658" + "104b884682b57efd97decbb318a45c05a527b9cc5c2f64f7352935a049ceea60" + "680d52308194ccef2a18e6812b452a5815fbd7f5babc083856919aaf668fe7e4"), + CARDANO_SECRET_LENGTH); +} +END_TEST + +START_TEST(test_cardano_ledger_vector_2) { + uint8_t seed[512 / 8]; + uint8_t cardano_secret[CARDANO_SECRET_LENGTH]; + + const char *mnemonic = + "correct cherry mammal bubble want mandate polar hazard " + "crater better craft exotic choice fun tourist census " + "gap lottery neglect address glow carry old business"; + + mnemonic_to_seed(mnemonic, "", seed, NULL); + const int res = + secret_from_seed_cardano_ledger(seed, sizeof(seed), cardano_secret); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + cardano_secret, + fromhex( + "587c6774357ecbf840d4db6404ff7af016dace0400769751ad2abfc77b9a3844" + "cc71702520ef1a4d1b68b91187787a9b8faab0a9bb6b160de541b6ee62469901" + "fc0beda0975fe4763beabd83b7051a5fd5cbce5b88e82c4bbaca265014e524bd"), + CARDANO_SECRET_LENGTH); +} +END_TEST + +START_TEST(test_cardano_ledger_vector_3) { + uint8_t seed[512 / 8]; + uint8_t cardano_secret[CARDANO_SECRET_LENGTH]; + + const char *mnemonic = + "abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon art"; + + mnemonic_to_seed(mnemonic, "foo", seed, NULL); + const int res = + secret_from_seed_cardano_ledger(seed, sizeof(seed), cardano_secret); + ck_assert_int_eq(res, 1); + ck_assert_mem_eq( + cardano_secret, + fromhex( + "f053a1e752de5c26197b60f032a4809f08bb3e5d90484fe42024be31efcba757" + "8d914d3ff992e21652fee6a4d99f6091006938fac2c0c0f9d2de0ba64b754e92" + "a4f3723f23472077aa4cd4dd8a8a175dba07ea1852dad1cf268c61a2679c3890"), + CARDANO_SECRET_LENGTH); +} +END_TEST diff --git a/trezor-crypto/crypto/tests/test_check_zilliqa.h b/trezor-crypto/crypto/tests/test_check_zilliqa.h new file mode 100644 index 00000000000..b8b16824b51 --- /dev/null +++ b/trezor-crypto/crypto/tests/test_check_zilliqa.h @@ -0,0 +1,214 @@ +#include +#include + +START_TEST(test_zil_schnorr_sign_verify) { + static struct { + const char *message; + const char *priv_key; + const char *k_hex; + const char *s_hex; + const char *r_hex; + } test_cases[] = { + { + "123", + "3382266517e2ebe6df51faf4bfe612236ad46fb8bd59ac982a223b045e080ac6", + "669301F724C555D7BB1185C04909E9CACA3EC7A292B3A1C92DDCCD5A5A7DDDD3", + "FFD72C290B98C93A4BCEDC0EDCDF040C35579BE962FE83E6821D4F3CB4B795D2", + "74AAE9C3E069E2806E1B0D890970BE387AEBED8040F37991AACAD70B27895E39", + }, + { + "1234", + "51a2758eed776c40b367364909c8a9c98cc969104f69ff316f7a287495c37c9b", + "A0A1A9B3570AAE963535B8D4376C58A61646C18182C9FDDA5FB13703F88D4D1E", + "99A0CB942C81571B77C682F79CD3CB663CE9E1C55BB425BA24B9F11A0DE84FE2", + "C3C10363E38158BBA20556A36DE9358DFD81A31C180ABC9E7617C1CC1CAF03B3", + }, + { + "12345", + "2685adffdbb4b2c515054cffc25cfcbfe2e462df65bbe82fb50f71e1e68dd285", + "38DE7B3315F201433D271E91FBE62966576CA05CBFEC1770B77D7EC9D6A01D6D", + "28982FA6C2B620CBC550F7EF9EAB605F409C584FBE5A765678877B79AB517086", + "9A0788E5B0947DEDEDE386DF57A006CF3FE43919A74D9CA630F8A1A9D97B4650", + }, + { + "fun", + "7457dc574d927e5dae84b05264a5b637b5a68e34a85b3965084ed6fed5b7f12d", + "E005ABD242C7C602AB5EED080C5083C7C5F8DAEC6D046A54F384A8B8CDECF740", + "51070ABCA039DAC294F6BA3BFC8C36CFC66020EDF66D1ACF1A9B545B0BF09F52", + "330A924525EF722FA20E8E25CB6E8BD7DF4394886FA4414E4A0B6812AA25BBC0", + }, + { + "funny", + "52c395a6d304de1a959e73e4604e32c5ad3f2bf01c8f730af426b38d7d5dd908", + "0CF28B5C40A8830F3195BB99A9F0E2808F576105F41D16ABCF596AC5A8CFE88A", + "3D60FB4664C994AD956378B9402BC68F7B4799D74F4783A6199C0D74865EA2B6", + "5ED5EDEE0314DFFBEE39EE4E9C76DE8BC3EB8CB891AEC32B83957514284B205B", + }, + { + "What is great in man is that he is a bridge and not a goal", + "52c395a6d304de1a959e73e4604e32c5ad3f2bf01c8f730af426b38d7d5dd908", + "000000000000000000000000000000000000000000000000000000000000007B", + "546F70AA1FEE3718C95508240CDC073B9FEFED05959C5319DD8E2BF07A1DD028", + "B8667BE5E10B113608BFE5327C44E9F0462BE26F789177E10DCE53019AA33DAA", + }, + { + "123456789147258369qwertyuiopasdfghjklzxcvbnm,", + "2685adffdbb4b2c515054cffc25cfcbfe2e462df65bbe82fb50f71e1e68dd285", + "1D0CB70310C4D793A4561FE592B7C156771E3E26283B28AB588E968243B52DD0", + "54D7A435E5E3F2811AA542F8895C20CCB760F2713DBDDB7291DAB6DA4E4F927E", + "20A3BDABFFF2C1BF8E2AF709F6CDCAFE70DA9A1DBC22305B6332E36844092984", + }, + { + "11111111111111111111111111111111111111111111111111111111111111111" + "11111111111111111111111111111111111111111111111111111111111111111" + "111111111111111111", + "3382266517e2ebe6df51faf4bfe612236ad46fb8bd59ac982a223b045e080ac6", + "A669F372B3C2EEA351210082CAEC3B96767A7B222D19FF2EE3D814860F0D703A", + "4890F9AC3A8D102EE3A2A473930C01CAD29DCE3860ACB7A5DADAEF16FE808991", + "979F088E58F1814D5E462CB9F935D2924ABD8D32211D8F02DD7E0991726DF573", + }, + { + "qwertyuiop[]asdfghjkl;'zxcvbnm,./1234567890-=", + "7457dc574d927e5dae84b05264a5b637b5a68e34a85b3965084ed6fed5b7f12d", + "000000000000000000000000000000000000000000000000000000000000007C", + "0AA595A649E517133D3448CA657424DD07BBED289030F0C0AA6738D26AB9A910", + "83812632F1443A70B198D112D075D886BE7BBC6EC6275AE52661E52B7358BB8B", + }, + }; + + const ecdsa_curve *curve = &secp256k1; + bignum256 k; + uint8_t priv_key[32]; + uint8_t pub_key[33]; + uint8_t buf_raw[32]; + schnorr_sign_pair result; + schnorr_sign_pair expected; + int res; + + for (size_t i = 0; i < sizeof(test_cases) / sizeof(*test_cases); i++) { + memcpy(priv_key, fromhex(test_cases[i].priv_key), 32); + memcpy(&buf_raw, fromhex(test_cases[i].k_hex), 32); + bn_read_be(buf_raw, &k); + zil_schnorr_sign_k(curve, priv_key, &k, (const uint8_t *)test_cases[i].message, + strlen(test_cases[i].message), &result); + + memcpy(&expected.s, fromhex(test_cases[i].s_hex), 32); + memcpy(&expected.r, fromhex(test_cases[i].r_hex), 32); + + ck_assert_mem_eq(&expected.r, &result.r, 32); + ck_assert_mem_eq(&expected.s, &result.s, 32); + + ecdsa_get_public_key33(curve, priv_key, pub_key); + res = zil_schnorr_verify_pair(curve, pub_key, (const uint8_t *)test_cases[i].message, + strlen(test_cases[i].message), &result); + ck_assert_int_eq(res, 0); + } +} +END_TEST + +START_TEST(test_zil_schnorr_fail_verify) { + static struct { + const char *message; + const char *priv_key; + const char *k_hex; + const char *s_hex; + const char *r_hex; + } test_case = { + "123", + "3382266517e2ebe6df51faf4bfe612236ad46fb8bd59ac982a223b045e080ac6", + "669301F724C555D7BB1185C04909E9CACA3EC7A292B3A1C92DDCCD5A5A7DDDD3", + "FFD72C290B98C93A4BCEDC0EDCDF040C35579BE962FE83E6821D4F3CB4B795D2", + "74AAE9C3E069E2806E1B0D890970BE387AEBED8040F37991AACAD70B27895E39", + }; + + const ecdsa_curve *curve = &secp256k1; + bignum256 k; + bignum256 bn_temp; + uint8_t priv_key[32]; + uint8_t pub_key[33]; + uint8_t buf_raw[32]; + schnorr_sign_pair result; + schnorr_sign_pair bad_result; + int res; + + memcpy(priv_key, fromhex(test_case.priv_key), 32); + memcpy(&buf_raw, fromhex(test_case.k_hex), 32); + bn_read_be(buf_raw, &k); + + zil_schnorr_sign_k(curve, priv_key, &k, (const uint8_t *)test_case.message, + strlen(test_case.message), &result); + + ecdsa_get_public_key33(curve, priv_key, pub_key); + + // Test result = 0 (OK) + res = zil_schnorr_verify_pair(curve, pub_key, (const uint8_t *)test_case.message, + strlen(test_case.message), &result); + ck_assert_int_eq(res, 0); + + // Test result = 1 (empty message) + res = zil_schnorr_verify_pair(curve, pub_key, (const uint8_t *)test_case.message, 0, + &result); + ck_assert_int_eq(res, 1); + + // Test result = 2 (r = 0) + bn_zero(&bn_temp); + bn_write_be(&bn_temp, bad_result.r); + memcpy(bad_result.s, result.s, 32); + res = zil_schnorr_verify_pair(curve, pub_key, (const uint8_t *)test_case.message, + strlen(test_case.message), &bad_result); + ck_assert_int_eq(res, 2); + + // Test result = 3 (s = 0) + memcpy(bad_result.r, result.r, 32); + bn_zero(&bn_temp); + bn_write_be(&bn_temp, bad_result.s); + res = zil_schnorr_verify_pair(curve, pub_key, (const uint8_t *)test_case.message, + strlen(test_case.message), &bad_result); + ck_assert_int_eq(res, 3); + + // Test result = 4 (curve->order < r) + bn_copy(&curve->order, &bn_temp); + bn_addi(&bn_temp, 1); + bn_write_be(&bn_temp, bad_result.r); + memcpy(bad_result.s, result.s, 32); + res = zil_schnorr_verify_pair(curve, pub_key, (const uint8_t *)test_case.message, + strlen(test_case.message), &bad_result); + ck_assert_int_eq(res, 4); + + // Test result = 5 (curve->order < s) + memcpy(bad_result.r, result.r, 32); + bn_copy(&curve->order, &bn_temp); + bn_addi(&bn_temp, 1); + bn_write_be(&bn_temp, bad_result.s); + res = zil_schnorr_verify_pair(curve, pub_key, (const uint8_t *)test_case.message, + strlen(test_case.message), &bad_result); + ck_assert_int_eq(res, 5); + + // Test result = 6 (curve->order = r) + bn_copy(&curve->order, &bn_temp); + bn_write_be(&bn_temp, bad_result.r); + memcpy(bad_result.s, result.s, 32); + res = zil_schnorr_verify_pair(curve, pub_key, (const uint8_t *)test_case.message, + strlen(test_case.message), &bad_result); + ck_assert_int_eq(res, 6); + + // Test result = 7 (curve->order = s) + memcpy(bad_result.r, result.r, 32); + bn_copy(&curve->order, &bn_temp); + bn_write_be(&bn_temp, bad_result.s); + res = zil_schnorr_verify_pair(curve, pub_key, (const uint8_t *)test_case.message, + strlen(test_case.message), &bad_result); + ck_assert_int_eq(res, 7); + + // Test result = 8 (failed ecdsa_read_pubkey) + // TBD + + // Test result = 10 (r != r') + memcpy(bad_result.r, result.r, 32); + memcpy(bad_result.s, result.s, 32); + test_case.message = "12"; + res = zil_schnorr_verify_pair(curve, pub_key, (const uint8_t *)test_case.message, + strlen(test_case.message), &bad_result); + ck_assert_int_eq(res, 10); +} +END_TEST diff --git a/trezor-crypto/crypto/tests/test_openssl.c b/trezor-crypto/crypto/tests/test_openssl.c index 4b38658f811..b9390846cb9 100644 --- a/trezor-crypto/crypto/tests/test_openssl.c +++ b/trezor-crypto/crypto/tests/test_openssl.c @@ -79,8 +79,15 @@ void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) { } // generate public key from private key - ecdsa_get_public_key33(curve, priv_key, pub_key33); - ecdsa_get_public_key65(curve, priv_key, pub_key65); + if (ecdsa_get_public_key33(curve, priv_key, pub_key33) != 0) { + printf("ecdsa_get_public_key33 failed\n"); + return; + } + + if (ecdsa_get_public_key65(curve, priv_key, pub_key65) != 0) { + printf("ecdsa_get_public_key65 failed\n"); + return; + } // use our ECDSA verifier to verify the message signature if (ecdsa_verify(curve, HASHER_SHA2, pub_key65, sig, msg, msg_len) != 0) { diff --git a/trezor-crypto/crypto/tests/test_speed.c b/trezor-crypto/crypto/tests/test_speed.c index 8a675eca576..a82f67f3e65 100644 --- a/trezor-crypto/crypto/tests/test_speed.c +++ b/trezor-crypto/crypto/tests/test_speed.c @@ -11,7 +11,7 @@ #include "nist256p1.h" #include -uint8_t msg[256]; +static uint8_t msg[256]; void prepare_msg(void) { for (size_t i = 0; i < sizeof(msg); i++) { @@ -50,18 +50,16 @@ void bench_sign_nist256p1(int iterations) { } void bench_sign_ed25519(int iterations) { - ed25519_public_key pk; ed25519_secret_key sk; ed25519_signature sig; - memcpy(pk, + memcpy(sk, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); - ed25519_publickey(sk, pk); for (int i = 0; i < iterations; i++) { - ed25519_sign(msg, sizeof(msg), sk, pk, sig); + ed25519_sign(msg, sizeof(msg), sk, sig); } } @@ -138,12 +136,12 @@ void bench_verify_ed25519(int iterations) { ed25519_secret_key sk; ed25519_signature sig; - memcpy(pk, + memcpy(sk, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3" "\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32); ed25519_publickey(sk, pk); - ed25519_sign(msg, sizeof(msg), sk, pk, sig); + ed25519_sign(msg, sizeof(msg), sk, sig); for (int i = 0; i < iterations; i++) { ed25519_sign_open(msg, sizeof(msg), pk, sig); @@ -169,7 +167,7 @@ void bench_multiply_curve25519(int iterations) { } } -HDNode root; +static HDNode root; void prepare_node(void) { hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root); diff --git a/trezor-crypto/crypto/schnorr.c b/trezor-crypto/crypto/zilliqa.c similarity index 73% rename from trezor-crypto/crypto/schnorr.c rename to trezor-crypto/crypto/zilliqa.c index c37e48f75ba..5d30b56bf6c 100644 --- a/trezor-crypto/crypto/schnorr.c +++ b/trezor-crypto/crypto/zilliqa.c @@ -20,7 +20,53 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include +#include "string.h" + +#include +#include +#include +#include + +int zil_schnorr_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, const uint32_t msg_len, uint8_t *sig) +{ + int i; + bignum256 k; + + uint8_t hash[32]; + sha256_Raw(msg, msg_len, hash); + + rfc6979_state rng; + init_rfc6979(priv_key, hash, curve, &rng); + + for (i = 0; i < 10000; i++) { + // generate K deterministically + generate_k_rfc6979(&k, &rng); + // if k is too big or too small, we don't like it + if (bn_is_zero(&k) || !bn_is_less(&k, &curve->order)) { + continue; + } + + schnorr_sign_pair sign; + if (zil_schnorr_sign_k(curve, priv_key, &k, msg, msg_len, &sign) != 0) { + continue; + } + + // we're done + memcpy(sig, sign.r, 32); + memcpy(sig + 32, sign.s, 32); + + memzero(&k, sizeof(k)); + memzero(&rng, sizeof(rng)); + memzero(&sign, sizeof(sign)); + return 0; + } + + // Too many retries without a valid signature + // -> fail with an error + memzero(&k, sizeof(k)); + memzero(&rng, sizeof(rng)); + return -1; +} // r = H(Q, kpub, m) static void calc_r(const curve_point *Q, const uint8_t pub_key[33], @@ -41,7 +87,7 @@ static void calc_r(const curve_point *Q, const uint8_t pub_key[33], } // Returns 0 if signing succeeded -int schnorr_sign(const ecdsa_curve *curve, const uint8_t *priv_key, +int zil_schnorr_sign_k(const ecdsa_curve *curve, const uint8_t *priv_key, const bignum256 *k, const uint8_t *msg, const uint32_t msg_len, schnorr_sign_pair *result) { uint8_t pub_key[33]; @@ -89,8 +135,18 @@ int schnorr_sign(const ecdsa_curve *curve, const uint8_t *priv_key, return 0; } +int zil_schnorr_verify(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, const uint32_t msg_len) +{ + schnorr_sign_pair sign; + + memcpy(sign.r, sig, 32); + memcpy(sign.s, sig + 32, 32); + + return zil_schnorr_verify_pair(curve, pub_key, msg, msg_len, &sign); +} + // Returns 0 if verification succeeded -int schnorr_verify(const ecdsa_curve *curve, const uint8_t *pub_key, +int zil_schnorr_verify_pair(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *msg, const uint32_t msg_len, const schnorr_sign_pair *sign) { curve_point pub_key_point; diff --git a/trezor-crypto/include/TrezorCrypto/bip32.h b/trezor-crypto/include/TrezorCrypto/bip32.h index 99b35762469..4b698bcc600 100644 --- a/trezor-crypto/include/TrezorCrypto/bip32.h +++ b/trezor-crypto/include/TrezorCrypto/bip32.h @@ -79,14 +79,6 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, int hdnode_private_ckd(HDNode *inout, uint32_t i); -#if USE_CARDANO -int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i); -int hdnode_from_seed_cardano(const uint8_t *seed, int seed_len, HDNode *out); -int hdnode_from_entropy_cardano_icarus(const uint8_t *pass, int pass_len, - const uint8_t *seed, int seed_len, - HDNode *out); -#endif - int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code); @@ -101,13 +93,14 @@ void hdnode_public_ckd_address_optimized(const curve_point *pub, int addrsize, int addrformat); #if USE_BIP32_CACHE +void bip32_cache_clear(void); int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint); #endif uint32_t hdnode_fingerprint(HDNode *node); -void hdnode_fill_public_key(HDNode *node); +int hdnode_fill_public_key(HDNode *node); #if USE_ETHEREUM int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); @@ -151,9 +144,9 @@ int hdnode_deserialize_private(const char *str, uint32_t version, const char *curve, HDNode *node, uint32_t *fingerprint); -void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw); -void hdnode_get_address(HDNode *node, uint32_t version, char *addr, - int addrsize); +int hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw); +int hdnode_get_address(HDNode *node, uint32_t version, char *addr, + int addrsize); const curve_info *get_curve_by_name(const char *curve_name); diff --git a/trezor-crypto/include/TrezorCrypto/bip39.h b/trezor-crypto/include/TrezorCrypto/bip39.h index cd073a2d62e..46ec5b0229c 100644 --- a/trezor-crypto/include/TrezorCrypto/bip39.h +++ b/trezor-crypto/include/TrezorCrypto/bip39.h @@ -24,25 +24,30 @@ #ifndef __BIP39_H__ #define __BIP39_H__ -#include -#include - #ifdef __cplusplus extern "C" { #endif -#define BIP39_WORDS 2048 +#include +#include + +#include + +#define BIP39_WORD_COUNT 2048 #define BIP39_PBKDF2_ROUNDS 2048 -#define BIP39_MAX_WORDS 24 // [wallet-core] -#define BIP39_MAX_WORD_LENGTH 9 // [wallet-core] +#if USE_BIP39_CACHE +void bip39_cache_clear(void); +#endif + +// [wallet-core] +#define BIP39_MAX_WORDS 24 +#define BIP39_MAX_WORD_LENGTH 9 // [wallet-core] Added output buffer -const char *mnemonic_generate(int strength, char *buf, int buflen); // strength in bits -// [wallet-core] Added output buffer +const char *mnemonic_generate(int strength, char *buf, int buflen); // strength in bits const char *mnemonic_from_data(const uint8_t *data, int datalen, char *buf, int buflen); -// [wallet-core] No longer used -//void mnemonic_clear(void); +void mnemonic_clear(void); int mnemonic_check(const char *mnemonic); @@ -54,13 +59,13 @@ void mnemonic_to_seed(const char *mnemonic, const char *passphrase, void (*progress_callback)(uint32_t current, uint32_t total)); -#ifdef __cplusplus -} /* extern "C" */ -#endif - int mnemonic_find_word(const char *word); const char *mnemonic_complete_word(const char *prefix, int len); const char *mnemonic_get_word(int index); uint32_t mnemonic_word_completion_mask(const char *prefix, int len); +#ifdef __cplusplus +} /* extern "C" */ +#endif + #endif diff --git a/trezor-crypto/include/TrezorCrypto/cardano.h b/trezor-crypto/include/TrezorCrypto/cardano.h new file mode 100644 index 00000000000..3e9986c52bd --- /dev/null +++ b/trezor-crypto/include/TrezorCrypto/cardano.h @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2013-2021 SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __CARDANO_H__ +#define __CARDANO_H__ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#include +#include +#include +#include + +#if USE_CARDANO + +#define CARDANO_SECRET_LENGTH 96 +#define CARDANO_ICARUS_PBKDF2_ROUNDS 4096 + +extern const curve_info ed25519_cardano_info; + +int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i); + +int secret_from_entropy_cardano_icarus( + const uint8_t *pass, int pass_len, const uint8_t *entropy, int entropy_len, + uint8_t secret_out[CARDANO_SECRET_LENGTH], + void (*progress_callback)(uint32_t current, uint32_t total)); +int secret_from_seed_cardano_ledger(const uint8_t *seed, int seed_len, + uint8_t secret_out[CARDANO_SECRET_LENGTH]); +int secret_from_seed_cardano_slip23(const uint8_t *seed, int seed_len, + uint8_t secret_out[CARDANO_SECRET_LENGTH]); + +int hdnode_from_secret_cardano(const uint8_t secret[CARDANO_SECRET_LENGTH], + HDNode *out); + +#endif // USE_CARDANO + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // __CARDANO_H__ diff --git a/trezor-crypto/include/TrezorCrypto/chacha20poly1305/ecrypt-sync.h b/trezor-crypto/include/TrezorCrypto/chacha20poly1305/ecrypt-sync.h index 39be5c9bc88..efce9dde273 100644 --- a/trezor-crypto/include/TrezorCrypto/chacha20poly1305/ecrypt-sync.h +++ b/trezor-crypto/include/TrezorCrypto/chacha20poly1305/ecrypt-sync.h @@ -90,12 +90,21 @@ void ECRYPT_keysetup( * IV setup. After having called ECRYPT_keysetup(), the user is * allowed to call ECRYPT_ivsetup() different times in order to * encrypt/decrypt different messages with the same key but different - * IV's. + * IV's. ECRYPT_ivsetup() also sets block counter to zero. */ void ECRYPT_ivsetup( ECRYPT_ctx* ctx, const u8* iv); +/* + * Block counter setup. It is used only for special purposes, + * since block counter is usually initialized with ECRYPT_ivsetup. + * ECRYPT_ctrsetup has to be called after ECRYPT_ivsetup. + */ +void ECRYPT_ctrsetup( + ECRYPT_ctx* ctx, + const u8* ctr); + /* * Encryption/decryption of arbitrary length messages. * diff --git a/trezor-crypto/include/TrezorCrypto/chacha_drbg.h b/trezor-crypto/include/TrezorCrypto/chacha_drbg.h index 416ace82414..0676d126cd3 100644 --- a/trezor-crypto/include/TrezorCrypto/chacha_drbg.h +++ b/trezor-crypto/include/TrezorCrypto/chacha_drbg.h @@ -21,23 +21,34 @@ #define __CHACHA_DRBG__ #include +#include -// Very fast deterministic random bit generator inspired by CTR_DRBG in NIST SP -// 800-90A +// A very fast deterministic random bit generator based on CTR_DRBG in NIST SP +// 800-90A. Chacha is used instead of a block cipher in the counter mode, SHA256 +// is used as a derivation function. The highest supported security strength is +// at least 256 bits. Reseeding is left up to caller. -#define CHACHA_DRBG_KEY_LENGTH 16 -#define CHACHA_DRBG_IV_LENGTH 8 -#define CHACHA_DRBG_SEED_LENGTH (CHACHA_DRBG_KEY_LENGTH + CHACHA_DRBG_IV_LENGTH) +// Length of inputs of chacha_drbg_init (entropy and nonce) or +// chacha_drbg_reseed (entropy and additional_input) that fill exactly +// block_count blocks of hash function in derivation_function. There is no need +// the input to have this length, it's just an optimalization. +#define CHACHA_DRBG_OPTIMAL_RESEED_LENGTH(block_count) \ + ((block_count)*SHA256_BLOCK_LENGTH - 1 - 4 - 9) +// 1 = sizeof(counter), 4 = sizeof(output_length) in +// derivation_function, 9 is length of SHA256 padding of message +// aligned to bytes typedef struct _CHACHA_DRBG_CTX { ECRYPT_ctx chacha_ctx; uint32_t reseed_counter; } CHACHA_DRBG_CTX; -void chacha_drbg_init(CHACHA_DRBG_CTX *ctx, - const uint8_t entropy[CHACHA_DRBG_SEED_LENGTH]); -void chacha_drbg_reseed(CHACHA_DRBG_CTX *ctx, - const uint8_t entropy[CHACHA_DRBG_SEED_LENGTH]); +void chacha_drbg_init(CHACHA_DRBG_CTX *ctx, const uint8_t *entropy, + size_t entropy_length, const uint8_t *nonce, + size_t nonce_length); void chacha_drbg_generate(CHACHA_DRBG_CTX *ctx, uint8_t *output, - uint8_t output_length); + size_t output_length); +void chacha_drbg_reseed(CHACHA_DRBG_CTX *ctx, const uint8_t *entropy, + size_t entropy_length, const uint8_t *additional_input, + size_t additional_input_length); #endif // __CHACHA_DRBG__ diff --git a/trezor-crypto/include/TrezorCrypto/curves.h b/trezor-crypto/include/TrezorCrypto/curves.h index d65d1fe953f..d8d423563c6 100644 --- a/trezor-crypto/include/TrezorCrypto/curves.h +++ b/trezor-crypto/include/TrezorCrypto/curves.h @@ -35,16 +35,16 @@ extern const char SECP256K1_GROESTL_NAME[]; extern const char SECP256K1_SMART_NAME[]; extern const char NIST256P1_NAME[]; extern const char ED25519_NAME[]; -// [wallet-core] +extern const char ED25519_SEED_NAME[]; extern const char ED25519_CARDANO_NAME[]; -// [wallet-core] -extern const char ED25519_BLAKE2B_NANO_NAME[]; extern const char ED25519_SHA3_NAME[]; #if USE_KECCAK extern const char ED25519_KECCAK_NAME[]; #endif extern const char CURVE25519_NAME[]; +extern const char ED25519_BLAKE2B_NANO_NAME[]; // [wallet-core] + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/trezor-crypto/include/TrezorCrypto/ecdsa.h b/trezor-crypto/include/TrezorCrypto/ecdsa.h index 4d9046d5c82..48033642325 100644 --- a/trezor-crypto/include/TrezorCrypto/ecdsa.h +++ b/trezor-crypto/include/TrezorCrypto/ecdsa.h @@ -70,14 +70,14 @@ void point_copy(const curve_point *cp1, curve_point *cp2); void point_add(const ecdsa_curve *curve, const curve_point *cp1, curve_point *cp2); void point_double(const ecdsa_curve *curve, curve_point *cp); -void point_multiply(const ecdsa_curve *curve, const bignum256 *k, - const curve_point *p, curve_point *res); +int point_multiply(const ecdsa_curve *curve, const bignum256 *k, + const curve_point *p, curve_point *res); void point_set_infinity(curve_point *p); int point_is_infinity(const curve_point *p); int point_is_equal(const curve_point *p, const curve_point *q); int point_is_negative_of(const curve_point *p, const curve_point *q); -void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, - curve_point *res); +int scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, + curve_point *res); int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *pub_key, uint8_t *session_key); void compress_coords(const curve_point *cp, uint8_t *compressed); @@ -93,10 +93,10 @@ int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); -void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, - uint8_t *pub_key); -void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, - uint8_t *pub_key); +int ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, + uint8_t *pub_key); +int ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, + uint8_t *pub_key); void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, uint8_t *pubkeyhash); void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, @@ -130,10 +130,6 @@ int ecdsa_recover_pub_from_sig(const ecdsa_curve *curve, uint8_t *pub_key, int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der); int ecdsa_sig_from_der(const uint8_t *der, size_t der_len, uint8_t sig[64]); -// [wallet-core] -int zil_schnorr_sign(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *msg, const uint32_t msg_len, uint8_t *sig); -int zil_schnorr_verify(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, const uint32_t msg_len); - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/trezor-crypto/include/TrezorCrypto/ed25519-donna/ed25519-blake2b.h b/trezor-crypto/include/TrezorCrypto/ed25519-donna/ed25519-blake2b.h index 9dddc5f7401..f9bd619e93c 100644 --- a/trezor-crypto/include/TrezorCrypto/ed25519-donna/ed25519-blake2b.h +++ b/trezor-crypto/include/TrezorCrypto/ed25519-donna/ed25519-blake2b.h @@ -10,7 +10,7 @@ extern "C" { void ed25519_publickey_blake2b(const ed25519_secret_key sk, ed25519_public_key pk); int ed25519_sign_open_blake2b(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); -void ed25519_sign_blake2b(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); +void ed25519_sign_blake2b(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS); int ed25519_scalarmult_blake2b(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); diff --git a/trezor-crypto/include/TrezorCrypto/ed25519-donna/ed25519-keccak.h b/trezor-crypto/include/TrezorCrypto/ed25519-donna/ed25519-keccak.h index fa63770e92b..58fd8355ae4 100644 --- a/trezor-crypto/include/TrezorCrypto/ed25519-donna/ed25519-keccak.h +++ b/trezor-crypto/include/TrezorCrypto/ed25519-donna/ed25519-keccak.h @@ -10,7 +10,7 @@ extern "C" { void ed25519_publickey_keccak(const ed25519_secret_key sk, ed25519_public_key pk); int ed25519_sign_open_keccak(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); -void ed25519_sign_keccak(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); +void ed25519_sign_keccak(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS); int ed25519_scalarmult_keccak(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); diff --git a/trezor-crypto/include/TrezorCrypto/ed25519-donna/ed25519-sha3.h b/trezor-crypto/include/TrezorCrypto/ed25519-donna/ed25519-sha3.h index e8a62d0dca3..3adcf84891f 100644 --- a/trezor-crypto/include/TrezorCrypto/ed25519-donna/ed25519-sha3.h +++ b/trezor-crypto/include/TrezorCrypto/ed25519-donna/ed25519-sha3.h @@ -10,7 +10,7 @@ extern "C" { void ed25519_publickey_sha3(const ed25519_secret_key sk, ed25519_public_key pk); int ed25519_sign_open_sha3(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); -void ed25519_sign_sha3(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); +void ed25519_sign_sha3(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS); int ed25519_scalarmult_sha3(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); diff --git a/trezor-crypto/include/TrezorCrypto/ed25519.h b/trezor-crypto/include/TrezorCrypto/ed25519.h index 78a27a279ed..6b4c098b963 100644 --- a/trezor-crypto/include/TrezorCrypto/ed25519.h +++ b/trezor-crypto/include/TrezorCrypto/ed25519.h @@ -16,15 +16,11 @@ typedef unsigned char curve25519_key[32]; typedef unsigned char ed25519_cosi_signature[32]; void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk); -#if USE_CARDANO -void ed25519_publickey_ext(const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_public_key pk); -#endif +void ed25519_publickey_ext(const ed25519_secret_key extsk, ed25519_public_key pk); int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS); -void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS); -#if USE_CARDANO -void ed25519_sign_ext(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, const ed25519_public_key pk, ed25519_signature RS); -#endif +void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, ed25519_signature RS); +void ed25519_sign_ext(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_signature RS); int ed25519_scalarmult(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk); diff --git a/trezor-crypto/include/TrezorCrypto/rfc6979.h b/trezor-crypto/include/TrezorCrypto/rfc6979.h index 3e409535093..e4cb9ff049f 100644 --- a/trezor-crypto/include/TrezorCrypto/rfc6979.h +++ b/trezor-crypto/include/TrezorCrypto/rfc6979.h @@ -27,13 +27,14 @@ #include #include "bignum.h" +#include "ecdsa.h" #include "hmac_drbg.h" // rfc6979 pseudo random number generator state typedef HMAC_DRBG_CTX rfc6979_state; void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, - rfc6979_state *rng); + const ecdsa_curve *curve, rfc6979_state *rng); void generate_rfc6979(uint8_t rnd[32], rfc6979_state *rng); void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng); diff --git a/trezor-crypto/include/TrezorCrypto/slip39.h b/trezor-crypto/include/TrezorCrypto/slip39.h new file mode 100644 index 00000000000..08883edf2b5 --- /dev/null +++ b/trezor-crypto/include/TrezorCrypto/slip39.h @@ -0,0 +1,47 @@ +/** + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SLIP39_H__ +#define __SLIP39_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +const char* get_word(uint16_t index); + +bool word_index(uint16_t* index, const char* word, uint8_t word_length); + +uint16_t slip39_word_completion_mask(uint16_t prefix); + +const char* button_sequence_to_word(uint16_t prefix); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/trezor-crypto/include/TrezorCrypto/slip39_wordlist.h b/trezor-crypto/include/TrezorCrypto/slip39_wordlist.h new file mode 100644 index 00000000000..3464aae9412 --- /dev/null +++ b/trezor-crypto/include/TrezorCrypto/slip39_wordlist.h @@ -0,0 +1,1246 @@ +/** + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SLIP39_WORDLIST_H__ +#define __SLIP39_WORDLIST_H__ + +#include + +#define WORDS_COUNT 1024 + +static const char* const slip39_wordlist[WORDS_COUNT] = { + "academic", "acid", "acne", "acquire", "acrobat", "activity", + "actress", "adapt", "adequate", "adjust", "admit", "adorn", + "adult", "advance", "advocate", "afraid", "again", "agency", + "agree", "aide", "aircraft", "airline", "airport", "ajar", + "alarm", "album", "alcohol", "alien", "alive", "alpha", + "already", "alto", "aluminum", "always", "amazing", "ambition", + "amount", "amuse", "analysis", "anatomy", "ancestor", "ancient", + "angel", "angry", "animal", "answer", "antenna", "anxiety", + "apart", "aquatic", "arcade", "arena", "argue", "armed", + "artist", "artwork", "aspect", "auction", "august", "aunt", + "average", "aviation", "avoid", "award", "away", "axis", + "axle", "beam", "beard", "beaver", "become", "bedroom", + "behavior", "being", "believe", "belong", "benefit", "best", + "beyond", "bike", "biology", "birthday", "bishop", "black", + "blanket", "blessing", "blimp", "blind", "blue", "body", + "bolt", "boring", "born", "both", "boundary", "bracelet", + "branch", "brave", "breathe", "briefing", "broken", "brother", + "browser", "bucket", "budget", "building", "bulb", "bulge", + "bumpy", "bundle", "burden", "burning", "busy", "buyer", + "cage", "calcium", "camera", "campus", "canyon", "capacity", + "capital", "capture", "carbon", "cards", "careful", "cargo", + "carpet", "carve", "category", "cause", "ceiling", "center", + "ceramic", "champion", "change", "charity", "check", "chemical", + "chest", "chew", "chubby", "cinema", "civil", "class", + "clay", "cleanup", "client", "climate", "clinic", "clock", + "clogs", "closet", "clothes", "club", "cluster", "coal", + "coastal", "coding", "column", "company", "corner", "costume", + "counter", "course", "cover", "cowboy", "cradle", "craft", + "crazy", "credit", "cricket", "criminal", "crisis", "critical", + "crowd", "crucial", "crunch", "crush", "crystal", "cubic", + "cultural", "curious", "curly", "custody", "cylinder", "daisy", + "damage", "dance", "darkness", "database", "daughter", "deadline", + "deal", "debris", "debut", "decent", "decision", "declare", + "decorate", "decrease", "deliver", "demand", "density", "deny", + "depart", "depend", "depict", "deploy", "describe", "desert", + "desire", "desktop", "destroy", "detailed", "detect", "device", + "devote", "diagnose", "dictate", "diet", "dilemma", "diminish", + "dining", "diploma", "disaster", "discuss", "disease", "dish", + "dismiss", "display", "distance", "dive", "divorce", "document", + "domain", "domestic", "dominant", "dough", "downtown", "dragon", + "dramatic", "dream", "dress", "drift", "drink", "drove", + "drug", "dryer", "duckling", "duke", "duration", "dwarf", + "dynamic", "early", "earth", "easel", "easy", "echo", + "eclipse", "ecology", "edge", "editor", "educate", "either", + "elbow", "elder", "election", "elegant", "element", "elephant", + "elevator", "elite", "else", "email", "emerald", "emission", + "emperor", "emphasis", "employer", "empty", "ending", "endless", + "endorse", "enemy", "energy", "enforce", "engage", "enjoy", + "enlarge", "entrance", "envelope", "envy", "epidemic", "episode", + "equation", "equip", "eraser", "erode", "escape", "estate", + "estimate", "evaluate", "evening", "evidence", "evil", "evoke", + "exact", "example", "exceed", "exchange", "exclude", "excuse", + "execute", "exercise", "exhaust", "exotic", "expand", "expect", + "explain", "express", "extend", "extra", "eyebrow", "facility", + "fact", "failure", "faint", "fake", "false", "family", + "famous", "fancy", "fangs", "fantasy", "fatal", "fatigue", + "favorite", "fawn", "fiber", "fiction", "filter", "finance", + "findings", "finger", "firefly", "firm", "fiscal", "fishing", + "fitness", "flame", "flash", "flavor", "flea", "flexible", + "flip", "float", "floral", "fluff", "focus", "forbid", + "force", "forecast", "forget", "formal", "fortune", "forward", + "founder", "fraction", "fragment", "frequent", "freshman", "friar", + "fridge", "friendly", "frost", "froth", "frozen", "fumes", + "funding", "furl", "fused", "galaxy", "game", "garbage", + "garden", "garlic", "gasoline", "gather", "general", "genius", + "genre", "genuine", "geology", "gesture", "glad", "glance", + "glasses", "glen", "glimpse", "goat", "golden", "graduate", + "grant", "grasp", "gravity", "gray", "greatest", "grief", + "grill", "grin", "grocery", "gross", "group", "grownup", + "grumpy", "guard", "guest", "guilt", "guitar", "gums", + "hairy", "hamster", "hand", "hanger", "harvest", "have", + "havoc", "hawk", "hazard", "headset", "health", "hearing", + "heat", "helpful", "herald", "herd", "hesitate", "hobo", + "holiday", "holy", "home", "hormone", "hospital", "hour", + "huge", "human", "humidity", "hunting", "husband", "hush", + "husky", "hybrid", "idea", "identify", "idle", "image", + "impact", "imply", "improve", "impulse", "include", "income", + "increase", "index", "indicate", "industry", "infant", "inform", + "inherit", "injury", "inmate", "insect", "inside", "install", + "intend", "intimate", "invasion", "involve", "iris", "island", + "isolate", "item", "ivory", "jacket", "jerky", "jewelry", + "join", "judicial", "juice", "jump", "junction", "junior", + "junk", "jury", "justice", "kernel", "keyboard", "kidney", + "kind", "kitchen", "knife", "knit", "laden", "ladle", + "ladybug", "lair", "lamp", "language", "large", "laser", + "laundry", "lawsuit", "leader", "leaf", "learn", "leaves", + "lecture", "legal", "legend", "legs", "lend", "length", + "level", "liberty", "library", "license", "lift", "likely", + "lilac", "lily", "lips", "liquid", "listen", "literary", + "living", "lizard", "loan", "lobe", "location", "losing", + "loud", "loyalty", "luck", "lunar", "lunch", "lungs", + "luxury", "lying", "lyrics", "machine", "magazine", "maiden", + "mailman", "main", "makeup", "making", "mama", "manager", + "mandate", "mansion", "manual", "marathon", "march", "market", + "marvel", "mason", "material", "math", "maximum", "mayor", + "meaning", "medal", "medical", "member", "memory", "mental", + "merchant", "merit", "method", "metric", "midst", "mild", + "military", "mineral", "minister", "miracle", "mixed", "mixture", + "mobile", "modern", "modify", "moisture", "moment", "morning", + "mortgage", "mother", "mountain", "mouse", "move", "much", + "mule", "multiple", "muscle", "museum", "music", "mustang", + "nail", "national", "necklace", "negative", "nervous", "network", + "news", "nuclear", "numb", "numerous", "nylon", "oasis", + "obesity", "object", "observe", "obtain", "ocean", "often", + "olympic", "omit", "oral", "orange", "orbit", "order", + "ordinary", "organize", "ounce", "oven", "overall", "owner", + "paces", "pacific", "package", "paid", "painting", "pajamas", + "pancake", "pants", "papa", "paper", "parcel", "parking", + "party", "patent", "patrol", "payment", "payroll", "peaceful", + "peanut", "peasant", "pecan", "penalty", "pencil", "percent", + "perfect", "permit", "petition", "phantom", "pharmacy", "photo", + "phrase", "physics", "pickup", "picture", "piece", "pile", + "pink", "pipeline", "pistol", "pitch", "plains", "plan", + "plastic", "platform", "playoff", "pleasure", "plot", "plunge", + "practice", "prayer", "preach", "predator", "pregnant", "premium", + "prepare", "presence", "prevent", "priest", "primary", "priority", + "prisoner", "privacy", "prize", "problem", "process", "profile", + "program", "promise", "prospect", "provide", "prune", "public", + "pulse", "pumps", "punish", "puny", "pupal", "purchase", + "purple", "python", "quantity", "quarter", "quick", "quiet", + "race", "racism", "radar", "railroad", "rainbow", "raisin", + "random", "ranked", "rapids", "raspy", "reaction", "realize", + "rebound", "rebuild", "recall", "receiver", "recover", "regret", + "regular", "reject", "relate", "remember", "remind", "remove", + "render", "repair", "repeat", "replace", "require", "rescue", + "research", "resident", "response", "result", "retailer", "retreat", + "reunion", "revenue", "review", "reward", "rhyme", "rhythm", + "rich", "rival", "river", "robin", "rocky", "romantic", + "romp", "roster", "round", "royal", "ruin", "ruler", + "rumor", "sack", "safari", "salary", "salon", "salt", + "satisfy", "satoshi", "saver", "says", "scandal", "scared", + "scatter", "scene", "scholar", "science", "scout", "scramble", + "screw", "script", "scroll", "seafood", "season", "secret", + "security", "segment", "senior", "shadow", "shaft", "shame", + "shaped", "sharp", "shelter", "sheriff", "short", "should", + "shrimp", "sidewalk", "silent", "silver", "similar", "simple", + "single", "sister", "skin", "skunk", "slap", "slavery", + "sled", "slice", "slim", "slow", "slush", "smart", + "smear", "smell", "smirk", "smith", "smoking", "smug", + "snake", "snapshot", "sniff", "society", "software", "soldier", + "solution", "soul", "source", "space", "spark", "speak", + "species", "spelling", "spend", "spew", "spider", "spill", + "spine", "spirit", "spit", "spray", "sprinkle", "square", + "squeeze", "stadium", "staff", "standard", "starting", "station", + "stay", "steady", "step", "stick", "stilt", "story", + "strategy", "strike", "style", "subject", "submit", "sugar", + "suitable", "sunlight", "superior", "surface", "surprise", "survive", + "sweater", "swimming", "swing", "switch", "symbolic", "sympathy", + "syndrome", "system", "tackle", "tactics", "tadpole", "talent", + "task", "taste", "taught", "taxi", "teacher", "teammate", + "teaspoon", "temple", "tenant", "tendency", "tension", "terminal", + "testify", "texture", "thank", "that", "theater", "theory", + "therapy", "thorn", "threaten", "thumb", "thunder", "ticket", + "tidy", "timber", "timely", "ting", "tofu", "together", + "tolerate", "total", "toxic", "tracks", "traffic", "training", + "transfer", "trash", "traveler", "treat", "trend", "trial", + "tricycle", "trip", "triumph", "trouble", "true", "trust", + "twice", "twin", "type", "typical", "ugly", "ultimate", + "umbrella", "uncover", "undergo", "unfair", "unfold", "unhappy", + "union", "universe", "unkind", "unknown", "unusual", "unwrap", + "upgrade", "upstairs", "username", "usher", "usual", "valid", + "valuable", "vampire", "vanish", "various", "vegan", "velvet", + "venture", "verdict", "verify", "very", "veteran", "vexed", + "victim", "video", "view", "vintage", "violence", "viral", + "visitor", "visual", "vitamins", "vocal", "voice", "volume", + "voter", "voting", "walnut", "warmth", "warn", "watch", + "wavy", "wealthy", "weapon", "webcam", "welcome", "welfare", + "western", "width", "wildlife", "window", "wine", "wireless", + "wisdom", "withdraw", "wits", "wolf", "woman", "work", + "worthy", "wrap", "wrist", "writing", "wrote", "year", + "yelp", "yield", "yoga", "zero", +}; + +/** + * This array contains number representations of SLIP-39 words. + * These numbers are determined how the words were entered on a + * T9 keyboard with the following layout: + * ab (1) cd (2) ef (3) + * ghij (4) klm (5) nopq (6) + * rs (7) tuv (8) wxyz (9) + * + * Each word is uniquely defined by four buttons. + */ +static const struct { + uint16_t sequence; + uint16_t index; +} words_button_seq[WORDS_COUNT] = { + {1212, 0}, // academic + {1216, 7}, // adapt + {1236, 8}, // adequate + {1242, 1}, // acid + {1248, 9}, // adjust + {1254, 10}, // admit + {1263, 2}, // acne + {1267, 11}, // adorn + {1268, 3}, // acquire + {1276, 4}, // acrobat + {1281, 13}, // advance + {1284, 5}, // activity + {1285, 12}, // adult + {1286, 14}, // advocate + {1287, 6}, // actress + {1315, 67}, // beam + {1317, 68}, // beard + {1318, 69}, // beaver + {1326, 70}, // become + {1327, 71}, // bedroom + {1341, 72}, // behavior + {1346, 73}, // being + {1354, 74}, // believe + {1356, 75}, // belong + {1363, 76}, // benefit + {1371, 15}, // afraid + {1378, 77}, // best + {1396, 78}, // beyond + {1414, 16}, // again + {1417, 23}, // ajar + {1423, 19}, // aide + {1436, 17}, // agency + {1453, 79}, // bike + {1465, 80}, // biology + {1472, 20}, // aircraft + {1473, 18}, // agree + {1474, 82}, // bishop + {1475, 21}, // airline + {1476, 22}, // airport + {1478, 81}, // birthday + {1512, 83}, // black + {1514, 35}, // ambition + {1516, 84}, // blanket + {1517, 24}, // alarm + {1518, 25}, // album + {1519, 34}, // amazing + {1526, 26}, // alcohol + {1537, 85}, // blessing + {1543, 27}, // alien + {1545, 86}, // blimp + {1546, 87}, // blind + {1548, 28}, // alive + {1564, 29}, // alpha + {1568, 36}, // amount + {1573, 30}, // already + {1583, 88}, // blue + {1585, 32}, // aluminum + {1586, 31}, // alto + {1587, 37}, // amuse + {1591, 33}, // always + {1615, 38}, // analysis + {1617, 48}, // apart + {1618, 39}, // anatomy + {1623, 40}, // ancestor + {1624, 41}, // ancient + {1629, 89}, // body + {1643, 42}, // angel + {1645, 44}, // animal + {1647, 43}, // angry + {1658, 90}, // bolt + {1674, 91}, // boring + {1676, 92}, // born + {1679, 45}, // answer + {1681, 49}, // aquatic + {1683, 46}, // antenna + {1684, 93}, // both + {1686, 94}, // boundary + {1694, 47}, // anxiety + {1712, 95}, // bracelet + {1716, 96}, // branch + {1718, 97}, // brave + {1721, 50}, // arcade + {1731, 98}, // breathe + {1736, 51}, // arena + {1743, 99}, // briefing + {1748, 52}, // argue + {1753, 53}, // armed + {1763, 56}, // aspect + {1765, 100}, // broken + {1768, 101}, // brother + {1769, 102}, // browser + {1784, 54}, // artist + {1789, 55}, // artwork + {1824, 104}, // budget + {1825, 103}, // bucket + {1828, 57}, // auction + {1837, 60}, // average + {1841, 61}, // aviation + {1845, 105}, // building + {1848, 58}, // august + {1851, 106}, // bulb + {1854, 107}, // bulge + {1856, 108}, // bumpy + {1862, 109}, // bundle + {1864, 62}, // avoid + {1868, 59}, // aunt + {1872, 110}, // burden + {1876, 111}, // burning + {1879, 112}, // busy + {1893, 113}, // buyer + {1917, 63}, // award + {1919, 64}, // away + {1947, 65}, // axis + {1953, 66}, // axle + {2143, 114}, // cage + {2147, 185}, // daisy + {2151, 186}, // damage + {2152, 115}, // calcium + {2153, 116}, // camera + {2156, 117}, // campus + {2161, 119}, // capacity + {2162, 187}, // dance + {2164, 120}, // capital + {2168, 121}, // capture + {2169, 118}, // canyon + {2171, 122}, // carbon + {2172, 123}, // cards + {2173, 124}, // careful + {2174, 125}, // cargo + {2175, 188}, // darkness + {2176, 126}, // carpet + {2178, 127}, // carve + {2181, 189}, // database + {2183, 128}, // category + {2184, 190}, // daughter + {2187, 129}, // cause + {2312, 191}, // deadline + {2315, 192}, // deal + {2317, 193}, // debris + {2318, 194}, // debut + {2323, 195}, // decent + {2324, 196}, // decision + {2325, 197}, // declare + {2326, 198}, // decorate + {2327, 199}, // decrease + {2345, 130}, // ceiling + {2351, 201}, // demand + {2354, 200}, // deliver + {2361, 204}, // depart + {2363, 205}, // depend + {2364, 206}, // depict + {2365, 207}, // deploy + {2367, 202}, // density + {2368, 131}, // center + {2369, 203}, // deny + {2371, 132}, // ceramic + {2372, 208}, // describe + {2373, 209}, // desert + {2374, 210}, // desire + {2375, 211}, // desktop + {2378, 212}, // destroy + {2381, 213}, // detailed + {2383, 214}, // detect + {2384, 215}, // device + {2386, 216}, // devote + {2414, 217}, // diagnose + {2415, 133}, // champion + {2416, 134}, // change + {2417, 135}, // charity + {2428, 218}, // dictate + {2432, 136}, // check + {2435, 137}, // chemical + {2437, 138}, // chest + {2438, 219}, // diet + {2439, 139}, // chew + {2453, 220}, // dilemma + {2454, 221}, // diminish + {2463, 141}, // cinema + {2464, 222}, // dining + {2465, 223}, // diploma + {2471, 224}, // disaster + {2472, 225}, // discuss + {2473, 226}, // disease + {2474, 227}, // dish + {2475, 228}, // dismiss + {2476, 229}, // display + {2478, 230}, // distance + {2481, 140}, // chubby + {2483, 231}, // dive + {2484, 142}, // civil + {2486, 232}, // divorce + {2517, 143}, // class + {2519, 144}, // clay + {2531, 145}, // cleanup + {2543, 146}, // client + {2545, 147}, // climate + {2546, 148}, // clinic + {2562, 149}, // clock + {2564, 150}, // clogs + {2567, 151}, // closet + {2568, 152}, // clothes + {2581, 153}, // club + {2587, 154}, // cluster + {2615, 155}, // coal + {2617, 156}, // coastal + {2624, 157}, // coding + {2628, 233}, // document + {2651, 234}, // domain + {2653, 235}, // domestic + {2654, 236}, // dominant + {2656, 159}, // company + {2658, 158}, // column + {2676, 160}, // corner + {2678, 161}, // costume + {2683, 164}, // cover + {2684, 237}, // dough + {2686, 162}, // counter + {2687, 163}, // course + {2691, 165}, // cowboy + {2696, 238}, // downtown + {2712, 166}, // cradle + {2713, 167}, // craft + {2714, 239}, // dragon + {2715, 240}, // dramatic + {2719, 168}, // crazy + {2731, 241}, // dream + {2732, 169}, // credit + {2737, 242}, // dress + {2742, 170}, // cricket + {2743, 243}, // drift + {2745, 171}, // criminal + {2746, 244}, // drink + {2747, 172}, // crisis + {2748, 173}, // critical + {2768, 245}, // drove + {2769, 174}, // crowd + {2782, 175}, // crucial + {2784, 246}, // drug + {2786, 176}, // crunch + {2787, 177}, // crush + {2793, 247}, // dryer + {2797, 178}, // crystal + {2814, 179}, // cubic + {2825, 248}, // duckling + {2853, 249}, // duke + {2858, 180}, // cultural + {2871, 250}, // duration + {2874, 181}, // curious + {2875, 182}, // curly + {2878, 183}, // custody + {2917, 251}, // dwarf + {2954, 184}, // cylinder + {2961, 252}, // dynamic + {3124, 323}, // facility + {3128, 324}, // fact + {3145, 325}, // failure + {3146, 326}, // faint + {3153, 327}, // fake + {3154, 329}, // family + {3156, 330}, // famous + {3157, 328}, // false + {3162, 331}, // fancy + {3164, 332}, // fangs + {3168, 333}, // fantasy + {3173, 255}, // easel + {3175, 253}, // early + {3178, 254}, // earth + {3179, 256}, // easy + {3181, 334}, // fatal + {3184, 335}, // fatigue + {3186, 336}, // favorite + {3196, 337}, // fawn + {3243, 260}, // edge + {3246, 257}, // echo + {3248, 261}, // editor + {3254, 258}, // eclipse + {3265, 259}, // ecology + {3282, 262}, // educate + {3413, 338}, // fiber + {3428, 339}, // fiction + {3458, 340}, // filter + {3461, 341}, // finance + {3462, 342}, // findings + {3464, 343}, // finger + {3472, 346}, // fiscal + {3473, 344}, // firefly + {3474, 347}, // fishing + {3475, 345}, // firm + {3484, 263}, // either + {3486, 348}, // fitness + {3514, 273}, // email + {3515, 349}, // flame + {3516, 264}, // elbow + {3517, 350}, // flash + {3518, 351}, // flavor + {3523, 265}, // elder + {3531, 352}, // flea + {3532, 266}, // election + {3534, 267}, // elegant + {3535, 268}, // element + {3536, 269}, // elephant + {3537, 274}, // emerald + {3538, 270}, // elevator + {3539, 353}, // flexible + {3546, 354}, // flip + {3547, 275}, // emission + {3548, 271}, // elite + {3561, 355}, // float + {3563, 276}, // emperor + {3564, 277}, // emphasis + {3565, 278}, // employer + {3567, 356}, // floral + {3568, 279}, // empty + {3573, 272}, // else + {3583, 357}, // fluff + {3624, 280}, // ending + {3625, 281}, // endless + {3626, 282}, // endorse + {3628, 358}, // focus + {3635, 283}, // enemy + {3636, 285}, // enforce + {3637, 284}, // energy + {3641, 286}, // engage + {3642, 292}, // epidemic + {3646, 287}, // enjoy + {3647, 293}, // episode + {3651, 288}, // enlarge + {3671, 359}, // forbid + {3672, 360}, // force + {3673, 361}, // forecast + {3674, 362}, // forget + {3675, 363}, // formal + {3678, 364}, // fortune + {3679, 365}, // forward + {3681, 294}, // equation + {3683, 290}, // envelope + {3684, 295}, // equip + {3686, 366}, // founder + {3687, 289}, // entrance + {3689, 291}, // envy + {3712, 367}, // fraction + {3714, 368}, // fragment + {3717, 296}, // eraser + {3721, 298}, // escape + {3736, 369}, // frequent + {3737, 370}, // freshman + {3741, 371}, // friar + {3742, 372}, // fridge + {3743, 373}, // friendly + {3762, 297}, // erode + {3767, 374}, // frost + {3768, 375}, // froth + {3769, 376}, // frozen + {3781, 299}, // estate + {3784, 300}, // estimate + {3815, 301}, // evaluate + {3836, 302}, // evening + {3842, 303}, // evidence + {3845, 304}, // evil + {3853, 377}, // fumes + {3862, 378}, // funding + {3865, 305}, // evoke + {3873, 380}, // fused + {3875, 379}, // furl + {3912, 306}, // exact + {3915, 307}, // example + {3923, 308}, // exceed + {3924, 309}, // exchange + {3925, 310}, // exclude + {3928, 311}, // excuse + {3931, 322}, // eyebrow + {3932, 312}, // execute + {3937, 313}, // exercise + {3941, 314}, // exhaust + {3961, 316}, // expand + {3963, 317}, // expect + {3965, 318}, // explain + {3967, 319}, // express + {3968, 315}, // exotic + {3983, 320}, // extend + {3987, 321}, // extra + {4125, 483}, // jacket + {4147, 420}, // hairy + {4151, 381}, // galaxy + {4153, 382}, // game + {4157, 421}, // hamster + {4162, 422}, // hand + {4164, 423}, // hanger + {4171, 383}, // garbage + {4172, 384}, // garden + {4175, 385}, // garlic + {4176, 386}, // gasoline + {4178, 424}, // harvest + {4183, 425}, // have + {4184, 387}, // gather + {4186, 426}, // havoc + {4191, 428}, // hazard + {4195, 427}, // hawk + {4231, 452}, // idea + {4236, 453}, // identify + {4253, 454}, // idle + {4312, 429}, // headset + {4315, 430}, // health + {4317, 431}, // hearing + {4318, 432}, // heat + {4356, 433}, // helpful + {4363, 388}, // general + {4364, 389}, // genius + {4365, 392}, // geology + {4367, 390}, // genre + {4368, 391}, // genuine + {4371, 434}, // herald + {4372, 435}, // herd + {4374, 436}, // hesitate + {4375, 484}, // jerky + {4378, 393}, // gesture + {4393, 485}, // jewelry + {4512, 394}, // glad + {4514, 455}, // image + {4516, 395}, // glance + {4517, 396}, // glasses + {4536, 397}, // glen + {4545, 398}, // glimpse + {4561, 456}, // impact + {4565, 457}, // imply + {4567, 458}, // improve + {4568, 459}, // impulse + {4616, 437}, // hobo + {4618, 399}, // goat + {4623, 463}, // index + {4624, 464}, // indicate + {4625, 460}, // include + {4626, 461}, // income + {4627, 462}, // increase + {4628, 465}, // industry + {4631, 466}, // infant + {4636, 467}, // inform + {4643, 468}, // inherit + {4646, 486}, // join + {4648, 469}, // injury + {4651, 470}, // inmate + {4652, 400}, // golden + {4653, 440}, // home + {4654, 438}, // holiday + {4659, 439}, // holy + {4673, 471}, // insect + {4674, 472}, // inside + {4675, 441}, // hormone + {4676, 442}, // hospital + {4678, 473}, // install + {4681, 476}, // invasion + {4683, 474}, // intend + {4684, 475}, // intimate + {4686, 477}, // involve + {4687, 443}, // hour + {4712, 401}, // graduate + {4716, 402}, // grant + {4717, 403}, // grasp + {4718, 404}, // gravity + {4719, 405}, // gray + {4731, 406}, // greatest + {4743, 407}, // grief + {4745, 408}, // grill + {4746, 409}, // grin + {4747, 478}, // iris + {4751, 479}, // island + {4762, 410}, // grocery + {4765, 480}, // isolate + {4767, 411}, // gross + {4768, 412}, // group + {4769, 413}, // grownup + {4785, 414}, // grumpy + {4817, 415}, // guard + {4824, 487}, // judicial + {4835, 481}, // item + {4837, 416}, // guest + {4842, 488}, // juice + {4843, 444}, // huge + {4845, 417}, // guilt + {4848, 418}, // guitar + {4851, 445}, // human + {4854, 446}, // humidity + {4856, 489}, // jump + {4857, 419}, // gums + {4862, 490}, // junction + {4864, 491}, // junior + {4865, 492}, // junk + {4867, 482}, // ivory + {4868, 447}, // hunting + {4871, 448}, // husband + {4874, 449}, // hush + {4875, 450}, // husky + {4878, 494}, // justice + {4879, 493}, // jury + {4917, 451}, // hybrid + {5123, 502}, // laden + {5124, 549}, // machine + {5125, 503}, // ladle + {5129, 504}, // ladybug + {5141, 550}, // magazine + {5142, 551}, // maiden + {5145, 552}, // mailman + {5146, 553}, // main + {5147, 505}, // lair + {5151, 556}, // mama + {5153, 554}, // makeup + {5154, 555}, // making + {5156, 506}, // lamp + {5161, 557}, // manager + {5162, 558}, // mandate + {5164, 507}, // language + {5167, 559}, // mansion + {5168, 560}, // manual + {5171, 561}, // marathon + {5172, 562}, // march + {5173, 509}, // laser + {5174, 508}, // large + {5175, 563}, // market + {5176, 565}, // mason + {5178, 564}, // marvel + {5183, 566}, // material + {5184, 567}, // math + {5186, 510}, // laundry + {5194, 568}, // maximum + {5196, 569}, // mayor + {5197, 511}, // lawsuit + {5312, 512}, // leader + {5313, 513}, // leaf + {5316, 570}, // meaning + {5317, 514}, // learn + {5318, 515}, // leaves + {5321, 571}, // medal + {5324, 572}, // medical + {5328, 516}, // lecture + {5341, 517}, // legal + {5343, 518}, // legend + {5347, 519}, // legs + {5351, 573}, // member + {5356, 574}, // memory + {5362, 520}, // lend + {5364, 521}, // length + {5368, 575}, // mental + {5372, 576}, // merchant + {5374, 577}, // merit + {5376, 495}, // kernel + {5383, 522}, // level + {5384, 578}, // method + {5387, 579}, // metric + {5391, 496}, // keyboard + {5413, 523}, // liberty + {5417, 524}, // library + {5423, 525}, // license + {5426, 497}, // kidney + {5427, 580}, // midst + {5438, 526}, // lift + {5451, 528}, // lilac + {5452, 581}, // mild + {5453, 527}, // likely + {5454, 582}, // military + {5459, 529}, // lily + {5462, 498}, // kind + {5463, 583}, // mineral + {5464, 584}, // minister + {5467, 530}, // lips + {5468, 531}, // liquid + {5471, 585}, // miracle + {5478, 532}, // listen + {5482, 499}, // kitchen + {5483, 533}, // literary + {5484, 534}, // living + {5491, 535}, // lizard + {5493, 586}, // mixed + {5498, 587}, // mixture + {5613, 537}, // lobe + {5614, 588}, // mobile + {5616, 536}, // loan + {5621, 538}, // location + {5623, 589}, // modern + {5624, 590}, // modify + {5643, 500}, // knife + {5647, 591}, // moisture + {5648, 501}, // knit + {5653, 592}, // moment + {5674, 539}, // losing + {5676, 593}, // morning + {5678, 594}, // mortgage + {5682, 540}, // loud + {5683, 598}, // move + {5684, 595}, // mother + {5686, 596}, // mountain + {5687, 597}, // mouse + {5691, 541}, // loyalty + {5824, 599}, // much + {5825, 542}, // luck + {5853, 600}, // mule + {5858, 601}, // multiple + {5861, 543}, // lunar + {5862, 544}, // lunch + {5864, 545}, // lungs + {5872, 602}, // muscle + {5873, 603}, // museum + {5874, 604}, // music + {5878, 605}, // mustang + {5898, 546}, // luxury + {5946, 547}, // lying + {5974, 548}, // lyrics + {6123, 636}, // paces + {6124, 637}, // pacific + {6125, 638}, // package + {6137, 618}, // obesity + {6141, 641}, // pajamas + {6142, 639}, // paid + {6143, 619}, // object + {6145, 606}, // nail + {6146, 640}, // painting + {6161, 644}, // papa + {6162, 642}, // pancake + {6163, 645}, // paper + {6168, 643}, // pants + {6172, 646}, // parcel + {6173, 620}, // observe + {6174, 617}, // oasis + {6175, 647}, // parking + {6178, 648}, // party + {6181, 621}, // obtain + {6183, 649}, // patent + {6184, 607}, // national + {6187, 650}, // patrol + {6195, 651}, // payment + {6197, 652}, // payroll + {6231, 622}, // ocean + {6312, 653}, // peaceful + {6316, 654}, // peanut + {6317, 655}, // peasant + {6321, 656}, // pecan + {6325, 608}, // necklace + {6341, 609}, // negative + {6361, 657}, // penalty + {6362, 658}, // pencil + {6372, 659}, // percent + {6373, 660}, // perfect + {6375, 661}, // permit + {6378, 610}, // nervous + {6383, 623}, // often + {6384, 662}, // petition + {6389, 611}, // network + {6397, 612}, // news + {6416, 663}, // phantom + {6417, 664}, // pharmacy + {6425, 668}, // pickup + {6428, 669}, // picture + {6432, 670}, // piece + {6453, 671}, // pile + {6463, 673}, // pipeline + {6465, 672}, // pink + {6468, 665}, // photo + {6471, 666}, // phrase + {6478, 674}, // pistol + {6482, 675}, // pitch + {6497, 667}, // physics + {6514, 676}, // plains + {6516, 677}, // plan + {6517, 678}, // plastic + {6518, 679}, // platform + {6519, 680}, // playoff + {6531, 681}, // pleasure + {6548, 625}, // omit + {6568, 682}, // plot + {6586, 683}, // plunge + {6595, 624}, // olympic + {6712, 684}, // practice + {6714, 628}, // orbit + {6715, 626}, // oral + {6716, 627}, // orange + {6719, 685}, // prayer + {6723, 629}, // order + {6724, 630}, // ordinary + {6731, 686}, // preach + {6732, 687}, // predator + {6734, 688}, // pregnant + {6735, 689}, // premium + {6736, 690}, // prepare + {6737, 691}, // presence + {6738, 692}, // prevent + {6741, 631}, // organize + {6743, 693}, // priest + {6745, 694}, // primary + {6746, 695}, // priority + {6747, 696}, // prisoner + {6748, 697}, // privacy + {6749, 698}, // prize + {6761, 699}, // problem + {6762, 700}, // process + {6763, 701}, // profile + {6764, 702}, // program + {6765, 703}, // promise + {6767, 704}, // prospect + {6768, 705}, // provide + {6786, 706}, // prune + {6815, 707}, // public + {6816, 716}, // quantity + {6817, 717}, // quarter + {6825, 613}, // nuclear + {6836, 633}, // oven + {6837, 634}, // overall + {6842, 718}, // quick + {6843, 719}, // quiet + {6851, 614}, // numb + {6853, 615}, // numerous + {6856, 709}, // pumps + {6857, 708}, // pulse + {6861, 712}, // pupal + {6862, 632}, // ounce + {6864, 710}, // punish + {6869, 711}, // puny + {6872, 713}, // purchase + {6876, 714}, // purple + {6956, 616}, // nylon + {6963, 635}, // owner + {6984, 715}, // python + {7121, 722}, // radar + {7123, 720}, // race + {7124, 721}, // racism + {7125, 775}, // sack + {7131, 776}, // safari + {7145, 723}, // railroad + {7146, 724}, // rainbow + {7147, 725}, // raisin + {7151, 777}, // salary + {7156, 778}, // salon + {7158, 779}, // salt + {7162, 726}, // random + {7164, 728}, // rapids + {7165, 727}, // ranked + {7176, 729}, // raspy + {7183, 782}, // saver + {7184, 780}, // satisfy + {7186, 781}, // satoshi + {7197, 783}, // says + {7216, 784}, // scandal + {7217, 785}, // scared + {7218, 786}, // scatter + {7236, 787}, // scene + {7243, 789}, // science + {7246, 788}, // scholar + {7268, 790}, // scout + {7271, 791}, // scramble + {7273, 792}, // screw + {7274, 793}, // script + {7276, 794}, // scroll + {7312, 730}, // reaction + {7313, 795}, // seafood + {7315, 731}, // realize + {7316, 732}, // rebound + {7317, 796}, // season + {7318, 733}, // rebuild + {7321, 734}, // recall + {7323, 735}, // receiver + {7326, 736}, // recover + {7327, 797}, // secret + {7328, 798}, // security + {7343, 739}, // reject + {7345, 799}, // segment + {7347, 737}, // regret + {7348, 738}, // regular + {7351, 740}, // relate + {7353, 741}, // remember + {7354, 742}, // remind + {7356, 743}, // remove + {7361, 745}, // repair + {7362, 744}, // render + {7363, 746}, // repeat + {7364, 800}, // senior + {7365, 747}, // replace + {7368, 748}, // require + {7372, 749}, // rescue + {7373, 750}, // research + {7374, 751}, // resident + {7376, 752}, // response + {7378, 753}, // result + {7381, 754}, // retailer + {7383, 757}, // revenue + {7384, 758}, // review + {7386, 756}, // reunion + {7387, 755}, // retreat + {7391, 759}, // reward + {7412, 801}, // shadow + {7413, 802}, // shaft + {7415, 803}, // shame + {7416, 804}, // shaped + {7417, 805}, // sharp + {7423, 811}, // sidewalk + {7424, 762}, // rich + {7435, 806}, // shelter + {7437, 807}, // sheriff + {7453, 812}, // silent + {7454, 814}, // similar + {7456, 815}, // simple + {7458, 813}, // silver + {7464, 816}, // single + {7467, 808}, // short + {7468, 809}, // should + {7474, 810}, // shrimp + {7478, 817}, // sister + {7481, 763}, // rival + {7483, 764}, // river + {7495, 760}, // rhyme + {7498, 761}, // rhythm + {7516, 820}, // slap + {7517, 827}, // smart + {7518, 821}, // slavery + {7531, 828}, // smear + {7532, 822}, // sled + {7535, 829}, // smell + {7542, 823}, // slice + {7545, 824}, // slim + {7546, 818}, // skin + {7547, 830}, // smirk + {7548, 831}, // smith + {7565, 832}, // smoking + {7569, 825}, // slow + {7584, 833}, // smug + {7586, 819}, // skunk + {7587, 826}, // slush + {7612, 843}, // space + {7614, 765}, // robin + {7615, 834}, // snake + {7616, 835}, // snapshot + {7617, 844}, // spark + {7624, 837}, // society + {7625, 766}, // rocky + {7631, 845}, // speak + {7632, 846}, // species + {7635, 847}, // spelling + {7636, 848}, // spend + {7638, 838}, // software + {7639, 849}, // spew + {7642, 850}, // spider + {7643, 836}, // sniff + {7645, 851}, // spill + {7646, 852}, // spine + {7647, 853}, // spirit + {7648, 854}, // spit + {7651, 767}, // romantic + {7652, 839}, // soldier + {7656, 768}, // romp + {7658, 840}, // solution + {7671, 855}, // spray + {7674, 856}, // sprinkle + {7678, 769}, // roster + {7681, 857}, // square + {7683, 858}, // squeeze + {7685, 841}, // soul + {7686, 770}, // round + {7687, 842}, // source + {7691, 771}, // royal + {7812, 859}, // stadium + {7813, 860}, // staff + {7814, 873}, // subject + {7815, 874}, // submit + {7816, 861}, // standard + {7817, 862}, // starting + {7818, 863}, // station + {7819, 864}, // stay + {7831, 865}, // steady + {7836, 866}, // step + {7841, 875}, // sugar + {7842, 867}, // stick + {7845, 868}, // stilt + {7846, 772}, // ruin + {7848, 876}, // suitable + {7853, 773}, // ruler + {7856, 774}, // rumor + {7863, 878}, // superior + {7865, 877}, // sunlight + {7867, 869}, // story + {7871, 870}, // strategy + {7873, 879}, // surface + {7874, 871}, // strike + {7876, 880}, // surprise + {7878, 881}, // survive + {7895, 872}, // style + {7931, 882}, // sweater + {7945, 883}, // swimming + {7946, 884}, // swing + {7948, 885}, // switch + {7951, 886}, // symbolic + {7956, 887}, // sympathy + {7962, 888}, // syndrome + {7978, 889}, // system + {8125, 890}, // tackle + {8126, 892}, // tadpole + {8128, 891}, // tactics + {8153, 893}, // talent + {8154, 965}, // valid + {8156, 967}, // vampire + {8158, 966}, // valuable + {8164, 968}, // vanish + {8174, 969}, // various + {8175, 894}, // task + {8178, 895}, // taste + {8184, 896}, // taught + {8194, 897}, // taxi + {8312, 898}, // teacher + {8315, 899}, // teammate + {8317, 900}, // teaspoon + {8341, 970}, // vegan + {8356, 901}, // temple + {8358, 971}, // velvet + {8361, 902}, // tenant + {8362, 903}, // tendency + {8367, 904}, // tension + {8368, 972}, // venture + {8372, 973}, // verdict + {8374, 974}, // verify + {8375, 905}, // terminal + {8378, 906}, // testify + {8379, 975}, // very + {8383, 976}, // veteran + {8393, 977}, // vexed + {8398, 907}, // texture + {8416, 908}, // thank + {8418, 909}, // that + {8423, 979}, // video + {8425, 917}, // ticket + {8428, 978}, // victim + {8429, 918}, // tidy + {8431, 910}, // theater + {8436, 911}, // theory + {8437, 912}, // therapy + {8439, 980}, // view + {8451, 919}, // timber + {8453, 920}, // timely + {8459, 946}, // ugly + {8464, 921}, // ting + {8465, 982}, // violence + {8467, 913}, // thorn + {8468, 981}, // vintage + {8471, 983}, // viral + {8473, 914}, // threaten + {8474, 984}, // visitor + {8478, 985}, // visual + {8481, 986}, // vitamins + {8485, 915}, // thumb + {8486, 916}, // thunder + {8517, 948}, // umbrella + {8584, 947}, // ultimate + {8621, 987}, // vocal + {8623, 950}, // undergo + {8626, 949}, // uncover + {8631, 951}, // unfair + {8636, 952}, // unfold + {8638, 922}, // tofu + {8641, 953}, // unhappy + {8642, 988}, // voice + {8643, 923}, // together + {8646, 954}, // union + {8647, 960}, // upgrade + {8648, 955}, // universe + {8653, 924}, // tolerate + {8654, 956}, // unkind + {8656, 957}, // unknown + {8658, 989}, // volume + {8678, 961}, // upstairs + {8681, 925}, // total + {8683, 990}, // voter + {8684, 991}, // voting + {8687, 958}, // unusual + {8694, 926}, // toxic + {8697, 959}, // unwrap + {8712, 927}, // tracks + {8713, 928}, // traffic + {8714, 929}, // training + {8716, 930}, // transfer + {8717, 931}, // trash + {8718, 932}, // traveler + {8731, 933}, // treat + {8736, 934}, // trend + {8737, 962}, // username + {8741, 935}, // trial + {8742, 936}, // tricycle + {8743, 963}, // usher + {8746, 937}, // trip + {8748, 938}, // triumph + {8768, 939}, // trouble + {8781, 964}, // usual + {8783, 940}, // true + {8787, 941}, // trust + {8942, 942}, // twice + {8946, 943}, // twin + {8963, 944}, // type + {8964, 945}, // typical + {9156, 992}, // walnut + {9175, 993}, // warmth + {9176, 994}, // warn + {9182, 995}, // watch + {9189, 996}, // wavy + {9312, 999}, // webcam + {9315, 997}, // wealthy + {9316, 998}, // weapon + {9317, 1019}, // year + {9352, 1000}, // welcome + {9353, 1001}, // welfare + {9356, 1020}, // yelp + {9376, 1023}, // zero + {9378, 1002}, // western + {9428, 1003}, // width + {9435, 1021}, // yield + {9452, 1004}, // wildlife + {9462, 1005}, // window + {9463, 1006}, // wine + {9472, 1008}, // wisdom + {9473, 1007}, // wireless + {9484, 1009}, // withdraw + {9487, 1010}, // wits + {9641, 1022}, // yoga + {9651, 1012}, // woman + {9653, 1011}, // wolf + {9675, 1013}, // work + {9678, 1014}, // worthy + {9716, 1015}, // wrap + {9747, 1016}, // wrist + {9748, 1017}, // writing + {9768, 1018}, // wrote +}; + +#endif diff --git a/trezor-crypto/include/TrezorCrypto/schnorr.h b/trezor-crypto/include/TrezorCrypto/zilliqa.h similarity index 77% rename from trezor-crypto/include/TrezorCrypto/schnorr.h rename to trezor-crypto/include/TrezorCrypto/zilliqa.h index 4091c807446..46ada660b06 100644 --- a/trezor-crypto/include/TrezorCrypto/schnorr.h +++ b/trezor-crypto/include/TrezorCrypto/zilliqa.h @@ -20,8 +20,8 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef __SCHNORR_H__ -#define __SCHNORR_H__ +#ifndef __ZILLIQA_H__ +#define __ZILLIQA_H__ #include @@ -38,11 +38,16 @@ typedef struct { // sign/verify returns 0 if operation succeeded +int zil_schnorr_sign(const ecdsa_curve *curve, const uint8_t *priv_key, + const uint8_t *msg, const uint32_t msg_len, uint8_t *sig); +int zil_schnorr_verify(const ecdsa_curve *curve, const uint8_t *pub_key, + const uint8_t *sig, const uint8_t *msg, const uint32_t msg_len); + // k is a random from [1, ..., order-1] -int schnorr_sign(const ecdsa_curve *curve, const uint8_t *priv_key, +int zil_schnorr_sign_k(const ecdsa_curve *curve, const uint8_t *priv_key, const bignum256 *k, const uint8_t *msg, const uint32_t msg_len, schnorr_sign_pair *result); -int schnorr_verify(const ecdsa_curve *curve, const uint8_t *pub_key, +int zil_schnorr_verify_pair(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *msg, const uint32_t msg_len, const schnorr_sign_pair *sign); #ifdef __cplusplus From 7818d5b3b915008ec4a52854fc5e0d38b9f6693a Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sat, 23 Jul 2022 00:44:21 +0800 Subject: [PATCH 031/497] Update registry.json (#2400) --- registry.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry.json b/registry.json index 152395ffd4a..c9cdb3272de 100644 --- a/registry.json +++ b/registry.json @@ -1906,7 +1906,7 @@ "info": { "url": "https://polygon.technology", "source": "https://github.com/maticnetwork/contracts", - "rpc": "https://rpc-mainnet.matic.network", + "rpc": "https://polygon-rpc.com", "documentation": "https://eth.wiki/json-rpc/API" } }, @@ -2657,4 +2657,4 @@ "documentation": "https://docs.meter.io/" } } -] \ No newline at end of file +] From 9acde6ad6eb1a000b58424e16b6947d7883c37c0 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 22 Jul 2022 22:56:32 +0200 Subject: [PATCH 032/497] [Improvements]: Add memzero wrapper (#2395) * feat(memzero): add memzero c++ wrapper * fix(memzero): fix cmake * feat(hdwallet): use memzero wrapper --- src/HDWallet.cpp | 14 +++++++------- src/memory/memzero_wrapper.h | 23 +++++++++++++++++++++++ tests/memory/memzero_tests.cpp | 23 +++++++++++++++++++++++ 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 src/memory/memzero_wrapper.h create mode 100644 tests/memory/memzero_tests.cpp diff --git a/src/HDWallet.cpp b/src/HDWallet.cpp index 11e8e7c0848..d1025d64457 100644 --- a/src/HDWallet.cpp +++ b/src/HDWallet.cpp @@ -12,6 +12,7 @@ #include "Bitcoin/SegwitAddress.h" #include "Coin.h" #include "Mnemonic.h" +#include "memory/memzero_wrapper.h" #include #include @@ -22,7 +23,6 @@ #include #include #include -#include #include #include @@ -50,7 +50,7 @@ HDWallet::HDWallet(int strength, const std::string& passphrase) throw std::invalid_argument("Invalid strength"); } mnemonic = mnemonic_chars; - memzero(buf, MnemonicBufLength); + TW::memzero(buf, MnemonicBufLength); updateSeedAndEntropy(); } @@ -71,7 +71,7 @@ HDWallet::HDWallet(const Data& entropy, const std::string& passphrase) throw std::invalid_argument("Invalid mnemonic data"); } mnemonic = mnemonic_chars; - memzero(buf, MnemonicBufLength); + TW::memzero(buf, MnemonicBufLength); updateSeedAndEntropy(); } @@ -142,7 +142,7 @@ PrivateKey HDWallet::getKey(TWCoinType coin, const DerivationPath& derivationPat auto extData2 = Data(node2.private_key_extension, node2.private_key_extension + PrivateKey::size); auto chainCode2 = Data(node2.chain_code, node2.chain_code + PrivateKey::size); - memset(&node, 0, sizeof(HDNode)); + TW::memzero(&node); return PrivateKey(pkData, extData, chainCode, pkData2, extData2, chainCode2); } @@ -150,7 +150,7 @@ PrivateKey HDWallet::getKey(TWCoinType coin, const DerivationPath& derivationPat default: // default path auto data = Data(node.private_key, node.private_key + PrivateKey::size); - memset(&node, 0, sizeof(HDNode)); + TW::memzero(&node); return PrivateKey(data); } } @@ -286,7 +286,7 @@ std::string serialize(const HDNode* node, uint32_t fingerprint, uint32_t version } bool deserialize(const std::string& extended, TWCurve curve, Hash::Hasher hasher, HDNode* node) { - memset(node, 0, sizeof(HDNode)); + TW::memzero(node); const char* curveNameStr = curveName(curve); if (curveNameStr == nullptr || ::strlen(curveNameStr) == 0) { return false; @@ -344,7 +344,7 @@ HDNode getMasterNode(const HDWallet& wallet, TWCurve curve) { uint8_t secret[CARDANO_SECRET_LENGTH]; secret_from_entropy_cardano_icarus((const uint8_t*)"", 0, entropy.data(), int(entropy.size()), secret, nullptr); hdnode_from_secret_cardano(secret, &node); - memzero(secret, CARDANO_SECRET_LENGTH); + TW::memzero(secret, CARDANO_SECRET_LENGTH); break; } case PrivateKeyTypeDefault32: diff --git a/src/memory/memzero_wrapper.h b/src/memory/memzero_wrapper.h new file mode 100644 index 00000000000..be8c7859e4d --- /dev/null +++ b/src/memory/memzero_wrapper.h @@ -0,0 +1,23 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include + +#include + +#include + +namespace TW { + +template +static inline void memzero(T* data, std::size_t len = sizeof(T)) noexcept { + static_assert(std::is_trivial_v, "type should be a pod"); + ::memzero(data, len); +} + +} // namespace TW diff --git a/tests/memory/memzero_tests.cpp b/tests/memory/memzero_tests.cpp new file mode 100644 index 00000000000..47fba2f4697 --- /dev/null +++ b/tests/memory/memzero_tests.cpp @@ -0,0 +1,23 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "memory/memzero_wrapper.h" + +#include "gtest/gtest.h" + +struct int_wrapper { + int value; +}; + +TEST(Memory, Memzero) { + int_wrapper obj{.value = 42}; + TW::memzero(&obj); + ASSERT_EQ(obj.value, 0); + obj.value = 42; + ASSERT_EQ(obj.value, 42); + TW::memzero(&obj, sizeof(int_wrapper)); + ASSERT_EQ(obj.value, 0); +} From b1de49f67c05709158be485da1fd9e11f6d84403 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Tue, 26 Jul 2022 02:27:48 +0200 Subject: [PATCH 033/497] Remove unused Ethereum ChecksumType (#2407) --- src/Ethereum/Address.cpp | 2 +- src/Ethereum/AddressChecksum.cpp | 2 +- src/Ethereum/AddressChecksum.h | 8 +------- src/Ronin/Address.cpp | 2 +- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/Ethereum/Address.cpp b/src/Ethereum/Address.cpp index 890c180fe74..a59c7b5f035 100644 --- a/src/Ethereum/Address.cpp +++ b/src/Ethereum/Address.cpp @@ -43,5 +43,5 @@ Address::Address(const PublicKey& publicKey) { } std::string Address::string() const { - return checksumed(*this, ChecksumType::eip55); + return checksumed(*this); } diff --git a/src/Ethereum/AddressChecksum.cpp b/src/Ethereum/AddressChecksum.cpp index 65fa5ba458f..004e8f8a47d 100644 --- a/src/Ethereum/AddressChecksum.cpp +++ b/src/Ethereum/AddressChecksum.cpp @@ -13,7 +13,7 @@ using namespace TW; using namespace TW::Ethereum; -std::string Ethereum::checksumed(const Address& address, enum ChecksumType type) { +std::string Ethereum::checksumed(const Address& address) { const auto addressString = hex(address.bytes); const auto hash = hex(Hash::keccak256(addressString)); diff --git a/src/Ethereum/AddressChecksum.h b/src/Ethereum/AddressChecksum.h index 2aa11e989d4..922110c6869 100644 --- a/src/Ethereum/AddressChecksum.h +++ b/src/Ethereum/AddressChecksum.h @@ -11,12 +11,6 @@ namespace TW::Ethereum { -/// Checksum types for Ethereum-based blockchains. -enum ChecksumType { - eip55 = 0, - wanchain = 1, -}; - -std::string checksumed(const Address& address, enum ChecksumType type); +std::string checksumed(const Address& address); } // namespace TW::Ethereum diff --git a/src/Ronin/Address.cpp b/src/Ronin/Address.cpp index 88f80d30597..c6699436413 100644 --- a/src/Ronin/Address.cpp +++ b/src/Ronin/Address.cpp @@ -44,7 +44,7 @@ Address::Address(const std::string& string) { // Normalized: with ronin prefix, checksummed hex address, no 0x prefix std::string Address::string() const { - std::string address = Ethereum::checksumed(*this, Ethereum::ChecksumType::eip55); + std::string address = Ethereum::checksumed(*this); if (address.size() >= 2 && address.substr(0, 2) == "0x") { address = address.substr(2); } // skip 0x return prefix + address; } From a01276d3c4d116212aec6afbf52949b57fb899ca Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Tue, 26 Jul 2022 11:52:44 +0200 Subject: [PATCH 034/497] Fix for StoredKey::privateKey() with derivation (#2406) * Fix for StoredKey::privateKey() with derivation * Fix for Solana TokenProgram::findProgramAddress * Add tests --- src/Keystore/StoredKey.cpp | 5 ++--- src/Solana/Program.cpp | 2 +- tests/Keystore/StoredKeyTests.cpp | 23 +++++++++++++++++++++++ tests/Solana/ProgramTests.cpp | 28 +++++++++++++++++++--------- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/Keystore/StoredKey.cpp b/src/Keystore/StoredKey.cpp index 9546ef6c76f..af854073ffe 100644 --- a/src/Keystore/StoredKey.cpp +++ b/src/Keystore/StoredKey.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include @@ -253,8 +252,8 @@ const PrivateKey StoredKey::privateKey(TWCoinType coin, const Data& password) { const PrivateKey StoredKey::privateKey(TWCoinType coin, TWDerivation derivation, const Data& password) { if (type == StoredKeyType::mnemonicPhrase) { const auto wallet = this->wallet(password); - const auto account = this->account(coin, &wallet); - return wallet.getKey(coin, account->derivationPath); + const Account& account = this->account(coin, derivation, wallet); + return wallet.getKey(coin, account.derivationPath); } // type == StoredKeyType::privateKey return PrivateKey(payload.decrypt(password)); diff --git a/src/Solana/Program.cpp b/src/Solana/Program.cpp index 8a70254a82a..cf7c602b987 100644 --- a/src/Solana/Program.cpp +++ b/src/Solana/Program.cpp @@ -69,7 +69,7 @@ Address TokenProgram::findProgramAddress(const std::vector& seeds, con for (std::uint8_t seed = 0; seed <= std::numeric_limits::max(); ++seed) { std::vector seedsCopy = seeds; seedsCopy.emplace_back(bumpSeed); - Address address = createProgramAddress(seedsCopy, Address(ASSOCIATED_TOKEN_PROGRAM_ID_ADDRESS)); + Address address = createProgramAddress(seedsCopy, programId); PublicKey publicKey = PublicKey(TW::data(address.bytes.data(), address.bytes.size()), TWPublicKeyTypeED25519); if (!publicKey.isValidED25519()) { result = address; diff --git a/tests/Keystore/StoredKeyTests.cpp b/tests/Keystore/StoredKeyTests.cpp index 135fb995d2b..0b26eec95a0 100644 --- a/tests/Keystore/StoredKeyTests.cpp +++ b/tests/Keystore/StoredKeyTests.cpp @@ -623,4 +623,27 @@ TEST(StoredKey, CreateMultiAccounts) { // Multiple accounts for the same coin } } +TEST(StoredKey, CreateWithMnemonicAlternativeDerivation) { + const auto coin = TWCoinTypeSolana; + auto key = StoredKey::createWithMnemonicAddDefaultAddress("name", password, mnemonic, coin); + EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); + + ASSERT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts[0].coin, coin); + EXPECT_EQ(key.accounts[0].address, "HiipoCKL8hX2RVmJTz3vaLy34hS2zLhWWMkUWtw85TmZ"); + EXPECT_EQ(key.accounts[0].publicKey, "f86b18399096c8134dd185f1e72dd7e26528772a2a998abfd81c5f8c547223d0"); + EXPECT_EQ(hex(key.privateKey(coin, password).bytes), "d81b5c525979e487736b69cb84ed8331559de17294f38491b304555c26687e83"); + EXPECT_EQ(hex(key.privateKey(coin, TWDerivationDefault, password).bytes), "d81b5c525979e487736b69cb84ed8331559de17294f38491b304555c26687e83"); + ASSERT_EQ(key.accounts.size(), 1); + + // alternative derivation, different keys + EXPECT_EQ(hex(key.privateKey(coin, TWDerivationSolanaSolana, password).bytes), "d49a5fa7f77593534c7afd2ba8dc8e9d8b007bc6ec65fe8df25ffe6fafc57151"); + + ASSERT_EQ(key.accounts.size(), 2); + EXPECT_EQ(key.accounts[1].coin, coin); + EXPECT_EQ(key.accounts[1].address, "CgWJeEWkiYqosy1ba7a3wn9HAQuHyK48xs3LM4SSDc1C"); + EXPECT_EQ(key.accounts[1].publicKey, "ad8f57924dce62f9040f93b4f6ce3c3d39afde7e29bcb4013dad59db7913c4c7"); + EXPECT_EQ(hex(key.privateKey(coin, TWDerivationSolanaSolana, password).bytes), "d49a5fa7f77593534c7afd2ba8dc8e9d8b007bc6ec65fe8df25ffe6fafc57151"); +} + } // namespace TW::Keystore diff --git a/tests/Solana/ProgramTests.cpp b/tests/Solana/ProgramTests.cpp index 0a5c413dafd..1aecb102539 100644 --- a/tests/Solana/ProgramTests.cpp +++ b/tests/Solana/ProgramTests.cpp @@ -52,21 +52,31 @@ TEST(SolanaTokenProgram, findProgramAddress) { Base58::bitcoin.decode("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), Base58::bitcoin.decode("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"), }; - Address address = TokenProgram::findProgramAddress(seeds, Address("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")); - EXPECT_EQ(address.string(), "EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); + { + Address address = TokenProgram::findProgramAddress(seeds, Address("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")); + EXPECT_EQ(address.string(), "EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); + } + { + Address address = TokenProgram::findProgramAddress(seeds, Address("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr")); + EXPECT_EQ(address.string(), "CuS1kE1wvGTmwGk3FYNQK85g4jU7gMySWwFRQQ9LFunp"); + } } TEST(SolanaTokenProgram, createProgramAddress) { + std::vector seeds4 = { + Base58::bitcoin.decode("B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"), + Base58::bitcoin.decode("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), + Base58::bitcoin.decode("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"), + Data{255} + }; { - std::vector seeds = { - Base58::bitcoin.decode("B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"), - Base58::bitcoin.decode("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), - Base58::bitcoin.decode("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"), - Data{255} - }; - Address address = TokenProgram::createProgramAddress(seeds, Address("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")); + Address address = TokenProgram::createProgramAddress(seeds4, Address("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")); EXPECT_EQ(address.string(), "EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); } + { + Address address = TokenProgram::createProgramAddress(seeds4, Address("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr")); + EXPECT_EQ(address.string(), "CuS1kE1wvGTmwGk3FYNQK85g4jU7gMySWwFRQQ9LFunp"); + } // https://github.com/solana-labs/solana/blob/f25c969ad87e64e6d1fd07d2d37096ac71cf8d06/sdk/program/src/pubkey.rs#L353-L435 { std::vector seeds = {TW::data(""), {1}}; From 3c35dd8896ce731b4c9fc9c4c149e8c6372b11bf Mon Sep 17 00:00:00 2001 From: JianGuo Date: Tue, 26 Jul 2022 19:57:33 +0800 Subject: [PATCH 035/497] Add OKX Chain Support (#2399) --- .../blockchains/CoinAddressDerivationTests.kt | 2 +- docs/registry.md | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 30 ++++++++++++++++ swift/Tests/CoinAddressDerivationTests.swift | 3 +- tests/OKXChain/TWCoinTypeTests.cpp | 34 +++++++++++++++++++ 6 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 tests/OKXChain/TWCoinTypeTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index f8fd85fcb37..59170cc4a4d 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -42,7 +42,7 @@ class CoinAddressDerivationTests { DIGIBYTE -> assertEquals("dgb1qtjgmerfqwdffyf8ghcrkgy52cghsqptynmyswu", address) ETHEREUM, SMARTCHAIN, POLYGON, OPTIMISM, ARBITRUM, ECOCHAIN, AVALANCHECCHAIN, XDAI, FANTOM, CELO, CRONOSCHAIN, SMARTBITCOINCASH, KUCOINCOMMUNITYCHAIN, BOBA, METIS, - AURORA, EVMOS, MOONRIVER, MOONBEAM, KAVAEVM, KLAYTN, METER -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address) + AURORA, EVMOS, MOONRIVER, MOONBEAM, KAVAEVM, KLAYTN, METER, OKXCHAIN -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address) RONIN -> assertEquals("ronin:8f348F300873Fd5DA36950B2aC75a26584584feE", address) ETHEREUMCLASSIC -> assertEquals("0x078bA3228F3E6C08bEEac9A005de0b7e7089aD1c", address) GOCHAIN -> assertEquals("0x5940ce4A14210d4Ccd0ac206CE92F21828016aC2", address) diff --git a/docs/registry.md b/docs/registry.md index 3aa40ae48b0..61b971ab738 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -56,6 +56,7 @@ This list is generated from [./registry.json](../registry.json) | 899 | eCash | XEC | | | | 931 | THORChain | RUNE | | | | 966 | Polygon | MATIC | | | +| 996 | OKX Chain | OKT | | | | 1001 | Thunder Token | TT | | | | 1023 | Harmony | ONE | | | | 1024 | Ontology | ONT | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 2a2f9ec21f6..646e444ed73 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -113,6 +113,7 @@ enum TWCoinType { TWCoinTypeKavaEvm = 10002222, TWCoinTypeKlaytn = 10008217, TWCoinTypeMeter = 18000, + TWCoinTypeOKXChain = 996, }; /// Returns the blockchain for a coin type. diff --git a/registry.json b/registry.json index c9cdb3272de..c003b7c593d 100644 --- a/registry.json +++ b/registry.json @@ -2656,5 +2656,35 @@ "rpc": "https://rpc.meter.io", "documentation": "https://docs.meter.io/" } + }, + { + "id": "okc", + "name": "OKX Chain", + "coinId": 996, + "chainId": "66", + "symbol": "OKT", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "addressHasher": "keccak256", + "explorer": { + "url": "https://www.oklink.com/en/okc", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0x46C3A947E8248570FBD28E4FE456CC8F80DFD90716533878FB67857B95FA3D37", + "sampleAccount": "0x074faafd0b20fad2efa115b8ed7e75993e580b85" + }, + "info": { + "url": "https://www.okx.com/okc", + "source": "https://github.com/okex/exchain", + "rpc": "https://exchainrpc.okex.org", + "documentation": "https://okc-docs.readthedocs.io/en/latest" + } } ] diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 562e7c019bd..0440ed7f739 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -91,7 +91,8 @@ class CoinAddressDerivationTests: XCTestCase { .moonbeam, .kavaEvm, .klaytn, - .meter: + .meter, + .okxchain: let expectedResult = "0x8f348F300873Fd5DA36950B2aC75a26584584feE" assertCoinDerivation(coin, expectedResult, derivedAddress, address) case .ronin: diff --git a/tests/OKXChain/TWCoinTypeTests.cpp b/tests/OKXChain/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..4e68b569a69 --- /dev/null +++ b/tests/OKXChain/TWCoinTypeTests.cpp @@ -0,0 +1,34 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "../interface/TWTestUtilities.h" +#include +#include + + +TEST(TWCoinTypeOKXChain, TWCoinType) { + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeOKXChain)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("0x46C3A947E8248570FBD28E4FE456CC8F80DFD90716533878FB67857B95FA3D37")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeOKXChain, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0x074faafd0b20fad2efa115b8ed7e75993e580b85")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeOKXChain, accId.get())); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeOKXChain)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeOKXChain)); + + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeOKXChain), 18); + ASSERT_EQ(TWBlockchainEthereum, TWCoinTypeBlockchain(TWCoinTypeOKXChain)); + ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeOKXChain)); + ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeOKXChain)); + assertStringsEqual(symbol, "OKT"); + assertStringsEqual(txUrl, "https://www.oklink.com/en/okc/tx/0x46C3A947E8248570FBD28E4FE456CC8F80DFD90716533878FB67857B95FA3D37"); + assertStringsEqual(accUrl, "https://www.oklink.com/en/okc/address/0x074faafd0b20fad2efa115b8ed7e75993e580b85"); + assertStringsEqual(id, "okc"); + assertStringsEqual(name, "OKX Chain"); +} From 8b1f89336d24aac20024b27662dbe9e713c3a869 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Wed, 27 Jul 2022 11:19:52 +0200 Subject: [PATCH 036/497] [Cosmos] SignDirect support (#2415) * Cosmos SignDirect * Add additional comments to proto files --- src/Cosmos/ProtobufSerialization.cpp | 8 +++ src/proto/Cosmos.proto | 11 +++- tests/Cosmos/SignerTests.cpp | 77 ++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/Cosmos/ProtobufSerialization.cpp b/src/Cosmos/ProtobufSerialization.cpp index b92c9ac5162..a22ec52bad3 100644 --- a/src/Cosmos/ProtobufSerialization.cpp +++ b/src/Cosmos/ProtobufSerialization.cpp @@ -226,6 +226,10 @@ google::protobuf::Any convertMessage(const Proto::Message& msg) { } std::string buildProtoTxBody(const Proto::SigningInput& input) { + if (input.messages_size() >= 1 && input.messages(0).has_sign_direct_message()) { + return input.messages(0).sign_direct_message().body_bytes(); + } + if (input.messages_size() < 1) { throw std::invalid_argument("No message found"); } @@ -242,6 +246,10 @@ std::string buildProtoTxBody(const Proto::SigningInput& input) { } std::string buildAuthInfo(const Proto::SigningInput& input, TWCoinType coin) { + if (input.messages_size() >= 1 && input.messages(0).has_sign_direct_message()) { + return input.messages(0).sign_direct_message().auth_info_bytes(); + } + // AuthInfo const auto privateKey = PrivateKey(input.private_key()); const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); diff --git a/src/proto/Cosmos.proto b/src/proto/Cosmos.proto index 307f4a12ad6..457bdef7c93 100644 --- a/src/proto/Cosmos.proto +++ b/src/proto/Cosmos.proto @@ -197,6 +197,14 @@ message Message { string value = 2; } + // For signing an already serialized transaction. Account number and chain ID must be set outside. + message SignDirect { + // The prepared serialized TxBody + bytes body_bytes = 1; + // The prepared serialized AuthInfo + bytes auth_info_bytes = 2; + } + oneof message_oneof { Send send_coins_message = 1; Transfer transfer_tokens_message = 2; @@ -212,6 +220,7 @@ message Message { WasmExecuteContractTransfer wasm_execute_contract_transfer_message = 12; WasmExecuteContractSend wasm_execute_contract_send_message = 13; WasmExecuteContractGeneric wasm_execute_contract_generic = 14; + SignDirect sign_direct_message = 15; } } @@ -229,7 +238,7 @@ message SigningInput { string chain_id = 3; Fee fee = 4; string memo = 5; - uint64 sequence = 6; + uint64 sequence = 6; bytes private_key = 7; diff --git a/tests/Cosmos/SignerTests.cpp b/tests/Cosmos/SignerTests.cpp index 06c4e5bc0e1..e3b87703b6d 100644 --- a/tests/Cosmos/SignerTests.cpp +++ b/tests/Cosmos/SignerTests.cpp @@ -11,6 +11,8 @@ #include "Cosmos/Address.h" #include "Cosmos/Signer.h" #include "../interface/TWTestUtilities.h" +#include "Cosmos/Protobuf/bank_tx.pb.h" +#include "Cosmos/Protobuf/coin.pb.h" #include #include @@ -217,3 +219,78 @@ TEST(CosmosSigner, SignIbcTransferProtobuf_817101) { EXPECT_EQ(output.json(), ""); EXPECT_EQ(output.error(), ""); } + +TEST(CosmosSigner, SignDirect1) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(1037); + input.set_chain_id("gaia-13003"); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_sign_direct_message(); + const auto bodyBytes = parse_hex("0a89010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e6412690a2d636f736d6f733168736b366a727979716a6668703564686335357463396a74636b796778306570683664643032122d636f736d6f73317a743530617a7570616e716c66616d356166687633686578777975746e756b656834633537331a090a046d756f6e120131"); + message.set_body_bytes(bodyBytes.data(), bodyBytes.size()); + const auto authInfoBytes = parse_hex("0a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a210257286ec3f37d33557bbbaa000b27744ac9023aa9967cae75a181d1ff91fa9dc512040a020801180812110a0b0a046d756f6e120332303010c09a0c"); + message.set_auth_info_bytes(authInfoBytes.data(), authInfoBytes.size()); + + { + std::string json; + google::protobuf::util::MessageToJsonString(input, &json); + EXPECT_EQ(R"({"signingMode":"Protobuf","accountNumber":"1037","chainId":"gaia-13003","messages":[{"signDirectMessage":{"bodyBytes":"CokBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmkKLWNvc21vczFoc2s2anJ5eXFqZmhwNWRoYzU1dGM5anRja3lneDBlcGg2ZGQwMhItY29zbW9zMXp0NTBhenVwYW5xbGZhbTVhZmh2M2hleHd5dXRudWtlaDRjNTczGgkKBG11b24SATE=","authInfoBytes":"ClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiECVyhuw/N9M1V7u6oACyd0SskCOqmWfK51oYHR/5H6ncUSBAoCCAEYCBIRCgsKBG11b24SAzIwMBDAmgw="}}]})", json); + } + + auto privateKey = parse_hex("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeCosmos); + + assertJSONEqual(output.serialized(), "{\"tx_bytes\": \"CowBCokBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmkKLWNvc21vczFoc2s2anJ5eXFqZmhwNWRoYzU1dGM5anRja3lneDBlcGg2ZGQwMhItY29zbW9zMXp0NTBhenVwYW5xbGZhbTVhZmh2M2hleHd5dXRudWtlaDRjNTczGgkKBG11b24SATESZQpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3FEgQKAggBGAgSEQoLCgRtdW9uEgMyMDAQwJoMGkD54fQAFlekIAnE62hZYl0uQelh/HLv0oQpCciY5Dn8H1SZFuTsrGdu41PH1Uxa4woptCELi/8Ov9yzdeEFAC9H\", \"mode\": \"BROADCAST_MODE_BLOCK\"}"); + EXPECT_EQ(hex(output.signature()), "f9e1f4001657a42009c4eb6859625d2e41e961fc72efd2842909c898e439fc1f549916e4ecac676ee353c7d54c5ae30a29b4210b8bff0ebfdcb375e105002f47"); + EXPECT_EQ(output.json(), ""); + EXPECT_EQ(output.error(), ""); +} + +TEST(CosmosSigner, SignDirect_0a90010a) { + const auto bodyBytes = parse_hex("0a90010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e6412700a2d636f736d6f7331706b707472653766646b6c366766727a6c65736a6a766878686c63337234676d6d6b38727336122d636f736d6f7331717970717870713971637273737a673270767871367273307a716733797963356c7a763778751a100a0575636f736d120731323334353637"); + { // verify contents of body + auto msgSend = cosmos::bank::v1beta1::MsgSend(); + msgSend.set_from_address("cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6"); + msgSend.set_to_address("cosmos1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu"); + auto amount = msgSend.add_amount(); + amount->set_denom("ucosm"); + amount->set_amount("1234567"); + const auto msgSendSer = msgSend.SerializeAsString(); + const auto bodyBytes1 = data(msgSendSer); + ASSERT_EQ(hex(bodyBytes1), "0a2d636f736d6f7331706b707472653766646b6c366766727a6c65736a6a766878686c63337234676d6d6b38727336122d636f736d6f7331717970717870713971637273737a673270767871367273307a716733797963356c7a763778751a100a0575636f736d120731323334353637"); + const auto prefix = "/cosmos.bank.v1beta1.MsgSend"; + const auto bodyBytes2 = parse_hex("0a90010a1c" + hex(data(prefix)) + "1270" + hex(bodyBytes1)); + ASSERT_EQ(hex(bodyBytes2), hex(bodyBytes)); + } + + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(1); + input.set_chain_id("cosmoshub-4"); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_sign_direct_message(); + message.set_body_bytes(bodyBytes.data(), bodyBytes.size()); + const auto authInfoBytes = parse_hex("0a0a0a0012040a020801180112130a0d0a0575636f736d12043230303010c09a0c"); + message.set_auth_info_bytes(authInfoBytes.data(), authInfoBytes.size()); + + { + std::string json; + google::protobuf::util::MessageToJsonString(input, &json); + EXPECT_EQ(R"({"signingMode":"Protobuf","accountNumber":"1","chainId":"cosmoshub-4","messages":[{"signDirectMessage":{"bodyBytes":"CpABChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnAKLWNvc21vczFwa3B0cmU3ZmRrbDZnZnJ6bGVzamp2aHhobGMzcjRnbW1rOHJzNhItY29zbW9zMXF5cHF4cHE5cWNyc3N6ZzJwdnhxNnJzMHpxZzN5eWM1bHp2N3h1GhAKBXVjb3NtEgcxMjM0NTY3","authInfoBytes":"CgoKABIECgIIARgBEhMKDQoFdWNvc20SBDIwMDAQwJoM"}}]})", json); + } + + auto privateKey = parse_hex("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeCosmos); + + assertJSONEqual(output.serialized(), "{\"tx_bytes\": \"CpMBCpABChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnAKLWNvc21vczFwa3B0cmU3ZmRrbDZnZnJ6bGVzamp2aHhobGMzcjRnbW1rOHJzNhItY29zbW9zMXF5cHF4cHE5cWNyc3N6ZzJwdnhxNnJzMHpxZzN5eWM1bHp2N3h1GhAKBXVjb3NtEgcxMjM0NTY3EiEKCgoAEgQKAggBGAESEwoNCgV1Y29zbRIEMjAwMBDAmgwaQEgXmSAlm4M5bz+OX1GtvvZ3fBV2wrZrp4A/Imd55KM7ASivB/siYJegmYiOKzQ82uwoEmFalNnG2BrHHDwDR2Y=\", \"mode\": \"BROADCAST_MODE_BLOCK\"}"); + EXPECT_EQ(hex(output.signature()), "48179920259b83396f3f8e5f51adbef6777c1576c2b66ba7803f226779e4a33b0128af07fb226097a099888e2b343cdaec2812615a94d9c6d81ac71c3c034766"); + EXPECT_EQ(output.json(), ""); + EXPECT_EQ(output.error(), ""); +} From ca4bc04941a85659748d8737f496c330f515fb97 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 27 Jul 2022 11:32:50 +0200 Subject: [PATCH 037/497] [Improvements]: Enable -Wextra warning (#2397) * fix(warnings): enable -Wextra - fix unused parameter - fix sign compare * feat(warning): enable non virtual dtor warning * fix(compilation): remove constexpr fee calculator until swift support * feat(ios): update config yml files to c++20 * feat(cosmos): remove unused input parameter from buildProtoTxRaw * fix(eth): refactor Parameters to support size_t index * fix(input_selector): change select input parameters * feat(warning): remove -Werror from CompilerWarnings.cmake --- cmake/CompilerWarnings.cmake | 4 +- src/Aeternity/Entry.cpp | 6 +- src/Aion/Entry.cpp | 8 +- src/Algorand/BaseTransaction.h | 3 +- src/Algorand/Entry.cpp | 8 +- src/Binance/Entry.cpp | 16 +- src/Bitcoin/Entry.cpp | 8 +- src/Bitcoin/FeeCalculator.cpp | 6 +- src/Bitcoin/FeeCalculator.h | 7 +- src/Bitcoin/InputSelector.cpp | 12 +- src/Bitcoin/InputSelector.h | 4 +- src/Bitcoin/Script.cpp | 4 +- src/Bitcoin/SignatureBuilder.cpp | 6 +- src/Bitcoin/Transaction.cpp | 4 +- src/Bitcoin/TransactionBuilder.cpp | 4 +- src/Cardano/Entry.cpp | 10 +- src/Cardano/Signer.cpp | 4 +- src/Cbor.cpp | 18 +- src/CoinEntry.h | 17 +- src/Cosmos/Entry.cpp | 6 +- src/Cosmos/ProtobufSerialization.cpp | 2 +- src/Cosmos/ProtobufSerialization.h | 2 +- src/Cosmos/Signer.cpp | 2 +- src/Crc.cpp | 2 +- src/Decred/Entry.cpp | 10 +- src/Decred/Signer.cpp | 6 +- src/Decred/Transaction.cpp | 6 +- src/EOS/Asset.cpp | 2 +- src/EOS/Entry.cpp | 6 +- src/EOS/Name.cpp | 4 +- src/EOS/Signer.cpp | 2 +- src/Elrond/Entry.cpp | 10 +- src/Ethereum/ABI/ParamBase.h | 2 +- src/Ethereum/ABI/ParamFactory.cpp | 2 +- src/Ethereum/ABI/ParamStruct.cpp | 6 +- src/Ethereum/ABI/ParamStruct.h | 6 +- src/Ethereum/ABI/Parameters.cpp | 4 +- src/Ethereum/ABI/Parameters.h | 8 +- src/Ethereum/ABI/Tuple.h | 2 +- src/Ethereum/AddressChecksum.cpp | 2 +- src/Ethereum/ContractCall.cpp | 12 +- src/Ethereum/Entry.cpp | 18 +- src/Ethereum/RLP.cpp | 4 +- src/Ethereum/Transaction.cpp | 2 +- src/FIO/Entry.cpp | 6 +- src/FIO/Signer.cpp | 2 +- src/Filecoin/Address.cpp | 6 +- src/Filecoin/Entry.cpp | 8 +- src/Groestlcoin/Entry.cpp | 8 +- src/Harmony/Entry.cpp | 10 +- src/Icon/Entry.cpp | 6 +- src/IoTeX/Entry.cpp | 6 +- src/Keystore/EncryptionParameters.cpp | 2 +- src/Keystore/StoredKey.cpp | 2 +- src/Kusama/Entry.cpp | 8 +- src/NEAR/Entry.cpp | 10 +- src/NEO/Address.cpp | 2 +- src/NEO/Entry.cpp | 10 +- src/NEO/ReadData.cpp | 2 +- src/NEO/Transaction.h | 2 +- src/NEO/TransactionAttribute.h | 4 +- src/NULS/BinaryCoding.h | 2 +- src/NULS/Entry.cpp | 6 +- src/Nano/Entry.cpp | 10 +- src/Nebulas/Entry.cpp | 6 +- src/Nimiq/Entry.cpp | 6 +- src/Oasis/Entry.cpp | 6 +- src/Ontology/Asset.h | 11 +- src/Ontology/Entry.cpp | 6 +- src/Polkadot/Entry.cpp | 8 +- src/PrivateKey.cpp | 2 +- src/PrivateKey.h | 2 +- src/Result.h | 2 +- src/Ripple/Entry.cpp | 6 +- src/Ripple/Signer.cpp | 2 +- src/Ronin/Entry.cpp | 12 +- src/Solana/Entry.cpp | 10 +- src/Solana/Program.cpp | 2 +- src/Stellar/Entry.cpp | 6 +- src/Stellar/Signer.cpp | 2 +- src/THORChain/Entry.cpp | 4 +- src/THORChain/Swap.cpp | 6 +- src/Tezos/BinaryCoding.cpp | 6 +- src/Tezos/BinaryCoding.h | 2 +- src/Tezos/Entry.cpp | 8 +- src/Tezos/Forging.cpp | 2 +- src/Theta/Entry.cpp | 2 +- src/Tron/Entry.cpp | 6 +- src/VeChain/Entry.cpp | 2 +- src/Waves/Entry.cpp | 6 +- src/Zcash/Entry.cpp | 12 +- src/Zcash/Transaction.cpp | 2 +- src/Zilliqa/AddressChecksum.cpp | 2 +- src/Zilliqa/Entry.cpp | 10 +- src/interface/TWData.cpp | 2 +- src/interface/TWPrivateKey.cpp | 4 +- src/interface/TWTransactionCompiler.cpp | 2 +- swift/common-xcframework.yml | 2 +- swift/project.yml | 2 +- tests/Bech32Tests.cpp | 2 +- tests/BinaryCodingTests.cpp | 4 - tests/Bitcoin/BitcoinScriptTests.cpp | 30 +-- tests/Bitcoin/InputSelectorTests.cpp | 16 +- tests/Bitcoin/SegwitAddressTests.cpp | 10 +- tests/Bitcoin/TWBitcoinScriptTests.cpp | 6 +- tests/Bitcoin/TWBitcoinSigningTests.cpp | 40 ++-- tests/Bitcoin/TWBitcoinTransactionTests.cpp | 2 +- tests/Bitcoin/TransactionPlanTests.cpp | 30 +-- tests/Bitcoin/TxComparisonHelper.cpp | 6 +- tests/BitcoinCash/TWBitcoinCashTests.cpp | 2 +- tests/BitcoinGold/TWSignerTests.cpp | 2 +- tests/Cardano/AddressTests.cpp | 4 +- tests/Cardano/SigningTests.cpp | 200 ++++++++-------- tests/Cardano/TWCardanoAddressTests.cpp | 6 +- tests/Cardano/TransactionTests.cpp | 34 +-- tests/CborTests.cpp | 148 ++++++------ tests/DataTests.cpp | 16 +- tests/Decred/TWAnySignerTests.cpp | 2 +- tests/DerivationPathTests.cpp | 16 +- tests/ECash/TWECashTests.cpp | 2 +- tests/Elrond/TransactionFactoryTests.cpp | 42 ++-- tests/EncryptTests.cpp | 36 +-- tests/Ethereum/AbiStructTests.cpp | 24 +- tests/Ethereum/AbiTests.cpp | 218 +++++++++--------- tests/Ethereum/ContractCallTests.cpp | 2 +- tests/Ethereum/RLPTests.cpp | 10 +- tests/Ethereum/TWAnySignerTests.cpp | 2 +- tests/Ethereum/TWEthereumAbiTests.cpp | 16 +- tests/Ethereum/ValueDecoderTests.cpp | 6 +- tests/Ethereum/ValueEncoderTests.cpp | 24 +- tests/FIO/AddressTests.cpp | 2 +- tests/FIO/EncryptionTests.cpp | 8 +- tests/FIO/TWFIOTests.cpp | 2 +- tests/FIO/TransactionBuilderTests.cpp | 6 +- tests/HDWallet/HDWalletTests.cpp | 18 +- tests/Keystore/StoredKeyTests.cpp | 106 ++++----- tests/NEO/TransactionTests.cpp | 8 +- tests/Ontology/ParamsBuilderTests.cpp | 4 +- tests/Ontology/TransactionTests.cpp | 10 +- tests/PrivateKeyTests.cpp | 12 +- tests/PublicKeyTests.cpp | 34 +-- tests/Ripple/AddressTests.cpp | 4 +- tests/Ripple/TransactionTests.cpp | 2 +- tests/Solana/SignerTests.cpp | 4 +- tests/Solana/TransactionTests.cpp | 12 +- tests/THORChain/SwapTests.cpp | 4 +- tests/THORChain/TWSwapTests.cpp | 10 +- tests/TransactionCompilerTests.cpp | 24 +- tests/WalletConsoleTests.cpp | 2 +- tests/algorithm/erase_tests.cpp | 10 +- tests/interface/TWBase32Tests.cpp | 4 +- tests/interface/TWDataTests.cpp | 8 +- tests/interface/TWDataVectorTests.cpp | 14 +- tests/interface/TWHDWalletTests.cpp | 2 +- tests/interface/TWPublicKeyTests.cpp | 6 +- tests/interface/TWStoredKeyTests.cpp | 22 +- .../interface/TWTransactionCompilerTests.cpp | 10 +- walletconsole/lib/Address.cpp | 2 +- walletconsole/lib/Buffer.cpp | 4 +- walletconsole/lib/CommandExecutor.cpp | 2 +- walletconsole/lib/CommandExecutor.h | 2 +- walletconsole/lib/Keys.cpp | 4 +- walletconsole/lib/Util.cpp | 2 +- 163 files changed, 941 insertions(+), 941 deletions(-) diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake index c62632cdb71..ca4b3f2ec87 100644 --- a/cmake/CompilerWarnings.cmake +++ b/cmake/CompilerWarnings.cmake @@ -47,12 +47,12 @@ target_compile_options( tw_error_settings INTERFACE -Wall - #-Wextra # reasonable and standard + -Wextra # reasonable and standard -Wfatal-errors # short error report #-Wshadow # warn the user if a variable declaration shadows one from a -Wshorten-64-to-32 # parent context - #-Wnon-virtual-dtor # warn the user if a class with virtual functions has a + -Wnon-virtual-dtor # warn the user if a class with virtual functions has a # non-virtual destructor. This helps catch hard to # track down memory errors #-Wold-style-cast # warn for c-style casts diff --git a/src/Aeternity/Entry.cpp b/src/Aeternity/Entry.cpp index 97d72906e63..896b784716e 100644 --- a/src/Aeternity/Entry.cpp +++ b/src/Aeternity/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Aion/Entry.cpp b/src/Aion/Entry.cpp index 66fe6240a60..e9f79e1e333 100644 --- a/src/Aion/Entry.cpp +++ b/src/Aion/Entry.cpp @@ -15,19 +15,19 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { const auto addr = Address(address); return {addr.bytes.begin(), addr.bytes.end()}; } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Algorand/BaseTransaction.h b/src/Algorand/BaseTransaction.h index 1db984c5a3d..232c5ed2b00 100644 --- a/src/Algorand/BaseTransaction.h +++ b/src/Algorand/BaseTransaction.h @@ -12,7 +12,8 @@ namespace TW::Algorand { class BaseTransaction { - public: +public: + virtual ~BaseTransaction() noexcept = default; virtual Data serialize() const = 0; virtual Data serialize(const Data& signature) const { /* Algorand transaction and signature are encoded with msgpack: diff --git a/src/Algorand/Entry.cpp b/src/Algorand/Entry.cpp index 29f9809955f..eb905d043d0 100644 --- a/src/Algorand/Entry.cpp +++ b/src/Algorand/Entry.cpp @@ -14,18 +14,18 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } diff --git a/src/Binance/Entry.cpp b/src/Binance/Entry.cpp index c98b659e824..71c6a6a8d50 100644 --- a/src/Binance/Entry.cpp +++ b/src/Binance/Entry.cpp @@ -15,15 +15,15 @@ using namespace TW::Binance; using namespace TW; using namespace std; -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { Address addr; if (!Address::decode(address, addr)) { return Data(); @@ -31,15 +31,15 @@ Data Entry::addressToData(TWCoinType coin, const std::string& address) const { return addr.getKeyHash(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } -Data Entry::preImageHashes(TWCoinType coin, const Data& txInputData) const { +Data Entry::preImageHashes([[maybe_unused]] TWCoinType coin, const Data& txInputData) const { return txCompilerTemplate( txInputData, [](const auto& input, auto& output) { Signer signer(input); @@ -51,7 +51,7 @@ Data Entry::preImageHashes(TWCoinType coin, const Data& txInputData) const { }); } -void Entry::compile(TWCoinType coin, const Data& txInputData, const std::vector& signatures, const std::vector& publicKeys, Data& dataOut) const { +void Entry::compile([[maybe_unused]] TWCoinType coin, const Data& txInputData, const std::vector& signatures, const std::vector& publicKeys, Data& dataOut) const { dataOut = txCompilerTemplate( txInputData, [&](const auto& input, auto& output) { if (signatures.size() == 0 || publicKeys.size() == 0) { @@ -68,7 +68,7 @@ void Entry::compile(TWCoinType coin, const Data& txInputData, const std::vector< }); } -Data Entry::buildTransactionInput(TWCoinType coinType, const std::string& from, const std::string& to, const uint256_t& amount, const std::string& asset, const std::string& memo, const std::string& chainId) const { +Data Entry::buildTransactionInput([[maybe_unused]] TWCoinType coinType, const std::string& from, const std::string& to, const uint256_t& amount, const std::string& asset, const std::string& memo, const std::string& chainId) const { auto input = Proto::SigningInput(); input.set_chain_id(chainId); input.set_account_number(0); diff --git a/src/Bitcoin/Entry.cpp b/src/Bitcoin/Entry.cpp index 1dfbccc261f..6d133133ef7 100644 --- a/src/Bitcoin/Entry.cpp +++ b/src/Bitcoin/Entry.cpp @@ -147,20 +147,20 @@ Data Entry::addressToData(TWCoinType coin, const std::string& address) const { } } -void Entry::sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const Data& dataIn, Data& dataOut) const { signTemplate(dataIn, dataOut); } -void Entry::plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const { +void Entry::plan([[maybe_unused]] TWCoinType coin, const Data& dataIn, Data& dataOut) const { planTemplate(dataIn, dataOut); } -Data Entry::preImageHashes(TWCoinType coin, const Data& txInputData) const { +Data Entry::preImageHashes([[maybe_unused]] TWCoinType coin, const Data& txInputData) const { return txCompilerTemplate( txInputData, [](auto&& input, auto&& output) { output = Signer::preImageHashes(input); }); } -void Entry::compile(TWCoinType coin, const Data& txInputData, const std::vector& signatures, +void Entry::compile([[maybe_unused]] TWCoinType coin, const Data& txInputData, const std::vector& signatures, const std::vector& publicKeys, Data& dataOut) const { auto txCompilerFunctor = [&signatures, &publicKeys](auto&& input, auto&& output) noexcept { if (signatures.empty() || publicKeys.empty()) { diff --git a/src/Bitcoin/FeeCalculator.cpp b/src/Bitcoin/FeeCalculator.cpp index 961ce3dfbcb..ffae2669621 100644 --- a/src/Bitcoin/FeeCalculator.cpp +++ b/src/Bitcoin/FeeCalculator.cpp @@ -34,9 +34,9 @@ class DecredFeeCalculator : public LinearFeeCalculator { : LinearFeeCalculator(gDecredBytesPerInput, gDecredBytesPerOutput, gDecredBytesBase) {} }; -constexpr DefaultFeeCalculator defaultFeeCalculator{}; -constexpr DecredFeeCalculator decredFeeCalculator{}; -constexpr SegwitFeeCalculator segwitFeeCalculator{}; +static constexpr DefaultFeeCalculator defaultFeeCalculator{}; +static constexpr DecredFeeCalculator decredFeeCalculator{}; +static constexpr SegwitFeeCalculator segwitFeeCalculator{}; const FeeCalculator& getFeeCalculator(TWCoinType coinType) noexcept { switch (coinType) { diff --git a/src/Bitcoin/FeeCalculator.h b/src/Bitcoin/FeeCalculator.h index 5d7dbb857e3..49b76b28a75 100644 --- a/src/Bitcoin/FeeCalculator.h +++ b/src/Bitcoin/FeeCalculator.h @@ -20,6 +20,7 @@ inline constexpr double gSegwitBytesBase{gDefaultBytesBase}; /// Interface for transaction fee calculator. class FeeCalculator { public: + virtual ~FeeCalculator() noexcept = default; [[nodiscard]] virtual int64_t calculate(int64_t inputs, int64_t outputs, int64_t byteFee) const noexcept = 0; [[nodiscard]] virtual int64_t calculateSingleInput(int64_t byteFee) const noexcept = 0; @@ -46,11 +47,11 @@ class ConstantFeeCalculator : public FeeCalculator { const int64_t fee; explicit constexpr ConstantFeeCalculator(int64_t fee) noexcept : fee(fee) {} - [[nodiscard]] int64_t calculate(int64_t inputs, int64_t outputs, - int64_t byteFee) const noexcept final { + [[nodiscard]] int64_t calculate([[maybe_unused]] int64_t inputs, [[maybe_unused]] int64_t outputs, + [[maybe_unused]] int64_t byteFee) const noexcept final { return fee; } - [[nodiscard]] int64_t calculateSingleInput(int64_t byteFee) const noexcept final { return 0; } + [[nodiscard]] int64_t calculateSingleInput([[maybe_unused]] int64_t byteFee) const noexcept final { return 0; } }; /// Default Bitcoin transaction fee calculator, non-segwit. diff --git a/src/Bitcoin/InputSelector.cpp b/src/Bitcoin/InputSelector.cpp index 1104344285f..a5025c4136d 100644 --- a/src/Bitcoin/InputSelector.cpp +++ b/src/Bitcoin/InputSelector.cpp @@ -39,7 +39,7 @@ InputSelector::filterThreshold(const std::vector uint64_t minimumAmount) noexcept { std::vector filtered; for (auto& i : inputs) { - if (i.amount > minimumAmount) { + if (static_cast(i.amount) > minimumAmount) { filtered.push_back(i); } } @@ -55,7 +55,7 @@ template static inline std::vector> slice(const std::vector& inputs, size_t sliceSize) { std::vector> slices; - for (auto i = 0; i <= inputs.size() - sliceSize; ++i) { + for (auto i = 0ul; i <= inputs.size() - sliceSize; ++i) { slices.emplace_back(); slices[i].reserve(sliceSize); for (auto j = i; j < i + sliceSize; j++) { @@ -67,7 +67,7 @@ slice(const std::vector& inputs, size_t sliceSize) { template std::vector -InputSelector::select(int64_t targetValue, int64_t byteFee, int64_t numOutputs) { +InputSelector::select(uint64_t targetValue, uint64_t byteFee, uint64_t numOutputs) { // if target value is zero, no UTXOs are needed if (targetValue == 0) { return {}; @@ -79,7 +79,7 @@ InputSelector::select(int64_t targetValue, int64_t byteFee, int6 } assert(inputs.size() >= 1); - // definitions for the following caluculation + // definitions for the following calculation const auto doubleTargetValue = targetValue * 2; // Get all possible utxo selections up to a maximum size, sort by total amount, increasing @@ -94,13 +94,13 @@ InputSelector::select(int64_t targetValue, int64_t byteFee, int6 std::vector maxWithXInputs = std::vector(); maxWithXInputs.push_back(0); int64_t maxSum = 0; - for (auto i = 0; i < n; ++i) { + for (auto i = 0ul; i < n; ++i) { maxSum += sorted[n - 1 - i].amount; maxWithXInputs.push_back(maxSum); } // difference from 2x targetValue - auto distFrom2x = [doubleTargetValue](int64_t val) -> int64_t { + auto distFrom2x = [doubleTargetValue](uint64_t val) -> uint64_t { if (val > doubleTargetValue) { return val - doubleTargetValue; } diff --git a/src/Bitcoin/InputSelector.h b/src/Bitcoin/InputSelector.h index 2031143cd95..ebd128e85a1 100644 --- a/src/Bitcoin/InputSelector.h +++ b/src/Bitcoin/InputSelector.h @@ -21,8 +21,8 @@ class InputSelector { /// /// \returns the list of indices of selected inputs, or an empty list if there are insufficient /// funds. - std::vector select(int64_t targetValue, int64_t byteFee, - int64_t numOutputs = 2); + std::vector select(uint64_t targetValue, uint64_t byteFee, + uint64_t numOutputs = 2); /// Selects unspent transactions to use given a target transaction value; /// Simplified version suitable for large number of inputs diff --git a/src/Bitcoin/Script.cpp b/src/Bitcoin/Script.cpp index 126e165fd3a..26a468d0b14 100644 --- a/src/Bitcoin/Script.cpp +++ b/src/Bitcoin/Script.cpp @@ -148,8 +148,8 @@ bool Script::matchMultisig(std::vector& keys, int& required) const { return false; } - auto expectedCount = decodeNumber(opcode); - if (keys.size() != expectedCount || expectedCount < required) { + std::size_t expectedCount = decodeNumber(opcode); + if (keys.size() != expectedCount || expectedCount < static_cast(required)) { return false; } if (it + 1 != bytes.size()) { diff --git a/src/Bitcoin/SignatureBuilder.cpp b/src/Bitcoin/SignatureBuilder.cpp index d791ea75a5e..7f534cba603 100644 --- a/src/Bitcoin/SignatureBuilder.cpp +++ b/src/Bitcoin/SignatureBuilder.cpp @@ -38,7 +38,7 @@ Result SignatureBuilder:: std::back_inserter(transactionToSign.inputs)); const auto hashSingle = hashTypeIsSingle(input.hashType); - for (auto i = 0; i < plan.utxos.size(); i++) { + for (auto i = 0ul; i < plan.utxos.size(); i++) { // Only sign TWBitcoinSigHashTypeSingle if there's a corresponding output if (hashSingle && i >= transaction.outputs.size()) { continue; @@ -162,7 +162,7 @@ Result, Common::Proto::SigningError> SignatureBuilder{{}}; // workaround CHECKMULTISIG bug for (auto& pubKey : keys) { - if (results.size() >= required + 1) { + if (results.size() >= required + 1ul) { break; } auto keyHash = Hash::ripemd(Hash::sha256(pubKey)); @@ -286,7 +286,7 @@ Data SignatureBuilder::createSignature( const auto key = std::get<0>(pair.value()); const auto pk = PrivateKey(key); - auto sig = pk.signAsDER(sighash, TWCurveSECP256k1); + auto sig = pk.signAsDER(sighash); if (!sig.empty()) { sig.push_back(static_cast(input.hashType)); } diff --git a/src/Bitcoin/Transaction.cpp b/src/Bitcoin/Transaction.cpp index c5fd33f1afa..6cf74961fd9 100644 --- a/src/Bitcoin/Transaction.cpp +++ b/src/Bitcoin/Transaction.cpp @@ -185,7 +185,7 @@ Data Transaction::getSignatureHashBase(const Script& scriptCode, size_t index, auto serializedInputCount = (hashType & TWBitcoinSigHashTypeAnyoneCanPay) != 0 ? 1 : inputs.size(); encodeVarInt(serializedInputCount, data); - for (auto subindex = 0; subindex < serializedInputCount; subindex += 1) { + for (auto subindex = 0ul; subindex < serializedInputCount; subindex += 1) { serializeInput(subindex, scriptCode, index, hashType, data); } @@ -193,7 +193,7 @@ Data Transaction::getSignatureHashBase(const Script& scriptCode, size_t index, auto hashSingle = hashTypeIsSingle(hashType); auto serializedOutputCount = hashNone ? 0 : (hashSingle ? index + 1 : outputs.size()); encodeVarInt(serializedOutputCount, data); - for (auto subindex = 0; subindex < serializedOutputCount; subindex += 1) { + for (auto subindex = 0ul; subindex < serializedOutputCount; subindex += 1) { if (hashSingle && subindex != index) { auto output = TransactionOutput(-1, {}); output.encode(data); diff --git a/src/Bitcoin/TransactionBuilder.cpp b/src/Bitcoin/TransactionBuilder.cpp index 464d651f544..82ac0367a14 100644 --- a/src/Bitcoin/TransactionBuilder.cpp +++ b/src/Bitcoin/TransactionBuilder.cpp @@ -104,7 +104,7 @@ TransactionPlan TransactionBuilder::plan(const SigningInput& input) { // if amount requested is the same or more than available amount, it cannot be satisifed, but // treat this case as MaxAmount, and send maximum available (which will be less) - if (!maxAmount && input.amount >= inputSum) { + if (!maxAmount && static_cast(input.amount) >= inputSum) { maxAmount = true; } @@ -127,7 +127,7 @@ TransactionPlan TransactionBuilder::plan(const SigningInput& input) { } else { // truncate to limit number of selected UTXOs plan.utxos.clear(); - for (auto i = 0; i < MaxUtxosHardLimit; ++i) { + for (auto i = 0ul; i < MaxUtxosHardLimit; ++i) { plan.utxos.push_back(selectedInputs[i]); } } diff --git a/src/Cardano/Entry.cpp b/src/Cardano/Entry.cpp index 4cac8a06ae4..e76beaf769d 100644 --- a/src/Cardano/Entry.cpp +++ b/src/Cardano/Entry.cpp @@ -18,22 +18,22 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return AddressV3::isValidLegacy(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return AddressV3(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { return AddressV3(address).data(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -void Entry::plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const { +void Entry::plan([[maybe_unused]] TWCoinType coin, const Data& dataIn, Data& dataOut) const { planTemplate(dataIn, dataOut); } diff --git a/src/Cardano/Signer.cpp b/src/Cardano/Signer.cpp index bd89f279dd4..fab8c008eb3 100644 --- a/src/Cardano/Signer.cpp +++ b/src/Cardano/Signer.cpp @@ -210,7 +210,7 @@ vector selectInputsSimpleNative(const vector& inputs, Amount a // Select a subset of inputs, to cover desired token amount. Simple algorithm: pick largest ones. void selectInputsSimpleToken(const vector& inputs, string key, uint256_t amount, vector& selectedInputs) { - uint256_t selectedAmount = std::accumulate(selectedInputs.begin(), selectedInputs.end(), uint256_t(0), [key](uint256_t sum, const TxInput& si){ return si.tokenBundle.getAmount(key); }); + uint256_t selectedAmount = std::accumulate(selectedInputs.begin(), selectedInputs.end(), uint256_t(0), [key]([[maybe_unused]] uint256_t sum, const TxInput& si){ return si.tokenBundle.getAmount(key); }); if (selectedAmount >= amount) { return; // already covered } @@ -218,7 +218,7 @@ void selectInputsSimpleToken(const vector& inputs, string key, uint256_ auto ii = vector(inputs); std::sort(ii.begin(), ii.end(), [key](TxInput t1, TxInput t2) { return t1.tokenBundle.getAmount(key) > t2.tokenBundle.getAmount(key); }); for (const auto& i: ii) { - if (distance(selectedInputs.begin(), find(selectedInputs.begin(), selectedInputs.end(), i)) < selectedInputs.size()) { + if (static_cast(distance(selectedInputs.begin(), find(selectedInputs.begin(), selectedInputs.end(), i))) < selectedInputs.size()) { // already selected continue; } diff --git a/src/Cbor.cpp b/src/Cbor.cpp index cccab743fe2..acbf4217c97 100644 --- a/src/Cbor.cpp +++ b/src/Cbor.cpp @@ -46,7 +46,7 @@ Encode Encode::array(const vector& elems) { Encode e; auto n = elems.size(); e.appendValue(Decode::MT_array, n); - for (int i = 0; i < n; ++i) { + for (auto i = 0ul; i < n; ++i) { e.append(elems[i].encoded()); } return e; @@ -56,7 +56,7 @@ Encode Encode::map(const vector>& elems) { Encode e; auto n = elems.size(); e.appendValue(Decode::MT_map, n); - for (int i = 0; i < n; ++i) { + for (auto i = 0ul; i < n; ++i) { e.append(elems[i].first.encoded()); e.append(elems[i].second.encoded()); } @@ -131,7 +131,7 @@ Encode Encode::appendValue(byte majorType, uint64_t value) { // add bytes TW::append(data, (byte)((majorType << 5) | (minorType & 0x1F))); Data valBytes = Data(byteCount - 1); - for (int i = 0; i < valBytes.size(); ++i) { + for (auto i = 0ul; i < valBytes.size(); ++i) { valBytes[valBytes.size() - 1 - i] = (byte)(value & 0xFF); value = value >> 8; } @@ -279,7 +279,7 @@ uint32_t Decode::getCompoundLength(uint32_t countMultiplier) const { uint32_t count = typeDesc.isIndefiniteValue ? 0 : (uint32_t)(typeDesc.value * countMultiplier); // process elements len += typeDesc.byteCount; - for (int i = 0; i < count || typeDesc.isIndefiniteValue; ++i) { + for (auto i = 0ul; i < count || typeDesc.isIndefiniteValue; ++i) { Decode nextElem = skipClone(len); if (typeDesc.isIndefiniteValue && nextElem.isBreak()) { // end of indefinite-length @@ -304,7 +304,7 @@ vector Decode::getCompoundElements(uint32_t countMultiplier, TW::byte ex uint32_t count = typeDesc.isIndefiniteValue ? 0 : (uint32_t)(typeDesc.value * countMultiplier); // process elements uint32_t idx = typeDesc.byteCount; - for (int i = 0; i < count || typeDesc.isIndefiniteValue; ++i) { + for (auto i = 0ul; i < count || typeDesc.isIndefiniteValue; ++i) { Decode nextElem = skipClone(idx); if (typeDesc.isIndefiniteValue && nextElem.isBreak()) { // end of indefinite-length @@ -323,7 +323,7 @@ vector Decode::getCompoundElements(uint32_t countMultiplier, TW::byte ex vector> Decode::getMapElements() const { auto elems = getCompoundElements(2, MT_map); vector> map; - for (int i = 0; i < elems.size(); i += 2) { + for (auto i = 0ul; i < elems.size(); i += 2) { map.emplace_back(make_pair(elems[i], elems[i + 1])); } return map; @@ -369,7 +369,7 @@ bool Decode::isValid() const { if (len > subLen) { return false; } auto count = typeDesc.isIndefiniteValue ? 0 : countMultiplier * typeDesc.value; uint32_t idx = typeDesc.byteCount; - for (int i = 0; i < count || typeDesc.isIndefiniteValue; ++i) + for (auto i = 0ul; i < count || typeDesc.isIndefiniteValue; ++i) { Decode nextElem = skipClone(idx); if (typeDesc.isIndefiniteValue && nextElem.isBreak()) { break; } @@ -416,7 +416,7 @@ string Decode::dumpToStringInternal() const { s << "["; } vector elems = getArrayElements(); - for (int i = 0; i < elems.size(); ++i) { + for (auto i = 0ul; i < elems.size(); ++i) { if (i > 0) s << ", "; s << elems[i].dumpToStringInternal(); } @@ -432,7 +432,7 @@ string Decode::dumpToStringInternal() const { s << "{"; } auto elems = getMapElements(); - for (int i = 0; i < elems.size(); ++i) { + for (auto i = 0ul; i < elems.size(); ++i) { if (i > 0) s << ", "; s << elems[i].first.dumpToStringInternal() << ": " << elems[i].second.dumpToStringInternal(); } diff --git a/src/CoinEntry.h b/src/CoinEntry.h index bff6736752c..b0ab4bd72d3 100644 --- a/src/CoinEntry.h +++ b/src/CoinEntry.h @@ -27,37 +27,38 @@ typedef std::vector> HashPubkeyList; /// Implement this for all coins. class CoinEntry { public: + virtual ~CoinEntry() noexcept = default; virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const = 0; // normalizeAddress is optional, it may leave this default, no-change implementation - virtual std::string normalizeAddress(TWCoinType coin, const std::string& address) const { return address; } + virtual std::string normalizeAddress([[maybe_unused]] TWCoinType coin, const std::string& address) const { return address; } // Address derivation, default derivation virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const = 0; // Address derivation, by default invoking default - virtual std::string deriveAddress(TWCoinType coin, TWDerivation derivation, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const { + virtual std::string deriveAddress(TWCoinType coin, [[maybe_unused]] TWDerivation derivation, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const { return deriveAddress(coin, publicKey, p2pkh, hrp); } // Return the binary representation of a string address, used by AnyAddress // It is optional, if not defined, 'AnyAddress' interface will not support this coin. - virtual Data addressToData(TWCoinType coin, const std::string& address) const { return {}; } + virtual Data addressToData([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const std::string& address) const { return {}; } // Signing virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const = 0; virtual bool supportsJSONSigning() const { return false; } // It is optional, Signing JSON input with private key - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const { return ""; } + virtual std::string signJSON([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const std::string& json, [[maybe_unused]] const Data& key) const { return ""; } // Planning, for UTXO chains, in preparation for signing // It is optional, only UTXO chains need it, default impl. leaves empty result. - virtual void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const { return; } + virtual void plan([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const Data& dataIn, [[maybe_unused]] Data& dataOut) const { } // Optional method for obtaining hash(es) for signing, needed for external signing. // It will return a proto object named `PreSigningOutput` which will include hash. // We provide a default `PreSigningOutput` in TransactionCompiler.proto. // For some special coins, such as bitcoin, we will create a custom `PreSigningOutput` object in its proto file. - virtual Data preImageHashes(TWCoinType coin, const Data& txInputData) const { return Data(); } + virtual Data preImageHashes([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const Data& txInputData) const { return {}; } // Optional method for compiling a transaction with externally-supplied signatures & pubkeys. - virtual void compile(TWCoinType coin, const Data& txInputData, const std::vector& signatures, const std::vector& publicKeys, Data& dataOut) const {} + virtual void compile([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const Data& txInputData, [[maybe_unused]] const std::vector& signatures, [[maybe_unused]] const std::vector& publicKeys, [[maybe_unused]] Data& dataOut) const {} // Optional helper to prepare a SigningInput from simple parameters. // Not suitable for UTXO chains. Some parameters, like chain-specific fee/gas paraemters, may need to be set in the SigningInput. - virtual Data buildTransactionInput(TWCoinType coinType, const std::string& from, const std::string& to, const uint256_t& amount, const std::string& asset, const std::string& memo, const std::string& chainId) const { return Data(); } + virtual Data buildTransactionInput([[maybe_unused]] TWCoinType coinType, [[maybe_unused]] const std::string& from, [[maybe_unused]] const std::string& to, [[maybe_unused]] const uint256_t& amount, [[maybe_unused]] const std::string& asset, [[maybe_unused]] const std::string& memo, [[maybe_unused]] const std::string& chainId) const { return Data(); } }; // In each coin's Entry.cpp the specific types of the coin are used, this template enforces the Signer implement: diff --git a/src/Cosmos/Entry.cpp b/src/Cosmos/Entry.cpp index 686ebe06557..bc5976080f4 100644 --- a/src/Cosmos/Entry.cpp +++ b/src/Cosmos/Entry.cpp @@ -15,15 +15,15 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char* hrp) const { +bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, [[maybe_unused]] const char* hrp) const { return Address::isValid(coin, address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char* hrp) const { +string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, [[maybe_unused]] const char* hrp) const { return Address(coin, publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { Address addr; if (!Address::decode(address, addr)) { return Data(); diff --git a/src/Cosmos/ProtobufSerialization.cpp b/src/Cosmos/ProtobufSerialization.cpp index a22ec52bad3..4364b3e0409 100644 --- a/src/Cosmos/ProtobufSerialization.cpp +++ b/src/Cosmos/ProtobufSerialization.cpp @@ -310,7 +310,7 @@ Data buildSignature(const Proto::SigningInput& input, const std::string& seriali return signature; } -std::string buildProtoTxRaw(const Proto::SigningInput& input, const std::string& serializedTxBody, const std::string& serializedAuthInfo, const Data& signature) { +std::string buildProtoTxRaw(const std::string& serializedTxBody, const std::string& serializedAuthInfo, const Data& signature) { auto txRaw = cosmos::TxRaw(); txRaw.set_body_bytes(serializedTxBody); txRaw.set_auth_info_bytes(serializedAuthInfo); diff --git a/src/Cosmos/ProtobufSerialization.h b/src/Cosmos/ProtobufSerialization.h index de41eb3269b..28c49be0c57 100644 --- a/src/Cosmos/ProtobufSerialization.h +++ b/src/Cosmos/ProtobufSerialization.h @@ -22,7 +22,7 @@ std::string buildAuthInfo(const Proto::SigningInput& input, TWCoinType coin); Data buildSignature(const Proto::SigningInput& input, const std::string& serializedTxBody, const std::string& serializedAuthInfo, TWCoinType coin); -std::string buildProtoTxRaw(const Proto::SigningInput& input, const std::string& serializedTxBody, const std::string& serializedAuthInfo, const Data& signature); +std::string buildProtoTxRaw(const std::string& serializedTxBody, const std::string& serializedAuthInfo, const Data& signature); std::string buildProtoTxJson(const Proto::SigningInput& input, const std::string& serializedTx); diff --git a/src/Cosmos/Signer.cpp b/src/Cosmos/Signer.cpp index f8f109b683d..5c2a9e0ac60 100644 --- a/src/Cosmos/Signer.cpp +++ b/src/Cosmos/Signer.cpp @@ -48,7 +48,7 @@ Proto::SigningOutput Signer::signProtobuf(const Proto::SigningInput& input, TWCo const auto serializedTxBody = buildProtoTxBody(input); const auto serializedAuthInfo = buildAuthInfo(input, coin); const auto signature = buildSignature(input, serializedTxBody, serializedAuthInfo, coin); - auto serializedTxRaw = buildProtoTxRaw(input, serializedTxBody, serializedAuthInfo, signature); + auto serializedTxRaw = buildProtoTxRaw(serializedTxBody, serializedAuthInfo, signature); auto output = Proto::SigningOutput(); const string jsonSerialized = buildProtoTxJson(input, serializedTxRaw); diff --git a/src/Crc.cpp b/src/Crc.cpp index 7a388a7c03c..37f4ea8ad6c 100644 --- a/src/Crc.cpp +++ b/src/Crc.cpp @@ -17,7 +17,7 @@ uint16_t Crc::crc16(uint8_t* bytes, uint32_t length) { uint16_t crc = 0x0000; const uint16_t polynomial = 0x1021; - for (auto i = 0; i < length; i++) { + for (auto i = 0ul; i < length; i++) { const auto byte = bytes[i]; for (auto bitidx = 0; bitidx < 8; bitidx++) { const auto bit = ((byte >> (7 - bitidx) & 1) == 1); diff --git a/src/Decred/Entry.cpp b/src/Decred/Entry.cpp index 31faf5c04ac..9704a99c842 100644 --- a/src/Decred/Entry.cpp +++ b/src/Decred/Entry.cpp @@ -13,23 +13,23 @@ using namespace TW::Decred; using namespace TW; using namespace std; -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] TW::byte p2sh, [[maybe_unused]] const char* hrp) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] const char* hrp) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { const auto addr = Address(address); return {addr.bytes.begin() + 2, addr.bytes.end()}; } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -void Entry::plan(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::plan([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { planTemplate(dataIn, dataOut); } diff --git a/src/Decred/Signer.cpp b/src/Decred/Signer.cpp index 6105aa5938c..d03766bb27a 100644 --- a/src/Decred/Signer.cpp +++ b/src/Decred/Signer.cpp @@ -54,7 +54,7 @@ Result Signer::sign() { signedInputs = transaction.inputs; const auto hashSingle = Bitcoin::hashTypeIsSingle(static_cast(input.hash_type())); - for (auto i = 0; i < txPlan.utxos.size(); i += 1) { + for (auto i = 0ul; i < txPlan.utxos.size(); i += 1) { auto& utxo = txPlan.utxos[i]; // Only sign TWBitcoinSigHashTypeSingle if there's a corresponding output @@ -149,7 +149,7 @@ Result, Common::Proto::SigningError> Signer::signStep(Bitcoin: } else if (script.matchMultisig(keys, required)) { auto results = std::vector{{}}; for (auto& pubKey : keys) { - if (results.size() >= required + 1) { + if (results.size() >= required + 1ul) { break; } auto keyHash = TW::Hash::ripemd(TW::Hash::blake256(pubKey)); @@ -177,7 +177,7 @@ Data Signer::createSignature(const Transaction& transaction, const Bitcoin::Scri const Data& key, size_t index) { auto sighash = transaction.computeSignatureHash(script, index, static_cast(input.hash_type())); auto pk = PrivateKey(key); - auto signature = pk.signAsDER(Data(begin(sighash), end(sighash)), TWCurveSECP256k1); + auto signature = pk.signAsDER(Data(begin(sighash), end(sighash))); if (script.empty()) { return {}; } diff --git a/src/Decred/Transaction.cpp b/src/Decred/Transaction.cpp index 705d37777bb..763731527e7 100644 --- a/src/Decred/Transaction.cpp +++ b/src/Decred/Transaction.cpp @@ -86,7 +86,7 @@ Data Transaction::computePrefixHash(const std::vector& inputsT // Commit to the relevant transaction inputs. encodeVarInt(inputsToSign.size(), preimage); - for (auto i = 0; i < inputsToSign.size(); i += 1) { + for (auto i = 0ul; i < inputsToSign.size(); i += 1) { auto& input = inputsToSign[i]; input.previousOutput.encode(preimage); @@ -100,7 +100,7 @@ Data Transaction::computePrefixHash(const std::vector& inputsT // Commit to the relevant transaction outputs. encodeVarInt(outputsToSign.size(), preimage); - for (auto i = 0; i < outputsToSign.size(); i += 1) { + for (auto i = 0ul; i < outputsToSign.size(); i += 1) { auto& output = outputsToSign[i]; auto value = output.value; auto pkScript = output.script; @@ -133,7 +133,7 @@ Data Transaction::computeWitnessHash(const std::vector& inputs // Commit to the relevant transaction inputs. encodeVarInt(inputsToSign.size(), witnessBuf); - for (auto i = 0; i < inputsToSign.size(); i += 1) { + for (auto i = 0ul; i < inputsToSign.size(); i += 1) { if (i == signIndex) { signScript.encode(witnessBuf); } else { diff --git a/src/EOS/Asset.cpp b/src/EOS/Asset.cpp index 17d03be7976..80638ceae43 100644 --- a/src/EOS/Asset.cpp +++ b/src/EOS/Asset.cpp @@ -25,7 +25,7 @@ Asset::Asset(int64_t amount, uint8_t decimals, const std::string& symbol) { throw std::invalid_argument("Symbol size invalid!"); } - for (int i = 0; i < symbol.size(); i++) { + for (std::size_t i = 0; i < symbol.size(); i++) { uint64_t c = symbol[i]; if (c < 'A' || c > 'Z') { throw std::invalid_argument("Invalid symbol " + symbol + ".\n Symbol can only have upper case alphabets!"); diff --git a/src/EOS/Entry.cpp b/src/EOS/Entry.cpp index 37de7a06c4c..36dc5df0da7 100644 --- a/src/EOS/Entry.cpp +++ b/src/EOS/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/EOS/Name.cpp b/src/EOS/Name.cpp index 07ec3a131e9..e42a5af8bf0 100644 --- a/src/EOS/Name.cpp +++ b/src/EOS/Name.cpp @@ -18,7 +18,7 @@ Name::Name(const std::string& str) { throw std::invalid_argument(str + ": size too long!"); } - int i = 0; + std::size_t i = 0; while (i < std::min(size_t(12), str.size())) { value |= (toSymbol(str[i]) & 0x1f) << (64 - (5 * (i + 1))); i++; @@ -59,4 +59,4 @@ std::string Name::string() const noexcept { void Name::serialize(Data& o) const noexcept { encode64LE(value, o); -} \ No newline at end of file +} diff --git a/src/EOS/Signer.cpp b/src/EOS/Signer.cpp index c268761018b..12a0c2833b6 100644 --- a/src/EOS/Signer.cpp +++ b/src/EOS/Signer.cpp @@ -102,7 +102,7 @@ TW::Data Signer::hash(const Transaction& transaction) const noexcept { } // canonical check for EOS -int Signer::isCanonical(uint8_t by, uint8_t sig[64]) { +int Signer::isCanonical([[maybe_unused]] uint8_t by, uint8_t sig[64]) { return !(sig[0] & 0x80) && !(sig[0] == 0 && !(sig[1] & 0x80)) && !(sig[32] & 0x80) diff --git a/src/Elrond/Entry.cpp b/src/Elrond/Entry.cpp index e97e307d91d..7ff8917f7e0 100644 --- a/src/Elrond/Entry.cpp +++ b/src/Elrond/Entry.cpp @@ -15,15 +15,15 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { Address addr; if (!Elrond::Address::decode(address, addr)) { return Data(); @@ -31,10 +31,10 @@ Data Entry::addressToData(TWCoinType coin, const std::string& address) const { return addr.getKeyHash(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } diff --git a/src/Ethereum/ABI/ParamBase.h b/src/Ethereum/ABI/ParamBase.h index 464fa92c109..161abdc7c0c 100644 --- a/src/Ethereum/ABI/ParamBase.h +++ b/src/Ethereum/ABI/ParamBase.h @@ -26,7 +26,7 @@ class ParamBase // EIP712-style hash of the value (used for signing); default implementation virtual Data hashStruct() const; // Helper for EIP712 encoding; provide full type of all used types (recursively). Default is empty implementation. - virtual std::string getExtraTypes(std::vector& ignoreList) const { return ""; } + virtual std::string getExtraTypes([[maybe_unused]] std::vector& ignoreList) const { return ""; } }; /// Collection of parameters base class diff --git a/src/Ethereum/ABI/ParamFactory.cpp b/src/Ethereum/ABI/ParamFactory.cpp index fbed6ce5f45..9a61eb71c1d 100644 --- a/src/Ethereum/ABI/ParamFactory.cpp +++ b/src/Ethereum/ABI/ParamFactory.cpp @@ -195,7 +195,7 @@ std::vector ParamFactory::getArrayValue(const std::shared_ptrgetVal(); std::vector values(elems.size()); - for (auto i = 0; i < elems.size(); ++i) { + for (auto i = 0ul; i < elems.size(); ++i) { values[i] = getValue(elems[i], elemType); } return values; diff --git a/src/Ethereum/ABI/ParamStruct.cpp b/src/Ethereum/ABI/ParamStruct.cpp index 124f7ec0e38..9346daa497c 100644 --- a/src/Ethereum/ABI/ParamStruct.cpp +++ b/src/Ethereum/ABI/ParamStruct.cpp @@ -212,9 +212,9 @@ std::shared_ptr ParamStruct::makeStruct(const std::string& structTy std::vector> params; const auto& typeParams = typeInfo->getParams(); // iterate through the type; order is important and field order in the value json is not defined - for (int i = 0; i < typeParams.getCount(); ++i) { - auto name = typeParams.getParam(i)->getName(); - auto type = typeParams.getParam(i)->getParam()->getType(); + for (auto i = 0ul; i < typeParams.getCount(); ++i) { + auto name = typeParams.getParam(static_cast(i))->getName(); + auto type = typeParams.getParam(static_cast(i))->getParam()->getType(); // look for it in value (may throw) auto value = values[name]; // first try simple params diff --git a/src/Ethereum/ABI/ParamStruct.h b/src/Ethereum/ABI/ParamStruct.h index 53eb8d42711..816720905dd 100644 --- a/src/Ethereum/ABI/ParamStruct.h +++ b/src/Ethereum/ABI/ParamStruct.h @@ -85,9 +85,9 @@ class ParamStruct: public ParamCollection virtual size_t getSize() const { return _params.getCount(); } virtual bool isDynamic() const { return true; } virtual size_t getCount() const { return _params.getCount(); } - virtual void encode(Data& data) const {} - virtual bool decode(const Data& encoded, size_t& offset_inout) { return true; } - virtual bool setValueJson(const std::string& value) { return false; } // see makeStruct + virtual void encode([[maybe_unused]] Data& data) const {} + virtual bool decode([[maybe_unused]] const Data& encoded, [[maybe_unused]] size_t& offset_inout) { return true; } + virtual bool setValueJson([[maybe_unused]] const std::string& value) { return false; } // see makeStruct Data encodeHashes() const; virtual std::string getExtraTypes(std::vector& ignoreList) const; std::shared_ptr findParamByName(const std::string& name) const { return _params.findParamByName(name); } diff --git a/src/Ethereum/ABI/Parameters.cpp b/src/Ethereum/ABI/Parameters.cpp index ed734d78257..40d1413434e 100644 --- a/src/Ethereum/ABI/Parameters.cpp +++ b/src/Ethereum/ABI/Parameters.cpp @@ -34,7 +34,7 @@ void ParamSet::addParams(const std::vector>& params) } } -bool ParamSet::getParam(int paramIndex, std::shared_ptr& param_out) const { +bool ParamSet::getParam(size_t paramIndex, std::shared_ptr& param_out) const { if (paramIndex >= _params.size() || paramIndex < 0) { return false; } @@ -42,7 +42,7 @@ bool ParamSet::getParam(int paramIndex, std::shared_ptr& param_out) c return true; } -std::shared_ptr ParamSet::getParamUnsafe(int paramIndex) const { +std::shared_ptr ParamSet::getParamUnsafe(size_t paramIndex) const { if (_params.size() == 0) { // zero parameter, nothing to return. This may cause trouble (segfault) return nullptr; diff --git a/src/Ethereum/ABI/Parameters.h b/src/Ethereum/ABI/Parameters.h index 4f62ff8f326..ac315235fbe 100644 --- a/src/Ethereum/ABI/Parameters.h +++ b/src/Ethereum/ABI/Parameters.h @@ -29,8 +29,8 @@ class ParamSet { /// Returns the index of the parameter int addParam(const std::shared_ptr& param); void addParams(const std::vector>& params); - bool getParam(int paramIndex, std::shared_ptr& param_out) const; - std::shared_ptr getParamUnsafe(int paramIndex) const; + bool getParam(size_t paramIndex, std::shared_ptr& param_out) const; + std::shared_ptr getParamUnsafe(size_t paramIndex) const; size_t getCount() const { return _params.size(); } std::vector> const& getParams() const { return _params; } /// Return the function type signature, of the form "baz(int32,uint256)" @@ -56,14 +56,14 @@ class Parameters: public ParamCollection Parameters(const std::vector>& params) : ParamCollection(), _params(ParamSet(params)) {} void addParam(const std::shared_ptr& param) { _params.addParam(param); } void addParams(const std::vector>& params) { _params.addParams(params); } - std::shared_ptr getParam(int paramIndex) const { return _params.getParamUnsafe(paramIndex); } + std::shared_ptr getParam(size_t paramIndex) const { return _params.getParamUnsafe(paramIndex); } virtual std::string getType() const { return _params.getType(); } virtual size_t getSize() const { return _params.getSize(); } virtual bool isDynamic() const { return true; } virtual size_t getCount() const { return _params.getCount(); } virtual void encode(Data& data) const { _params.encode(data); } virtual bool decode(const Data& encoded, size_t& offset_inout) { return _params.decode(encoded, offset_inout); } - virtual bool setValueJson(const std::string& value) { return false; } + virtual bool setValueJson([[maybe_unused]] const std::string& value) { return false; } virtual Data hashStruct() const; }; diff --git a/src/Ethereum/ABI/Tuple.h b/src/Ethereum/ABI/Tuple.h index b9aca129e28..6579f9784f6 100644 --- a/src/Ethereum/ABI/Tuple.h +++ b/src/Ethereum/ABI/Tuple.h @@ -34,7 +34,7 @@ class ParamTuple: public ParamCollection virtual bool isDynamic() const { return _params.isDynamic(); } virtual void encode(Data& data) const { return _params.encode(data); } virtual bool decode(const Data& encoded, size_t& offset_inout) { return _params.decode(encoded, offset_inout); } - virtual bool setValueJson(const std::string& value) { return false; } + virtual bool setValueJson([[maybe_unused]] const std::string& value) { return false; } virtual size_t getCount() const { return _params.getCount(); } }; diff --git a/src/Ethereum/AddressChecksum.cpp b/src/Ethereum/AddressChecksum.cpp index 004e8f8a47d..73e3c93d2df 100644 --- a/src/Ethereum/AddressChecksum.cpp +++ b/src/Ethereum/AddressChecksum.cpp @@ -18,7 +18,7 @@ std::string Ethereum::checksumed(const Address& address) { const auto hash = hex(Hash::keccak256(addressString)); std::string string = "0x"; - for (auto i = 0; i < std::min(addressString.size(), hash.size()); i += 1) { + for (auto i = 0ul; i < std::min(addressString.size(), hash.size()); i += 1) { const auto a = addressString[i]; const auto h = hash[i]; if (a >= '0' && a <= '9') { diff --git a/src/Ethereum/ContractCall.cpp b/src/Ethereum/ContractCall.cpp index 722ca4b68aa..0ae3a65db23 100644 --- a/src/Ethereum/ContractCall.cpp +++ b/src/Ethereum/ContractCall.cpp @@ -39,7 +39,7 @@ static vector getArrayValue(ParamSet& paramSet, const string& type, int static json buildInputs(ParamSet& paramSet, const json& registry); // forward -static json getTupleValue(ParamSet& paramSet, const string& type, int idx, const json& typeInfo) { +static json getTupleValue(ParamSet& paramSet, [[maybe_unused]] const string& type, int idx, const json& typeInfo) { shared_ptr param; paramSet.getParam(idx, param); auto paramTuple = dynamic_pointer_cast(param); @@ -57,7 +57,7 @@ static string getValue(ParamSet& paramSet, const string& type, int idx) { static json buildInputs(ParamSet& paramSet, const json& registry) { auto inputs = json::array(); - for (int i = 0; i < registry.size(); i++) { + for (auto i = 0ul; i < registry.size(); i++) { auto info = registry[i]; auto type = info["type"]; auto input = json{ @@ -65,13 +65,13 @@ static json buildInputs(ParamSet& paramSet, const json& registry) { {"type", type} }; if (boost::algorithm::ends_with(type.get(), "[]")) { - input["value"] = json(getArrayValue(paramSet, type, i)); + input["value"] = json(getArrayValue(paramSet, type, static_cast(i))); } else if (type == "tuple") { - input["components"] = getTupleValue(paramSet, type, i, info); + input["components"] = getTupleValue(paramSet, type, static_cast(i), info); } else if (type == "bool") { - input["value"] = getValue(paramSet, type, i) == "true" ? json(true) : json(false); + input["value"] = getValue(paramSet, type, static_cast(i)) == "true" ? json(true) : json(false); } else { - input["value"] = getValue(paramSet, type, i); + input["value"] = getValue(paramSet, type, static_cast(i)); } inputs.push_back(input); } diff --git a/src/Ethereum/Entry.cpp b/src/Ethereum/Entry.cpp index 1382f420d9d..e06875cdd48 100644 --- a/src/Ethereum/Entry.cpp +++ b/src/Ethereum/Entry.cpp @@ -15,33 +15,33 @@ using namespace TW::Ethereum; using namespace TW; using namespace std; -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::normalizeAddress(TWCoinType coin, const string& address) const { +string Entry::normalizeAddress([[maybe_unused]] TWCoinType coin, const string& address) const { // normalized with EIP55 checksum return Address(address).string(); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { const auto addr = Address(address); return {addr.bytes.begin(), addr.bytes.end()}; } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } -Data Entry::preImageHashes(TWCoinType coin, const Data& txInputData) const { +Data Entry::preImageHashes([[maybe_unused]] TWCoinType coin, const Data& txInputData) const { return txCompilerTemplate( txInputData, [](const auto& input, auto& output) { const auto transaction = Signer::build(input); @@ -53,7 +53,7 @@ Data Entry::preImageHashes(TWCoinType coin, const Data& txInputData) const { }); } -void Entry::compile(TWCoinType coin, const Data& txInputData, const std::vector& signatures, const std::vector& publicKeys, Data& dataOut) const { +void Entry::compile([[maybe_unused]] TWCoinType coin, const Data& txInputData, const std::vector& signatures, [[maybe_unused]] const std::vector& publicKeys, Data& dataOut) const { dataOut = txCompilerTemplate( txInputData, [&](const auto& input, auto& output) { if (signatures.size() != 1) { @@ -65,7 +65,7 @@ void Entry::compile(TWCoinType coin, const Data& txInputData, const std::vector< }); } -Data Entry::buildTransactionInput(TWCoinType coinType, const std::string& from, const std::string& to, const uint256_t& amount, const std::string& asset, const std::string& memo, const std::string& chainId) const { +Data Entry::buildTransactionInput([[maybe_unused]] TWCoinType coinType, [[maybe_unused]] const std::string& from, const std::string& to, const uint256_t& amount, [[maybe_unused]] const std::string& asset, [[maybe_unused]] const std::string& memo, const std::string& chainId) const { Proto::SigningInput input; auto chainIdData = store(uint256_t(1)); diff --git a/src/Ethereum/RLP.cpp b/src/Ethereum/RLP.cpp index 7098d75ff7a..5d794867f8d 100644 --- a/src/Ethereum/RLP.cpp +++ b/src/Ethereum/RLP.cpp @@ -83,7 +83,7 @@ uint64_t RLP::parseVarInt(size_t size, const Data& data, size_t index) { throw std::invalid_argument("multi-byte length must have no leading zero"); } uint64_t val = 0; - for (auto i = 0; i < size; ++i) { + for (auto i = 0ul; i < size; ++i) { val = val << 8; val += data[index + i]; } @@ -135,7 +135,7 @@ RLP::DecodedItem RLP::decode(const Data& input) { throw std::invalid_argument("single byte below 128 must be encoded as itself"); } - if (inputLen < (1 + strLen)) { + if (inputLen < (1ul + strLen)) { throw std::invalid_argument(std::string("invalid short string, length ") + std::to_string(strLen)); } item.decoded.push_back(subData(input, 1, strLen)); diff --git a/src/Ethereum/Transaction.cpp b/src/Ethereum/Transaction.cpp index f8e91580a44..6ab37bf09e4 100644 --- a/src/Ethereum/Transaction.cpp +++ b/src/Ethereum/Transaction.cpp @@ -66,7 +66,7 @@ Data TransactionNonTyped::serialize(const uint256_t chainID) const { return RLP::encodeList(encoded); } -Data TransactionNonTyped::encoded(const Signature& signature, const uint256_t chainID) const { +Data TransactionNonTyped::encoded(const Signature& signature, [[maybe_unused]] const uint256_t chainID) const { Data encoded; append(encoded, RLP::encode(nonce)); append(encoded, RLP::encode(gasPrice)); diff --git a/src/FIO/Entry.cpp b/src/FIO/Entry.cpp index 1caec6f5a68..2bb73f10a5e 100644 --- a/src/FIO/Entry.cpp +++ b/src/FIO/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/FIO/Signer.cpp b/src/FIO/Signer.cpp index f3a96ad0954..19b1803f624 100644 --- a/src/FIO/Signer.cpp +++ b/src/FIO/Signer.cpp @@ -56,7 +56,7 @@ bool Signer::verify(const PublicKey& pubKey, const Data& data, const Data& signa } // canonical check for FIO, both R and S lenght is 32 -int Signer::isCanonical(uint8_t by, uint8_t sig[64]) { +int Signer::isCanonical([[maybe_unused]] uint8_t by, uint8_t sig[64]) { return !(sig[0] & 0x80) && !(sig[0] == 0 && !(sig[1] & 0x80)) && !(sig[32] & 0x80) diff --git a/src/Filecoin/Address.cpp b/src/Filecoin/Address.cpp index ab464634e87..f4598d0f9b2 100644 --- a/src/Filecoin/Address.cpp +++ b/src/Filecoin/Address.cpp @@ -33,7 +33,7 @@ bool Address::isValid(const Data& data) { if (data.size() == 11 && data[10] > 0x01) { return false; } - int i; + std::size_t i; for (i = 1; i < data.size(); i++) { if ((data[i] & 0x80) == 0) { break; @@ -48,7 +48,7 @@ bool Address::isValid(const Data& data) { static bool isValidID(const std::string& string) { if (string.length() > 22) return false; - for (int i = 2; i < string.length(); i++) { + for (auto i = 2ul; i < string.length(); i++) { if (string[i] < '0' || string[i] > '9') { return false; } @@ -151,7 +151,7 @@ std::string Address::string() const { if (type() == Type::ID) { uint64_t id = 0; unsigned shift = 0; - for (int i = 1; i < bytes.size(); i++) { + for (auto i = 1ul; i < bytes.size(); i++) { if (bytes[i] <= SCHAR_MAX) { id |= static_cast(bytes[i]) << shift; break; diff --git a/src/Filecoin/Entry.cpp b/src/Filecoin/Entry.cpp index 39db5385ded..deeb0ff4a96 100644 --- a/src/Filecoin/Entry.cpp +++ b/src/Filecoin/Entry.cpp @@ -14,20 +14,20 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } diff --git a/src/Groestlcoin/Entry.cpp b/src/Groestlcoin/Entry.cpp index c5e77bf3b2f..c98d916b3da 100644 --- a/src/Groestlcoin/Entry.cpp +++ b/src/Groestlcoin/Entry.cpp @@ -13,19 +13,19 @@ using namespace TW::Groestlcoin; using namespace std; -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const { return TW::Bitcoin::SegwitAddress::isValid(address, hrp) || Address::isValid(address, {p2pkh, p2sh}); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TW::byte p2pkh, const char* hrp) const { return TW::Bitcoin::SegwitAddress(publicKey, hrp).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -void Entry::plan(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::plan([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { planTemplate(dataIn, dataOut); } diff --git a/src/Harmony/Entry.cpp b/src/Harmony/Entry.cpp index 408351678ff..ec8225be7cc 100644 --- a/src/Harmony/Entry.cpp +++ b/src/Harmony/Entry.cpp @@ -15,15 +15,15 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { Address addr; if (!Address::decode(address, addr)) { return Data(); @@ -31,10 +31,10 @@ Data Entry::addressToData(TWCoinType coin, const std::string& address) const { return addr.getKeyHash(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } diff --git a/src/Icon/Entry.cpp b/src/Icon/Entry.cpp index 2786ebd14b1..688d5d2b288 100644 --- a/src/Icon/Entry.cpp +++ b/src/Icon/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey, Icon::TypeAddress).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/IoTeX/Entry.cpp b/src/IoTeX/Entry.cpp index dc4c73dcc9d..bda6036643c 100644 --- a/src/IoTeX/Entry.cpp +++ b/src/IoTeX/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Keystore/EncryptionParameters.cpp b/src/Keystore/EncryptionParameters.cpp index 406474e638a..d5642ae28ee 100644 --- a/src/Keystore/EncryptionParameters.cpp +++ b/src/Keystore/EncryptionParameters.cpp @@ -136,7 +136,7 @@ Data EncryptedPayload::decrypt(const Data& password) const { auto __attribute__((unused)) result = aes_decrypt_key(derivedKey.data(), 16, &ctx); assert(result != EXIT_FAILURE); - for (auto i = 0; i < encrypted.size(); i += 16) { + for (auto i = 0ul; i < encrypted.size(); i += 16) { aes_cbc_decrypt(encrypted.data() + i, decrypted.data() + i, 16, iv.data(), &ctx); } } else { diff --git a/src/Keystore/StoredKey.cpp b/src/Keystore/StoredKey.cpp index af854073ffe..297eeb5443b 100644 --- a/src/Keystore/StoredKey.cpp +++ b/src/Keystore/StoredKey.cpp @@ -249,7 +249,7 @@ const PrivateKey StoredKey::privateKey(TWCoinType coin, const Data& password) { return privateKey(coin, TWDerivationDefault, password); } -const PrivateKey StoredKey::privateKey(TWCoinType coin, TWDerivation derivation, const Data& password) { +const PrivateKey StoredKey::privateKey(TWCoinType coin, [[maybe_unused]] TWDerivation derivation, const Data& password) { if (type == StoredKeyType::mnemonicPhrase) { const auto wallet = this->wallet(password); const Account& account = this->account(coin, derivation, wallet); diff --git a/src/Kusama/Entry.cpp b/src/Kusama/Entry.cpp index 3e96d1fdb08..e7a1002934d 100644 --- a/src/Kusama/Entry.cpp +++ b/src/Kusama/Entry.cpp @@ -15,19 +15,19 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { const auto addr = Address(address); return {addr.bytes.begin() + 1, addr.bytes.end()}; } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/NEAR/Entry.cpp b/src/NEAR/Entry.cpp index bb2da8a8f0c..e5b36a0b975 100644 --- a/src/NEAR/Entry.cpp +++ b/src/NEAR/Entry.cpp @@ -15,23 +15,23 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::normalizeAddress(TWCoinType coin, const string& address) const { +string Entry::normalizeAddress([[maybe_unused]] TWCoinType coin, const string& address) const { return Address(address).string(); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { const auto addr = Address(address); return {addr.bytes.begin(), addr.bytes.end()}; } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/NEO/Address.cpp b/src/NEO/Address.cpp index 229e61f27d4..e58b3f32208 100644 --- a/src/NEO/Address.cpp +++ b/src/NEO/Address.cpp @@ -22,7 +22,7 @@ bool Address::isValid(const std::string& string) { Address::Address() { Data keyHash; - for (int i = 0; i < Address::size; i++) { + for (auto i = 0ul; i < Address::size; i++) { keyHash.push_back(0); } std::copy(keyHash.data(), keyHash.data() + Address::size, bytes.begin()); diff --git a/src/NEO/Entry.cpp b/src/NEO/Entry.cpp index 9920ff2cc62..86e99889f30 100644 --- a/src/NEO/Entry.cpp +++ b/src/NEO/Entry.cpp @@ -13,23 +13,23 @@ using namespace TW::NEO; using namespace TW; using namespace std; -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const string& address, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] TW::byte p2sh, [[maybe_unused]] const char* hrp) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] const char* hrp) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { const auto addr = Address(address); return {addr.bytes.begin(), addr.bytes.end()}; } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -void Entry::plan(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::plan([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { planTemplate(dataIn, dataOut); } diff --git a/src/NEO/ReadData.cpp b/src/NEO/ReadData.cpp index e8f3487e4d8..f18a6312d5c 100644 --- a/src/NEO/ReadData.cpp +++ b/src/NEO/ReadData.cpp @@ -10,7 +10,7 @@ TW::Data TW::readBytes(const TW::Data& from, int max, int initial_pos) { - if (from.size() - initial_pos < max) { + if (from.size() - static_cast(initial_pos) < static_cast(max)) { throw std::invalid_argument("Data::Cannot read enough bytes!"); } return TW::Data(from.begin() + initial_pos, from.begin() + initial_pos + max); diff --git a/src/NEO/Transaction.h b/src/NEO/Transaction.h index 50a311e3d9a..7523995398c 100644 --- a/src/NEO/Transaction.h +++ b/src/NEO/Transaction.h @@ -33,7 +33,7 @@ class Transaction : public Serializable { bool operator==(const Transaction &other) const; - virtual int deserializeExclusiveData(const Data& data, int initial_pos = 0) { return initial_pos; } + virtual int deserializeExclusiveData([[maybe_unused]] const Data& data, int initial_pos = 0) { return initial_pos; } virtual Data serializeExclusiveData() const { return Data(); } Data getHash() const; diff --git a/src/NEO/TransactionAttribute.h b/src/NEO/TransactionAttribute.h index 8d8c5976c0f..87a4c62d764 100644 --- a/src/NEO/TransactionAttribute.h +++ b/src/NEO/TransactionAttribute.h @@ -25,7 +25,7 @@ class TransactionAttribute : public Serializable { } void deserialize(const Data& data, int initial_pos = 0) override { - if (data.size() < initial_pos + 1) { + if (static_cast(data.size()) < initial_pos + 1) { throw std::invalid_argument("Invalid data for deserialization"); } usage = (TransactionAttributeUsage) data[initial_pos]; @@ -58,4 +58,4 @@ class TransactionAttribute : public Serializable { } }; -} \ No newline at end of file +} diff --git a/src/NULS/BinaryCoding.h b/src/NULS/BinaryCoding.h index 077bf30cf85..3909b5c2d98 100644 --- a/src/NULS/BinaryCoding.h +++ b/src/NULS/BinaryCoding.h @@ -65,7 +65,7 @@ static inline Data makeTransactionSignature(PrivateKey& privateKey, Data& txHash Data transactionSignature = Data(); encodeVarInt(pubKey.bytes.size(), transactionSignature); std::copy(pubKey.bytes.begin(), pubKey.bytes.end(), std::back_inserter(transactionSignature)); - auto signature = privateKey.signAsDER(txHash, TWCurve::TWCurveSECP256k1); + auto signature = privateKey.signAsDER(txHash); encodeVarInt(signature.size(), transactionSignature); std::copy(signature.begin(), signature.end(), std::back_inserter(transactionSignature)); return transactionSignature; diff --git a/src/NULS/Entry.cpp b/src/NULS/Entry.cpp index 2dee29d9e31..56575ea447f 100644 --- a/src/NULS/Entry.cpp +++ b/src/NULS/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Nano/Entry.cpp b/src/Nano/Entry.cpp index 90b0a9ced38..2d276894700 100644 --- a/src/Nano/Entry.cpp +++ b/src/Nano/Entry.cpp @@ -15,23 +15,23 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { const auto addr = Address(address); return {addr.bytes.begin(), addr.bytes.end()}; } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } diff --git a/src/Nebulas/Entry.cpp b/src/Nebulas/Entry.cpp index a432250c5da..0daf8594ffd 100644 --- a/src/Nebulas/Entry.cpp +++ b/src/Nebulas/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Nimiq/Entry.cpp b/src/Nimiq/Entry.cpp index 9e795074477..53bad71eb77 100644 --- a/src/Nimiq/Entry.cpp +++ b/src/Nimiq/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Oasis/Entry.cpp b/src/Oasis/Entry.cpp index 44c756948a3..9768dd42bb4 100644 --- a/src/Oasis/Entry.cpp +++ b/src/Oasis/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Ontology/Asset.h b/src/Ontology/Asset.h index 123b6738ab7..1b1b0895094 100644 --- a/src/Ontology/Asset.h +++ b/src/Ontology/Asset.h @@ -19,18 +19,19 @@ namespace TW::Ontology { class Asset { - protected: +protected: const uint8_t txType = 0xD1; - public: +public: + virtual ~Asset() noexcept = default; virtual Data contractAddress() = 0; virtual Transaction decimals(uint32_t nonce) = 0; - virtual Transaction balanceOf(const Address &address, uint32_t nonce) = 0; + virtual Transaction balanceOf(const Address& address, uint32_t nonce) = 0; - virtual Transaction transfer(const Signer &from, const Address &to, uint64_t amount, - const Signer &payer, uint64_t gasPrice, uint64_t gasLimit, + virtual Transaction transfer(const Signer& from, const Address& to, uint64_t amount, + const Signer& payer, uint64_t gasPrice, uint64_t gasLimit, uint32_t nonce) = 0; }; } // namespace TW::Ontology diff --git a/src/Ontology/Entry.cpp b/src/Ontology/Entry.cpp index f0129ed1e08..0b6e1349c52 100644 --- a/src/Ontology/Entry.cpp +++ b/src/Ontology/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Polkadot/Entry.cpp b/src/Polkadot/Entry.cpp index d067d8a2f57..6e1185489d5 100644 --- a/src/Polkadot/Entry.cpp +++ b/src/Polkadot/Entry.cpp @@ -15,19 +15,19 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { const auto addr = Address(address); return {addr.bytes.begin() + 1, addr.bytes.end()}; } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/PrivateKey.cpp b/src/PrivateKey.cpp index 7a49cdfa7e4..df34b7e34f9 100644 --- a/src/PrivateKey.cpp +++ b/src/PrivateKey.cpp @@ -256,7 +256,7 @@ Data PrivateKey::sign(const Data& digest, TWCurve curve, int (*canonicalChecker) return result; } -Data PrivateKey::signAsDER(const Data& digest, TWCurve curve) const { +Data PrivateKey::signAsDER(const Data& digest) const { Data sig(64); bool success = ecdsa_sign_digest(&secp256k1, key().data(), digest.data(), sig.data(), nullptr, nullptr) == 0; diff --git a/src/PrivateKey.h b/src/PrivateKey.h index 94c1ea2d2c2..79108fec245 100644 --- a/src/PrivateKey.h +++ b/src/PrivateKey.h @@ -79,7 +79,7 @@ class PrivateKey { /// Signs a digest using the given ECDSA curve. The result is encoded with /// DER. - Data signAsDER(const Data& digest, TWCurve curve) const; + Data signAsDER(const Data& digest) const; /// Signs a digest using given ECDSA curve, returns Zilliqa schnorr signature Data signZilliqa(const Data& message) const; diff --git a/src/Result.h b/src/Result.h index 9e5a1f4c8f4..1ce611525a1 100644 --- a/src/Result.h +++ b/src/Result.h @@ -152,7 +152,7 @@ struct Result { public: /// Initializes a success result with a payload. - Result(Types::Success payload) : success_(true), error_() {} + Result([[maybe_unused]] Types::Success payload) : success_(true), error_() {} /// Initializes a failure result. Result(Types::Failure error) : success_(false), error_(error.val) {} diff --git a/src/Ripple/Entry.cpp b/src/Ripple/Entry.cpp index a2948f7073e..668154d70d8 100644 --- a/src/Ripple/Entry.cpp +++ b/src/Ripple/Entry.cpp @@ -15,14 +15,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address) || XAddress::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Ripple/Signer.cpp b/src/Ripple/Signer.cpp index 38b83c4d926..e19a385e098 100644 --- a/src/Ripple/Signer.cpp +++ b/src/Ripple/Signer.cpp @@ -52,5 +52,5 @@ void Signer::sign(const PrivateKey& privateKey, Transaction& transaction) const auto hash = Hash::sha512(unsignedTx); auto half = Data(hash.begin(), hash.begin() + 32); - transaction.signature = privateKey.signAsDER(half, TWCurveSECP256k1); + transaction.signature = privateKey.signAsDER(half); } diff --git a/src/Ronin/Entry.cpp b/src/Ronin/Entry.cpp index 008a717004a..61384ad8737 100644 --- a/src/Ronin/Entry.cpp +++ b/src/Ronin/Entry.cpp @@ -13,27 +13,27 @@ using namespace TW::Ronin; using namespace TW; using namespace std; -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::normalizeAddress(TWCoinType coin, const string& address) const { +string Entry::normalizeAddress([[maybe_unused]] TWCoinType coin, const string& address) const { return Address(address).string(); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { const auto addr = Address(address); return {addr.bytes.begin(), addr.bytes.end()}; } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Ethereum::Signer::signJSON(json, key); } diff --git a/src/Solana/Entry.cpp b/src/Solana/Entry.cpp index c76db86e157..ae9ef3e4e26 100644 --- a/src/Solana/Entry.cpp +++ b/src/Solana/Entry.cpp @@ -15,22 +15,22 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { return Address(address).vector(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } diff --git a/src/Solana/Program.cpp b/src/Solana/Program.cpp index cf7c602b987..0c54f1839d1 100644 --- a/src/Solana/Program.cpp +++ b/src/Solana/Program.cpp @@ -62,7 +62,7 @@ Address TokenProgram::defaultTokenAddress(const Address& mainAddress, const Addr * Based on solana code, find_program_address() * https://github.com/solana-labs/solana/blob/master/sdk/program/src/pubkey.rs#L193 */ -Address TokenProgram::findProgramAddress(const std::vector& seeds, const Address& programId) { +Address TokenProgram::findProgramAddress(const std::vector& seeds, [[maybe_unused]] const Address& programId) { Address result(Data(32)); // cycle through seeds for the rare case when result is not valid auto bumpSeed = Data{std::numeric_limits::max()}; diff --git a/src/Stellar/Entry.cpp b/src/Stellar/Entry.cpp index 0e1beb09ca3..87730c3cf18 100644 --- a/src/Stellar/Entry.cpp +++ b/src/Stellar/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Stellar/Signer.cpp b/src/Stellar/Signer.cpp index 1f36a90e3e2..fe3e4475ec4 100644 --- a/src/Stellar/Signer.cpp +++ b/src/Stellar/Signer.cpp @@ -176,7 +176,7 @@ void Signer::encodeAsset(const Proto::Asset& asset, Data& data) { } encode32BE(assetType, data); if (assetType > 0) { - for (auto i = 0; i < 4; ++i) { + for (auto i = 0ul; i < 4; ++i) { if (alphaUse.length() > i) { data.push_back(alphaUse[i]); } else { diff --git a/src/THORChain/Entry.cpp b/src/THORChain/Entry.cpp index 67faa8a23dc..1fb86e7cbff 100644 --- a/src/THORChain/Entry.cpp +++ b/src/THORChain/Entry.cpp @@ -14,13 +14,13 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { auto input = Cosmos::Proto::SigningInput(); input.ParseFromArray(dataIn.data(), (int)dataIn.size()); auto serializedOut = Signer::sign(input).SerializeAsString(); dataOut.insert(dataOut.end(), serializedOut.begin(), serializedOut.end()); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } diff --git a/src/THORChain/Swap.cpp b/src/THORChain/Swap.cpp index 8004b6662ff..fccacfb4f96 100644 --- a/src/THORChain/Swap.cpp +++ b/src/THORChain/Swap.cpp @@ -115,7 +115,7 @@ std::tuple Swap::build( } } -std::pair Swap::buildBitcoin(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& fromAddress, const std::string& toAddress, const std::string& vaultAddress, uint64_t amount, const std::string& memo, Data& out) { +std::pair Swap::buildBitcoin([[maybe_unused]] Chain toChain, [[maybe_unused]] const std::string& toSymbol, [[maybe_unused]] const std::string& toTokenId, const std::string& fromAddress, [[maybe_unused]] const std::string& toAddress, const std::string& vaultAddress, uint64_t amount, const std::string& memo, Data& out) { auto input = Bitcoin::Proto::SigningInput(); // Following fields must be set afterwards, before signing ... @@ -148,7 +148,7 @@ Data ethAddressStringToData(const std::string& asString) { return asData; } -std::pair Swap::buildEthereum(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& fromAddress, const std::string& toAddress, const std::string& vaultAddress, const std::string& routerAddress, uint64_t amount, const std::string& memo, Data& out) { +std::pair Swap::buildEthereum([[maybe_unused]] Chain toChain, [[maybe_unused]] const std::string& toSymbol, const std::string& toTokenId, [[maybe_unused]] const std::string& fromAddress, [[maybe_unused]] const std::string& toAddress, const std::string& vaultAddress, const std::string& routerAddress, uint64_t amount, const std::string& memo, Data& out) { auto input = Ethereum::Proto::SigningInput(); // some sanity check / address conversion @@ -192,7 +192,7 @@ std::pair Swap::buildEthereum(Chain toChain, const std::string return std::make_pair(0, ""); } -std::pair Swap::buildBinance(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& fromAddress, const std::string& toAddress, const std::string& vaultAddress, uint64_t amount, const std::string& memo, Data& out) { +std::pair Swap::buildBinance([[maybe_unused]] Chain toChain, [[maybe_unused]] const std::string& toSymbol, [[maybe_unused]] const std::string& toTokenId, const std::string& fromAddress, [[maybe_unused]] const std::string& toAddress, const std::string& vaultAddress, uint64_t amount, const std::string& memo, Data& out) { auto input = Binance::Proto::SigningInput(); // Following fields must be set afterwards, before signing ... diff --git a/src/Tezos/BinaryCoding.cpp b/src/Tezos/BinaryCoding.cpp index 35f2d9cee2b..a6824af9994 100644 --- a/src/Tezos/BinaryCoding.cpp +++ b/src/Tezos/BinaryCoding.cpp @@ -15,7 +15,7 @@ using namespace TW; -std::string base58ToHex(const std::string& string, size_t prefixLength, uint8_t* prefix) { +std::string base58ToHex(const std::string& string, size_t prefixLength) { const auto decoded = Base58::bitcoin.decodeCheck(string); if (decoded.size() < prefixLength) { return ""; @@ -40,11 +40,11 @@ PublicKey parsePublicKey(const std::string& publicKey) { PrivateKey parsePrivateKey(const std::string& privateKey) { const auto decoded = Base58::bitcoin.decodeCheck(privateKey); auto pk = Data(); - auto prefix_size = 4; + auto prefix_size = 4ul; if (decoded.size() != 32 + prefix_size) { throw std::invalid_argument("Invalid Public Key"); } append(pk, Data(decoded.begin() + prefix_size, decoded.end())); return PrivateKey(pk); -} \ No newline at end of file +} diff --git a/src/Tezos/BinaryCoding.h b/src/Tezos/BinaryCoding.h index 837a4e48b94..eb570166302 100644 --- a/src/Tezos/BinaryCoding.h +++ b/src/Tezos/BinaryCoding.h @@ -16,4 +16,4 @@ using namespace TW; PublicKey parsePublicKey(const std::string& publicKey); PrivateKey parsePrivateKey(const std::string& privateKey); -std::string base58ToHex(const std::string& data, size_t prefixLength, uint8_t* prefix); +std::string base58ToHex(const std::string& data, size_t prefixLength); diff --git a/src/Tezos/Entry.cpp b/src/Tezos/Entry.cpp index 2597237bb92..48b0568247c 100644 --- a/src/Tezos/Entry.cpp +++ b/src/Tezos/Entry.cpp @@ -14,18 +14,18 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } diff --git a/src/Tezos/Forging.cpp b/src/Tezos/Forging.cpp index b288b0935bf..52ad9a31fe6 100644 --- a/src/Tezos/Forging.cpp +++ b/src/Tezos/Forging.cpp @@ -55,7 +55,7 @@ Data forgePublicKey(PublicKey publicKey) { append(data, bytes); auto pk = Base58::bitcoin.encodeCheck(data); - auto decoded = "00" + base58ToHex(pk, 4, prefix.data()); + auto decoded = "00" + base58ToHex(pk, 4); return parse_hex(decoded); } diff --git a/src/Theta/Entry.cpp b/src/Theta/Entry.cpp index accd33e53f9..05875a67d7e 100644 --- a/src/Theta/Entry.cpp +++ b/src/Theta/Entry.cpp @@ -12,6 +12,6 @@ using namespace TW::Theta; using namespace std; -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Tron/Entry.cpp b/src/Tron/Entry.cpp index 0f69e92d865..5daceac1b61 100644 --- a/src/Tron/Entry.cpp +++ b/src/Tron/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/VeChain/Entry.cpp b/src/VeChain/Entry.cpp index cfb51da124f..c3c30c7f0ea 100644 --- a/src/VeChain/Entry.cpp +++ b/src/VeChain/Entry.cpp @@ -12,6 +12,6 @@ using namespace TW::VeChain; using namespace std; -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Waves/Entry.cpp b/src/Waves/Entry.cpp index 6162485901d..cb84f452cb7 100644 --- a/src/Waves/Entry.cpp +++ b/src/Waves/Entry.cpp @@ -14,14 +14,14 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Zcash/Entry.cpp b/src/Zcash/Entry.cpp index 6e1a5fb7ab1..9d5e39a1ca8 100644 --- a/src/Zcash/Entry.cpp +++ b/src/Zcash/Entry.cpp @@ -6,30 +6,30 @@ #include "Entry.h" -#include "TAddress.h" #include "Signer.h" +#include "TAddress.h" using namespace TW::Zcash; using namespace TW; using namespace std; -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const string& address, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] TW::byte p2sh, [[maybe_unused]] const char* hrp) const { return TAddress::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, [[maybe_unused]] const char* hrp) const { return TAddress(publicKey, p2pkh).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { const auto addr = TAddress(address); return {addr.bytes.begin() + 2, addr.bytes.end()}; } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -void Entry::plan(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::plan([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { planTemplate(dataIn, dataOut); } diff --git a/src/Zcash/Transaction.cpp b/src/Zcash/Transaction.cpp index b023b1284f0..7a61a33b2cb 100644 --- a/src/Zcash/Transaction.cpp +++ b/src/Zcash/Transaction.cpp @@ -181,7 +181,7 @@ void Transaction::encode(Data& data) const { Data Transaction::getSignatureHash(const Bitcoin::Script& scriptCode, size_t index, enum TWBitcoinSigHashType hashType, uint64_t amount, - Bitcoin::SignatureVersion version) const { + [[maybe_unused]] Bitcoin::SignatureVersion version) const { Data personalization; personalization.reserve(16); std::copy(sigHashPersonalization.begin(), sigHashPersonalization.begin() + 12, diff --git a/src/Zilliqa/AddressChecksum.cpp b/src/Zilliqa/AddressChecksum.cpp index 5332bee2363..3d741a5c4ae 100644 --- a/src/Zilliqa/AddressChecksum.cpp +++ b/src/Zilliqa/AddressChecksum.cpp @@ -23,7 +23,7 @@ std::string Zilliqa::checksum(const Data& bytes) { uint256_t v("0x" + hash); std::string string = ""; - for (auto i = 0; i < addressString.size(); i += 1) { + for (auto i = 0ul; i < addressString.size(); i += 1) { const auto a = addressString[i]; if (a >= '0' && a <= '9') { string.push_back(a); diff --git a/src/Zilliqa/Entry.cpp b/src/Zilliqa/Entry.cpp index 9333f1d7f3a..b005e72a5d9 100644 --- a/src/Zilliqa/Entry.cpp +++ b/src/Zilliqa/Entry.cpp @@ -15,15 +15,15 @@ using namespace std; // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } -Data Entry::addressToData(TWCoinType coin, const std::string& address) const { +Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { Address addr; if (!Address::decode(address, addr)) { return Data(); @@ -32,10 +32,10 @@ Data Entry::addressToData(TWCoinType coin, const std::string& address) const { return TW::data(checksum(addr.getKeyHash())); } -void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } diff --git a/src/interface/TWData.cpp b/src/interface/TWData.cpp index 561eb5dd9e8..b08b5e7cb94 100644 --- a/src/interface/TWData.cpp +++ b/src/interface/TWData.cpp @@ -71,7 +71,7 @@ void TWDataReplaceBytes(TWData *_Nonnull data, size_t start, size_t size, const void TWDataAppendBytes(TWData *_Nonnull data, const uint8_t *_Nonnull bytes, size_t size) { auto* v = const_cast(reinterpret_cast(data)); - for (auto i = 0; i < size; i += 1) + for (auto i = 0ul; i < size; i += 1) v->push_back(bytes[i]); } diff --git a/src/interface/TWPrivateKey.cpp b/src/interface/TWPrivateKey.cpp index 2440b47f0a7..2de3aaf3032 100644 --- a/src/interface/TWPrivateKey.cpp +++ b/src/interface/TWPrivateKey.cpp @@ -108,9 +108,9 @@ TWData *TWPrivateKeySign(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull dige } } -TWData *TWPrivateKeySignAsDER(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull digest, enum TWCurve curve) { +TWData *TWPrivateKeySignAsDER(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull digest, [[maybe_unused]] enum TWCurve curve) { auto& d = *reinterpret_cast(digest); - auto result = pk->impl.signAsDER(d, curve); + auto result = pk->impl.signAsDER(d); if (result.empty()) { return nullptr; } else { diff --git a/src/interface/TWTransactionCompiler.cpp b/src/interface/TWTransactionCompiler.cpp index 5e8e72adba1..bd8b6bcf051 100644 --- a/src/interface/TWTransactionCompiler.cpp +++ b/src/interface/TWTransactionCompiler.cpp @@ -34,7 +34,7 @@ TWData *_Nonnull TWTransactionCompilerBuildInput(enum TWCoinType coinType, TWStr std::vector createFromTWDataVector(const struct TWDataVector* _Nonnull dataVector) { std::vector ret; const auto n = TWDataVectorSize(dataVector); - for (auto i = 0; i < n; ++i) { + for (auto i = 0ul; i < n; ++i) { auto elem = TWDataVectorGet(dataVector, i); ret.push_back(*(static_cast(elem))); TWDataDelete(elem); diff --git a/swift/common-xcframework.yml b/swift/common-xcframework.yml index cf3bf1d6840..fead1284c2c 100644 --- a/swift/common-xcframework.yml +++ b/swift/common-xcframework.yml @@ -11,7 +11,7 @@ settings: ENABLE_BITCODE: YES HEADER_SEARCH_PATHS: $(SRCROOT)/wallet-core ${SRCROOT}/trezor-crypto/crypto SYSTEM_HEADER_SEARCH_PATHS: ${SRCROOT}/include ${SRCROOT}/../build/local/include ${SRCROOT}/trezor-crypto/include $(SRCROOT)/protobuf /usr/local/include /opt/homebrew/include - CLANG_CXX_LANGUAGE_STANDARD: c++17 + CLANG_CXX_LANGUAGE_STANDARD: c++20 GCC_WARN_64_TO_32_BIT_CONVERSION: NO targets: diff --git a/swift/project.yml b/swift/project.yml index 06541322c69..3d17eb60784 100644 --- a/swift/project.yml +++ b/swift/project.yml @@ -6,7 +6,7 @@ settings: base: HEADER_SEARCH_PATHS: $(SRCROOT)/wallet-core ${SRCROOT}/trezor-crypto/crypto SYSTEM_HEADER_SEARCH_PATHS: ${SRCROOT}/include ${SRCROOT}/../build/local/include ${SRCROOT}/trezor-crypto/include $(SRCROOT)/protobuf /usr/local/include /opt/homebrew/include - CLANG_CXX_LANGUAGE_STANDARD: c++17 + CLANG_CXX_LANGUAGE_STANDARD: c++20 SWIFT_VERSION: 5.1 IPHONEOS_DEPLOYMENT_TARGET: 13.0 configs: diff --git a/tests/Bech32Tests.cpp b/tests/Bech32Tests.cpp index adb569ec333..9c8b0b32baa 100644 --- a/tests/Bech32Tests.cpp +++ b/tests/Bech32Tests.cpp @@ -82,7 +82,7 @@ TEST(Bech32, decode) { auto res = Bech32::decode(td.encoded); if (!td.isValid && !td.isValidM) { EXPECT_EQ(std::get<0>(res), ""); - EXPECT_EQ(std::get<1>(res).size(), 0); + EXPECT_EQ(std::get<1>(res).size(), 0ul); } else { if (td.isValid) { EXPECT_EQ(std::get<2>(res), Bech32::ChecksumVariant::Bech32); diff --git a/tests/BinaryCodingTests.cpp b/tests/BinaryCodingTests.cpp index 138cbb7bea8..1627a90951c 100644 --- a/tests/BinaryCodingTests.cpp +++ b/tests/BinaryCodingTests.cpp @@ -47,10 +47,6 @@ TEST(BinaryCodingTests, varIntSize) { } } -void testEncodeVarInt(uint64_t input, const std::string& expectedEncoded) { - -} - TEST(BinaryCodingTests, encodeAndDecodeVarInt) { vector> tests = { {0, "00"}, diff --git a/tests/Bitcoin/BitcoinScriptTests.cpp b/tests/Bitcoin/BitcoinScriptTests.cpp index c9a7adc36df..cff0a76434f 100644 --- a/tests/Bitcoin/BitcoinScriptTests.cpp +++ b/tests/Bitcoin/BitcoinScriptTests.cpp @@ -61,7 +61,7 @@ TEST(BitcoinScript, PayToScriptHash) { EXPECT_EQ(hex(script.bytes), hex(PayToScriptHash.bytes)); EXPECT_EQ(PayToScriptHash.isPayToScriptHash(), true); - EXPECT_EQ(PayToScriptHash.bytes.size(), 23); + EXPECT_EQ(PayToScriptHash.bytes.size(), 23ul); EXPECT_EQ(PayToWitnessScriptHash.isPayToScriptHash(), false); EXPECT_EQ(PayToWitnessPublicKeyHash.isPayToScriptHash(), false); @@ -85,7 +85,7 @@ TEST(BitcoinScript, PayToWitnessScriptHash) { EXPECT_EQ(hex(script.bytes), hex(PayToWitnessScriptHash.bytes)); EXPECT_EQ(PayToWitnessScriptHash.isPayToWitnessScriptHash(), true); - EXPECT_EQ(PayToWitnessScriptHash.bytes.size(), 34); + EXPECT_EQ(PayToWitnessScriptHash.bytes.size(), 34ul); EXPECT_EQ(PayToScriptHash.isPayToWitnessScriptHash(), false); EXPECT_EQ(PayToWitnessPublicKeyHash.isPayToWitnessScriptHash(), false); @@ -109,7 +109,7 @@ TEST(BitcoinScript, PayToWitnessPublicKeyHash) { EXPECT_EQ(hex(script.bytes), hex(PayToWitnessPublicKeyHash.bytes)); EXPECT_EQ(PayToWitnessPublicKeyHash.isPayToWitnessPublicKeyHash(), true); - EXPECT_EQ(PayToWitnessPublicKeyHash.bytes.size(), 22); + EXPECT_EQ(PayToWitnessPublicKeyHash.bytes.size(), 22ul); EXPECT_EQ(PayToScriptHash.isPayToWitnessPublicKeyHash(), false); EXPECT_EQ(PayToWitnessScriptHash.isPayToWitnessPublicKeyHash(), false); @@ -160,21 +160,21 @@ TEST(BitcoinScript, GetScriptOp) { { size_t index = 0; uint8_t opcode; Data operand; EXPECT_EQ(Script(parse_hex("4f")).getScriptOp(index, opcode, operand), true); - EXPECT_EQ(index, 1); + EXPECT_EQ(index, 1ul); EXPECT_EQ(opcode, 0x4f); EXPECT_EQ(hex(operand), ""); } { size_t index = 0; uint8_t opcode; Data operand; EXPECT_EQ(Script(parse_hex("05" "0102030405")).getScriptOp(index, opcode, operand), true); - EXPECT_EQ(index, 6); + EXPECT_EQ(index, 6ul); EXPECT_EQ(opcode, 0x05); EXPECT_EQ(hex(operand), "0102030405"); } { // OP_PUSHDATA1 size_t index = 0; uint8_t opcode; Data operand; EXPECT_EQ(Script(parse_hex("4c" "05" "0102030405")).getScriptOp(index, opcode, operand), true); - EXPECT_EQ(index, 7); + EXPECT_EQ(index, 7ul); EXPECT_EQ(opcode, 0x4c); EXPECT_EQ(hex(operand), "0102030405"); } @@ -189,7 +189,7 @@ TEST(BitcoinScript, GetScriptOp) { { // OP_PUSHDATA2 size_t index = 0; uint8_t opcode; Data operand; EXPECT_EQ(Script(parse_hex("4d" "0500" "0102030405")).getScriptOp(index, opcode, operand), true); - EXPECT_EQ(index, 8); + EXPECT_EQ(index, 8ul); EXPECT_EQ(opcode, 0x4d); EXPECT_EQ(hex(operand), "0102030405"); } @@ -204,7 +204,7 @@ TEST(BitcoinScript, GetScriptOp) { { // OP_PUSHDATA4 size_t index = 0; uint8_t opcode; Data operand; EXPECT_EQ(Script(parse_hex("4e" "05000000" "0102030405")).getScriptOp(index, opcode, operand), true); - EXPECT_EQ(index, 10); + EXPECT_EQ(index, 10ul); EXPECT_EQ(opcode, 0x4e); EXPECT_EQ(hex(operand), "0102030405"); } @@ -239,7 +239,7 @@ TEST(BitcoinScript, MatchMultiSig) { // valid one key EXPECT_EQ(Script(parse_hex("51" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "51" "ae")).matchMultisig(keys, required), true); EXPECT_EQ(required, 1); - ASSERT_EQ(keys.size(), 1); + ASSERT_EQ(keys.size(), 1ul); EXPECT_EQ(hex(keys[0]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432"); EXPECT_EQ(Script(parse_hex("51" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "21" "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1" "51" "ae")).matchMultisig(keys, required), false); @@ -248,7 +248,7 @@ TEST(BitcoinScript, MatchMultiSig) { // valid two keys EXPECT_EQ(Script(parse_hex("52" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "21" "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1" "52" "ae")).matchMultisig(keys, required), true); EXPECT_EQ(required, 2); - ASSERT_EQ(keys.size(), 2); + ASSERT_EQ(keys.size(), 2ul); EXPECT_EQ(hex(keys[0]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432"); EXPECT_EQ(hex(keys[1]), "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1"); @@ -261,7 +261,7 @@ TEST(BitcoinScript, MatchMultiSig) { // valid one key, OP_PUSHDATA1 EXPECT_EQ(Script(parse_hex("514c" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "51" "ae")).matchMultisig(keys, required), true); EXPECT_EQ(required, 1); - ASSERT_EQ(keys.size(), 1); + ASSERT_EQ(keys.size(), 1ul); EXPECT_EQ(hex(keys[0]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432"); // OP_PUSHDATA2 @@ -273,7 +273,7 @@ TEST(BitcoinScript, MatchMultiSig) { // valid one key, OP_PUSHDATA2 EXPECT_EQ(Script(parse_hex("514d" "2100" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "51" "ae")).matchMultisig(keys, required), true); EXPECT_EQ(required, 1); - ASSERT_EQ(keys.size(), 1); + ASSERT_EQ(keys.size(), 1ul); EXPECT_EQ(hex(keys[0]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432"); // OP_PUSHDATA4 @@ -286,7 +286,7 @@ TEST(BitcoinScript, MatchMultiSig) { // valid one key, OP_PUSHDATA2 EXPECT_EQ(Script(parse_hex("514e" "21000000" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "51" "ae")).matchMultisig(keys, required), true); EXPECT_EQ(required, 1); - ASSERT_EQ(keys.size(), 1); + ASSERT_EQ(keys.size(), 1ul); EXPECT_EQ(hex(keys[0]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432"); // valid three keys, mixed @@ -296,7 +296,7 @@ TEST(BitcoinScript, MatchMultiSig) { "4e" "21000000" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "53" "ae")).matchMultisig(keys, required), true); EXPECT_EQ(required, 3); - ASSERT_EQ(keys.size(), 3); + ASSERT_EQ(keys.size(), 3ul); EXPECT_EQ(hex(keys[0]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432"); EXPECT_EQ(hex(keys[1]), "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1"); EXPECT_EQ(hex(keys[2]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432"); @@ -365,4 +365,4 @@ TEST(BitcoinTransactionSigner, PushAllEmpty) { Data res = SignatureBuilder::pushAll(input); EXPECT_EQ(hex(res), hex(expected)); } -} \ No newline at end of file +} diff --git a/tests/Bitcoin/InputSelectorTests.cpp b/tests/Bitcoin/InputSelectorTests.cpp index 4fb8355ad0c..ce8b32e5674 100644 --- a/tests/Bitcoin/InputSelectorTests.cpp +++ b/tests/Bitcoin/InputSelectorTests.cpp @@ -432,7 +432,7 @@ TEST(BitcoinInputSelector, ManyUtxos_900) { valueSum += val; } const uint64_t requestedAmount = valueSum / 8; - EXPECT_EQ(requestedAmount, 5'068'125); + EXPECT_EQ(requestedAmount, 5'068'125ul); auto utxos = buildTestUTXOs(values); auto selector = InputSelector(utxos); @@ -446,8 +446,8 @@ TEST(BitcoinInputSelector, ManyUtxos_900) { subset.push_back(val); subsetSum += val; } - EXPECT_EQ(subset.size(), 59); - EXPECT_EQ(subsetSum, 5'138'900); + EXPECT_EQ(subset.size(), 59ul); + EXPECT_EQ(subsetSum, 5'138'900ul); EXPECT_TRUE(verifySelectedUTXOs(selected, subset)); } @@ -462,7 +462,7 @@ TEST(BitcoinInputSelector, ManyUtxos_5000_simple) { valueSum += val; } const uint64_t requestedAmount = valueSum / 20; - EXPECT_EQ(requestedAmount, 62'512'500); + EXPECT_EQ(requestedAmount, 62'512'500ul); auto utxos = buildTestUTXOs(values); auto selector = InputSelector(utxos); @@ -476,8 +476,8 @@ TEST(BitcoinInputSelector, ManyUtxos_5000_simple) { subset.push_back(val); subsetSum += val; } - EXPECT_EQ(subset.size(), 1205); - EXPECT_EQ(subsetSum, 73'866'500); + EXPECT_EQ(subset.size(), 1205ul); + EXPECT_EQ(subsetSum, 73'866'500ul); EXPECT_TRUE(verifySelectedUTXOs(selected, subset)); } @@ -502,7 +502,7 @@ TEST(BitcoinInputSelector, ManyUtxos_MaxAmount_5000) { subset.push_back(val); subsetSum += val; } - EXPECT_EQ(subset.size(), 4990); - EXPECT_EQ(subsetSum, 1'250'244'500); + EXPECT_EQ(subset.size(), 4990ul); + EXPECT_EQ(subsetSum, 1'250'244'500ul); EXPECT_TRUE(verifySelectedUTXOs(selected, subset)); } diff --git a/tests/Bitcoin/SegwitAddressTests.cpp b/tests/Bitcoin/SegwitAddressTests.cpp index 7fadb980c0c..8bb0783ec01 100644 --- a/tests/Bitcoin/SegwitAddressTests.cpp +++ b/tests/Bitcoin/SegwitAddressTests.cpp @@ -128,7 +128,7 @@ bool case_insensitive_equal(const std::string& s1, const std::string& s2) { } TEST(SegwitAddress, ValidChecksum) { - for (auto i = 0; i < sizeof(valid_checksum) / sizeof(valid_checksum[0]); ++i) { + for (auto i = 0ul; i < sizeof(valid_checksum) / sizeof(valid_checksum[0]); ++i) { auto dec = Bech32::decode(valid_checksum[i]); ASSERT_FALSE(std::get<0>(dec).empty()); @@ -140,7 +140,7 @@ TEST(SegwitAddress, ValidChecksum) { } TEST(SegwitAddress, InvalidChecksum) { - for (auto i = 0; i < sizeof(invalid_checksum) / sizeof(invalid_checksum[0]); ++i) { + for (auto i = 0ul; i < sizeof(invalid_checksum) / sizeof(invalid_checksum[0]); ++i) { auto dec = Bech32::decode(invalid_checksum[i]); EXPECT_TRUE(std::get<0>(dec).empty() && std::get<1>(dec).empty()); } @@ -151,7 +151,7 @@ TEST(SegwitAddress, ValidAddress) { auto dec = SegwitAddress::decode(td.address); EXPECT_TRUE(std::get<2>(dec)) << "Valid address could not be decoded " << td.address; EXPECT_TRUE(std::get<0>(dec).witnessProgram.size() > 0) << "Empty decoded address data for " << td.address; - EXPECT_EQ(std::get<1>(dec).length(), 2); // hrp + EXPECT_EQ(std::get<1>(dec).length(), 2ul); // hrp // recode std::string recode = std::get<0>(dec).string(); @@ -164,14 +164,14 @@ TEST(SegwitAddress, ValidAddress) { } TEST(SegwitAddress, InvalidAddress) { - for (auto i = 0; i < invalid_address.size(); ++i) { + for (auto i = 0ul; i < invalid_address.size(); ++i) { auto dec = SegwitAddress::decode(invalid_address[i]); EXPECT_FALSE(std::get<2>(dec)) << "Invalid address reported as valid: " << invalid_address[i]; } } TEST(SegwitAddress, InvalidAddressEncoding) { - for (auto i = 0; i < sizeof(invalid_address_enc) / sizeof(invalid_address_enc[0]); ++i) { + for (auto i = 0ul; i < sizeof(invalid_address_enc) / sizeof(invalid_address_enc[0]); ++i) { auto address = SegwitAddress(invalid_address_enc[i].hrp, invalid_address_enc[i].version, Data(invalid_address_enc[i].program_length, 0)); std::string code = address.string(); EXPECT_TRUE(code.empty()); diff --git a/tests/Bitcoin/TWBitcoinScriptTests.cpp b/tests/Bitcoin/TWBitcoinScriptTests.cpp index 204ee624b90..e08a46dbea4 100644 --- a/tests/Bitcoin/TWBitcoinScriptTests.cpp +++ b/tests/Bitcoin/TWBitcoinScriptTests.cpp @@ -22,16 +22,16 @@ TEST(TWBitcoinScript, Create) { { auto script = WRAP(TWBitcoinScript, TWBitcoinScriptCreateWithData(data.get())); ASSERT_TRUE(script.get() != nullptr); - ASSERT_EQ(TWBitcoinScriptSize(script.get()), 23); + ASSERT_EQ(TWBitcoinScriptSize(script.get()), 23ul); } { auto script = WRAP(TWBitcoinScript, TWBitcoinScriptCreateWithBytes(TWDataBytes(data.get()), TWDataSize(data.get()))); ASSERT_TRUE(script.get() != nullptr); - ASSERT_EQ(TWBitcoinScriptSize(script.get()), 23); + ASSERT_EQ(TWBitcoinScriptSize(script.get()), 23ul); auto scriptCopy = WRAP(TWBitcoinScript, TWBitcoinScriptCreateCopy(script.get())); ASSERT_TRUE(scriptCopy.get() != nullptr); - ASSERT_EQ(TWBitcoinScriptSize(scriptCopy.get()), 23); + ASSERT_EQ(TWBitcoinScriptSize(scriptCopy.get()), 23ul); } } diff --git a/tests/Bitcoin/TWBitcoinSigningTests.cpp b/tests/Bitcoin/TWBitcoinSigningTests.cpp index 821272134de..e3f02115039 100644 --- a/tests/Bitcoin/TWBitcoinSigningTests.cpp +++ b/tests/Bitcoin/TWBitcoinSigningTests.cpp @@ -148,7 +148,7 @@ TEST(BitcoinSigning, EncodeP2WPKH) { Data unsignedData; unsignedTx.encode(unsignedData, Transaction::SegwitFormatMode::Segwit); - ASSERT_EQ(unsignedData.size(), 164); + ASSERT_EQ(unsignedData.size(), 164ul); ASSERT_EQ(hex(unsignedData), "01000000" // version "0001" // marker & flag @@ -318,7 +318,7 @@ TEST(BitcoinSigning, SignP2WPKH) { Data serialized; signedTx.encode(serialized); EXPECT_EQ(getEncodedTxSize(signedTx), (EncodedTxSize{195, 192, 193})); - EXPECT_EQ(serialized.size(), 192); + EXPECT_EQ(serialized.size(), 192ul); EXPECT_TRUE(validateEstimatedSize(signedTx, -1, 1)); ASSERT_EQ(hex(serialized), // printed using prettyPrintTransaction "01000000" // version @@ -335,7 +335,7 @@ TEST(BitcoinSigning, SignP2WPKH) { Data serialized; signedTx.encode(serialized, Transaction::SegwitFormatMode::NonSegwit); EXPECT_EQ(getEncodedTxSize(signedTx), (EncodedTxSize{195, 192, 193})); - EXPECT_EQ(serialized.size(), 192); + EXPECT_EQ(serialized.size(), 192ul); ASSERT_EQ(hex(serialized), // printed using prettyPrintTransaction "01000000" // version "01" // inputs @@ -626,7 +626,7 @@ TEST(BitcoinSigning, SignP2WSH_HashAnyoneCanPay) { Data serialized; signedTx.encode(serialized); - EXPECT_EQ(serialized.size(), 231); + EXPECT_EQ(serialized.size(), 231ul); EXPECT_EQ(getEncodedTxSize(signedTx), (EncodedTxSize{231, 119, 147})); EXPECT_TRUE(validateEstimatedSize(signedTx, -1, 1)); ASSERT_EQ(hex(serialized), // printed using prettyPrintTransaction @@ -1130,7 +1130,7 @@ TEST(BitcoinSigning, Plan_10input_MaxAmount) { EXPECT_EQ(getEncodedTxSize(signedTx), (EncodedTxSize{1529, 451, 721})); EXPECT_TRUE(validateEstimatedSize(signedTx, -1, 1)); - ASSERT_EQ(serialized.size(), 1529); + ASSERT_EQ(serialized.size(), 1529ul); } TEST(BitcoinSigning, Sign_LitecoinReal_a85f) { @@ -1297,7 +1297,7 @@ TEST(BitcoinSigning, Sign_ManyUtxos_400) { input.utxos.push_back(utxo); utxoSum += utxo.amount; } - EXPECT_EQ(utxoSum, 1'202'000); + EXPECT_EQ(utxoSum, 1'202'000ul); input.coinType = TWCoinTypeBitcoin; input.hashType = hashTypeForCoin(TWCoinTypeBitcoin); @@ -1318,8 +1318,8 @@ TEST(BitcoinSigning, Sign_ManyUtxos_400) { subset.push_back(val); subsetSum += val; } - EXPECT_EQ(subset.size(), 66); - EXPECT_EQ(subsetSum, 308'550); + EXPECT_EQ(subset.size(), 66ul); + EXPECT_EQ(subsetSum, 308'550ul); EXPECT_TRUE(verifyPlan(plan, subset, 300'000, 4'561)); // Extend input with keys, reuse plan, Sign @@ -1336,7 +1336,7 @@ TEST(BitcoinSigning, Sign_ManyUtxos_400) { Data serialized; signedTx.encode(serialized); - EXPECT_EQ(serialized.size(), 9871); + EXPECT_EQ(serialized.size(), 9871ul); } TEST(BitcoinSigning, Sign_ManyUtxos_2000) { @@ -1366,7 +1366,7 @@ TEST(BitcoinSigning, Sign_ManyUtxos_2000) { input.utxos.push_back(utxo); utxoSum += utxo.amount; } - EXPECT_EQ(utxoSum, 22'010'000); + EXPECT_EQ(utxoSum, 22'010'000ul); input.coinType = TWCoinTypeBitcoin; input.hashType = hashTypeForCoin(TWCoinTypeBitcoin); @@ -1387,8 +1387,8 @@ TEST(BitcoinSigning, Sign_ManyUtxos_2000) { subset.push_back(val); subsetSum += val; } - EXPECT_EQ(subset.size(), 601); - EXPECT_EQ(subsetSum, 2'410'010); + EXPECT_EQ(subset.size(), 601ul); + EXPECT_EQ(subsetSum, 2'410'010ul); EXPECT_TRUE(verifyPlan(plan, subset, 2'000'000, 40'943)); // Extend input with keys, reuse plan, Sign @@ -1405,7 +1405,7 @@ TEST(BitcoinSigning, Sign_ManyUtxos_2000) { Data serialized; signedTx.encode(serialized); - EXPECT_EQ(serialized.size(), 89'339); + EXPECT_EQ(serialized.size(), 89'339ul); } TEST(BitcoinSigning, EncodeThreeOutput) { @@ -1435,7 +1435,7 @@ TEST(BitcoinSigning, EncodeThreeOutput) { Data unsignedData; unsignedTx.encode(unsignedData, Transaction::SegwitFormatMode::Segwit); - EXPECT_EQ(unsignedData.size(), 147); + EXPECT_EQ(unsignedData.size(), 147ul); EXPECT_EQ(hex(unsignedData), // printed using prettyPrintTransaction "01000000" // version "0001" // marker & flag @@ -1467,7 +1467,7 @@ TEST(BitcoinSigning, EncodeThreeOutput) { auto hashType = TWBitcoinSigHashType::TWBitcoinSigHashTypeAll; Data sighash = unsignedTx.getSignatureHash(redeemScript0, unsignedTx.inputs[0].previousOutput.index, hashType, utxo0Amount, static_cast(unsignedTx.version)); - auto sig = privkey.signAsDER(sighash, TWCurveSECP256k1); + auto sig = privkey.signAsDER(sighash); ASSERT_FALSE(sig.empty()); sig.push_back(hashType); EXPECT_EQ(hex(sig), "30450221008d88197a37ffcb51ecacc7e826aa588cb1068a107a82373c4b54ec42318a395c02204abbf5408504614d8f943d67e7873506c575e85a5e1bd92a02cd345e5192a82701"); @@ -1478,7 +1478,7 @@ TEST(BitcoinSigning, EncodeThreeOutput) { unsignedData.clear(); unsignedTx.encode(unsignedData, Transaction::SegwitFormatMode::Segwit); - EXPECT_EQ(unsignedData.size(), 254); + EXPECT_EQ(unsignedData.size(), 254ul); // https://blockchair.com/litecoin/transaction/9e3fe98565a904d2da5ec1b3ba9d2b3376dfc074f43d113ce1caac01bf51b34c EXPECT_EQ(hex(unsignedData), // printed using prettyPrintTransaction "01000000" // version @@ -1549,7 +1549,7 @@ TEST(BitcoinSigning, RedeemExtendedPubkeyUTXO) { Data encoded; signedTx.encode(encoded); - EXPECT_EQ(encoded.size(), 402); + EXPECT_EQ(encoded.size(), 402ul); } TEST(BitcoinSigning, SignP2TR_5df51e) { @@ -1653,7 +1653,7 @@ TEST(BitcoinSigning, Build_OpReturn_THORChainSwap_eb4c) { Data unsignedData; unsignedTx.encode(unsignedData, Transaction::SegwitFormatMode::Segwit); - EXPECT_EQ(unsignedData.size(), 186); + EXPECT_EQ(unsignedData.size(), 186ul); EXPECT_EQ(hex(unsignedData), // printed using prettyPrintTransaction "02000000" // version "0001" // marker & flag @@ -1678,7 +1678,7 @@ TEST(BitcoinSigning, Build_OpReturn_THORChainSwap_eb4c) { unsignedData.clear(); unsignedTx.encode(unsignedData, Transaction::SegwitFormatMode::Segwit); - EXPECT_EQ(unsignedData.size(), 293); + EXPECT_EQ(unsignedData.size(), 293ul); // https://blockchair.com/bitcoin/transaction/eb4c1b064bfaf593d7cc6a5c73b75f932ffefe12a0478acf5a7e3145476683fc EXPECT_EQ(hex(unsignedData), "02000000000101354ecf19c1f050e419a9d3b4290e683e5e814a844cec6436de391a296029b8300100000000ffffffff03e0930400000000001600143729d3a1" @@ -1729,7 +1729,7 @@ TEST(BitcoinSigning, Sign_OpReturn_THORChainSwap) { // test plan (but do not reuse plan result) auto plan = TransactionBuilder::plan(input); EXPECT_TRUE(verifyPlan(plan, {342101}, 300000, 26586)); - EXPECT_EQ(plan.outputOpReturn.size(), 59); + EXPECT_EQ(plan.outputOpReturn.size(), 59ul); } // Sign diff --git a/tests/Bitcoin/TWBitcoinTransactionTests.cpp b/tests/Bitcoin/TWBitcoinTransactionTests.cpp index 4086289a438..c0654b789da 100644 --- a/tests/Bitcoin/TWBitcoinTransactionTests.cpp +++ b/tests/Bitcoin/TWBitcoinTransactionTests.cpp @@ -35,7 +35,7 @@ TEST(BitcoinTransaction, Encode) { Data unsignedData; transaction.encode(unsignedData, Transaction::SegwitFormatMode::NonSegwit); - ASSERT_EQ(unsignedData.size(), 201); + ASSERT_EQ(unsignedData.size(), 201ul); ASSERT_EQ(hex(unsignedData), "02000000035897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f0000000000ffffffffbf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c1200000000ffffffff22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc0100000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d717000000001976a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac00000000"); } diff --git a/tests/Bitcoin/TransactionPlanTests.cpp b/tests/Bitcoin/TransactionPlanTests.cpp index cf4d6b37671..955486e22f8 100644 --- a/tests/Bitcoin/TransactionPlanTests.cpp +++ b/tests/Bitcoin/TransactionPlanTests.cpp @@ -532,7 +532,7 @@ TEST(TransactionPlan, ManyUtxosNonmax_400) { valueSum += val; } const uint64_t requestedAmount = valueSum / 8; - EXPECT_EQ(requestedAmount, 1'002'500); + EXPECT_EQ(requestedAmount, 1'002'500ul); auto utxos = buildTestUTXOs(values); auto sigingInput = buildSigningInput(requestedAmount, byteFee, utxos, false, TWCoinTypeBitcoin); @@ -547,8 +547,8 @@ TEST(TransactionPlan, ManyUtxosNonmax_400) { subset.push_back(val); subsetSum += val; } - EXPECT_EQ(subset.size(), 27); - EXPECT_EQ(subsetSum, 1'044'900); + EXPECT_EQ(subset.size(), 27ul); + EXPECT_EQ(subsetSum, 1'044'900ul); EXPECT_TRUE(verifyPlan(txPlan, subset, requestedAmount, 19'150)); } @@ -563,7 +563,7 @@ TEST(TransactionPlan, ManyUtxosNonmax_5000_simple) { valueSum += val; } const uint64_t requestedAmount = valueSum / 20; - EXPECT_EQ(requestedAmount, 62'512'500); + EXPECT_EQ(requestedAmount, 62'512'500ul); // Use Ravencoin, because of faster non-segwit estimation, and one of the original issues was with this coin. auto utxos = buildTestUTXOs(values); @@ -579,8 +579,8 @@ TEST(TransactionPlan, ManyUtxosNonmax_5000_simple) { subset.push_back(val); subsetSum += val; } - EXPECT_EQ(subset.size(), 1220); - EXPECT_EQ(subsetSum, 76'189'000); + EXPECT_EQ(subset.size(), 1220ul); + EXPECT_EQ(subsetSum, 76'189'000ul); EXPECT_TRUE(verifyPlan(txPlan, subset, requestedAmount, 1'806'380)); } @@ -612,10 +612,10 @@ TEST(TransactionPlan, ManyUtxosMax_400) { filteredValueSum += val; } } - EXPECT_EQ(valueSum, 8'020'000); - EXPECT_EQ(dustLimit, 1480); - EXPECT_EQ(filteredValues.size(), 386); - EXPECT_EQ(filteredValueSum, 80'09'500); + EXPECT_EQ(valueSum, 8'020'000ul); + EXPECT_EQ(dustLimit, 1480ul); + EXPECT_EQ(filteredValues.size(), 386ul); + EXPECT_EQ(filteredValueSum, 80'09'500ul); EXPECT_TRUE(verifyPlan(txPlan, filteredValues, 7'437'780, 571'720)); } @@ -647,10 +647,10 @@ TEST(TransactionPlan, ManyUtxosMax_5000_simple) { filteredValueSum += val; } } - EXPECT_EQ(valueSum, 1'250'250'000); - EXPECT_EQ(dustLimit, 1500); - EXPECT_EQ(filteredValues.size(), 3000); - EXPECT_EQ(filteredValueSum, 454'350'000); + EXPECT_EQ(valueSum, 1'250'250'000ul); + EXPECT_EQ(dustLimit, 1500ul); + EXPECT_EQ(filteredValues.size(), 3000ul); + EXPECT_EQ(filteredValueSum, 454'350'000ul); EXPECT_TRUE(verifyPlan(txPlan, filteredValues, 449'909'560, 4'440'440)); } @@ -681,7 +681,7 @@ TEST(TransactionPlan, OpReturn) { auto txPlan = TransactionBuilder::plan(signingInput); EXPECT_TRUE(verifyPlan(txPlan, {342101}, 300000, 205 * byteFee)); - EXPECT_EQ(txPlan.outputOpReturn.size(), 59); + EXPECT_EQ(txPlan.outputOpReturn.size(), 59ul); EXPECT_EQ(hex(txPlan.outputOpReturn), "535741503a54484f522e52554e453a74686f72317470657263616d6b6b7865633071306a6b366c74646e6c7176737732396775617038776d636c3a"); auto& feeCalculator = getFeeCalculator(TWCoinTypeBitcoin); diff --git a/tests/Bitcoin/TxComparisonHelper.cpp b/tests/Bitcoin/TxComparisonHelper.cpp index e84e87c4998..3d617ee510b 100644 --- a/tests/Bitcoin/TxComparisonHelper.cpp +++ b/tests/Bitcoin/TxComparisonHelper.cpp @@ -78,7 +78,7 @@ bool verifySelectedUTXOs(const UTXOs& selected, const std::vector& expe std::cerr << "Wrong number of selected UTXOs, " << selected.size() << " vs. " << expectedAmounts.size() << std::endl; } int errorCount = 0; - for (auto i = 0; i < selected.size() && i < expectedAmounts.size(); ++i) { + for (auto i = 0ul; i < selected.size() && i < expectedAmounts.size(); ++i) { if (expectedAmounts[i] != selected[i].amount) { ret = false; ++errorCount; @@ -104,7 +104,7 @@ bool verifyPlan(const TransactionPlan& plan, const std::vector& utxoAmo std::cerr << "Mismatch in fee, act " << plan.fee << ", exp " << fee << std::endl; } int64_t sumExpectedUTXOs = 0; - for (auto i = 0; i < utxoAmounts.size(); ++i) { + for (auto i = 0ul; i < utxoAmounts.size(); ++i) { sumExpectedUTXOs += utxoAmounts[i]; } if (plan.availableAmount != sumExpectedUTXOs) { @@ -156,7 +156,7 @@ EncodedTxSize getEncodedTxSize(const Transaction& tx) { Data data; tx.encodeWitness(data); witnessSize = data.size(); - assert(size.segwit - size.nonSegwit == 2 + witnessSize); + assert(size.segwit - size.nonSegwit == 2ul + witnessSize); } // compute virtual size: 3/4 of (smaller) non-segwit + 1/4 of segwit size uint64_t sum = size.nonSegwit * 3 + size.segwit; diff --git a/tests/BitcoinCash/TWBitcoinCashTests.cpp b/tests/BitcoinCash/TWBitcoinCashTests.cpp index 3109f631b20..80b204de8df 100644 --- a/tests/BitcoinCash/TWBitcoinCashTests.cpp +++ b/tests/BitcoinCash/TWBitcoinCashTests.cpp @@ -151,7 +151,7 @@ TEST(BitcoinCash, SignTransaction) { EXPECT_EQ(output.transaction().outputs_size(), 2); EXPECT_EQ(output.transaction().outputs(0).value(), amount); EXPECT_EQ(output.transaction().outputs(1).value(), 4325); - EXPECT_EQ(output.encoded().length(), 226); + EXPECT_EQ(output.encoded().length(), 226ul); ASSERT_EQ(hex(output.encoded()), "01000000" "01" diff --git a/tests/BitcoinGold/TWSignerTests.cpp b/tests/BitcoinGold/TWSignerTests.cpp index b568ea08916..31f9a6f8fc5 100644 --- a/tests/BitcoinGold/TWSignerTests.cpp +++ b/tests/BitcoinGold/TWSignerTests.cpp @@ -83,7 +83,7 @@ TEST(TWBitcoinGoldSigner, SignTransaction) { Data serialized; signedTx.encode(serialized); // BitcoinGold Mainnet: https://btg2.trezor.io/tx/db26faec66d070045df0da56140349beb5a12bd14bca12b162fded8f84d18afa - EXPECT_EQ(serialized.size(), 222); + EXPECT_EQ(serialized.size(), 222ul); ASSERT_EQ(hex(serialized), "01000000" "0001" diff --git a/tests/Cardano/AddressTests.cpp b/tests/Cardano/AddressTests.cpp index a7cde0c7d60..a0d060b5687 100644 --- a/tests/Cardano/AddressTests.cpp +++ b/tests/Cardano/AddressTests.cpp @@ -344,14 +344,14 @@ TEST(CardanoAddress, PrivateKeyExtended) { dummyKey, dummyKey, dummyKey ); auto publicKeyExt = privateKeyExt.getPublicKey(TWPublicKeyTypeED25519Cardano); - ASSERT_EQ(128, publicKeyExt.bytes.size()); + ASSERT_EQ(128ul, publicKeyExt.bytes.size()); // Non-extended: both are 32 bytes. auto privateKeyNonext = PrivateKey( parse_hex("b0884d248cb301edd1b34cf626ba6d880bb3ae8fd91b4696446999dc4f0b5744") ); auto publicKeyNonext = privateKeyNonext.getPublicKey(TWPublicKeyTypeED25519); - ASSERT_EQ(32, publicKeyNonext.bytes.size()); + ASSERT_EQ(32ul, publicKeyNonext.bytes.size()); } TEST(CardanoAddress, FromStringNegativeInvalidString) { diff --git a/tests/Cardano/SigningTests.cpp b/tests/Cardano/SigningTests.cpp index 34edb07ca6b..f16820f87d1 100644 --- a/tests/Cardano/SigningTests.cpp +++ b/tests/Cardano/SigningTests.cpp @@ -31,37 +31,37 @@ const auto sundaeTokenPolicy = "9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4 TEST(CardanoSigning, SelectInputs) { const auto inputs = std::vector({ - TxInput{{parse_hex("0001"), 0}, "ad01", 700}, - TxInput{{parse_hex("0002"), 1}, "ad02", 900}, - TxInput{{parse_hex("0003"), 2}, "ad03", 300}, - TxInput{{parse_hex("0004"), 3}, "ad04", 600}, + TxInput{{parse_hex("0001"), 0}, "ad01", 700, {}}, + TxInput{{parse_hex("0002"), 1}, "ad02", 900, {}}, + TxInput{{parse_hex("0003"), 2}, "ad03", 300, {}}, + TxInput{{parse_hex("0004"), 3}, "ad04", 600, {}}, }); { // 2 const auto s1 = Signer::selectInputsWithTokens(inputs, 1500, {}); - ASSERT_EQ(s1.size(), 2); - EXPECT_EQ(s1[0].amount, 900); - EXPECT_EQ(s1[1].amount, 700); + ASSERT_EQ(s1.size(), 2ul); + EXPECT_EQ(s1[0].amount, 900ul); + EXPECT_EQ(s1[1].amount, 700ul); } { // all const auto s1 = Signer::selectInputsWithTokens(inputs, 10000, {}); - ASSERT_EQ(s1.size(), 4); - EXPECT_EQ(s1[0].amount, 900); - EXPECT_EQ(s1[1].amount, 700); - EXPECT_EQ(s1[2].amount, 600); - EXPECT_EQ(s1[3].amount, 300); + ASSERT_EQ(s1.size(), 4ul); + EXPECT_EQ(s1[0].amount, 900ul); + EXPECT_EQ(s1[1].amount, 700ul); + EXPECT_EQ(s1[2].amount, 600ul); + EXPECT_EQ(s1[3].amount, 300ul); } { // 3 const auto s1 = Signer::selectInputsWithTokens(inputs, 2000, {}); - ASSERT_EQ(s1.size(), 3); + ASSERT_EQ(s1.size(), 3ul); } { // 1 const auto s1 = Signer::selectInputsWithTokens(inputs, 500, {}); - ASSERT_EQ(s1.size(), 1); + ASSERT_EQ(s1.size(), 1ul); } { // at least 0 is returned const auto s1 = Signer::selectInputsWithTokens(inputs, 0, {}); - ASSERT_EQ(s1.size(), 1); + ASSERT_EQ(s1.size(), 1ul); } } @@ -107,11 +107,11 @@ TEST(CardanoSigning, Plan) { { auto signer = Signer(input); const auto plan = signer.doPlan(); - EXPECT_EQ(plan.utxos.size(), 2); - EXPECT_EQ(plan.availableAmount, 8000000); - EXPECT_EQ(plan.amount, 7000000); - EXPECT_EQ(plan.fee, 170196); - EXPECT_EQ(plan.change, 829804); + EXPECT_EQ(plan.utxos.size(), 2ul); + EXPECT_EQ(plan.availableAmount, 8000000ul); + EXPECT_EQ(plan.amount, 7000000ul); + EXPECT_EQ(plan.fee, 170196ul); + EXPECT_EQ(plan.change, 829804ul); EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); EXPECT_EQ(plan.error, Common::Proto::OK); } @@ -119,20 +119,20 @@ TEST(CardanoSigning, Plan) { input.mutable_transfer_message()->set_amount(1); auto signer = Signer(input); const auto plan = signer.doPlan(); - EXPECT_EQ(plan.utxos.size(), 1); - EXPECT_EQ(plan.availableAmount, 6500000); - EXPECT_EQ(plan.amount, 1); - EXPECT_EQ(plan.fee, 168435); + EXPECT_EQ(plan.utxos.size(), 1ul); + EXPECT_EQ(plan.availableAmount, 6500000ul); + EXPECT_EQ(plan.amount, 1ul); + EXPECT_EQ(plan.fee, 168435ul); EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); } { // small target amount input.mutable_transfer_message()->set_amount(2000000); auto signer = Signer(input); const auto plan = signer.doPlan(); - EXPECT_EQ(plan.utxos.size(), 1); - EXPECT_EQ(plan.availableAmount, 6500000); - EXPECT_EQ(plan.amount, 2000000); - EXPECT_EQ(plan.fee, 168611); + EXPECT_EQ(plan.utxos.size(), 1ul); + EXPECT_EQ(plan.availableAmount, 6500000ul); + EXPECT_EQ(plan.amount, 2000000ul); + EXPECT_EQ(plan.fee, 168611ul); EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); } { // small target amount requested, but max amount @@ -140,21 +140,21 @@ TEST(CardanoSigning, Plan) { input.mutable_transfer_message()->set_use_max_amount(true); auto signer = Signer(input); const auto plan = signer.doPlan(); - EXPECT_EQ(plan.utxos.size(), 2); - EXPECT_EQ(plan.availableAmount, 8000000); - EXPECT_EQ(plan.amount, 7832667); - EXPECT_EQ(plan.fee, 167333); + EXPECT_EQ(plan.utxos.size(), 2ul); + EXPECT_EQ(plan.availableAmount, 8000000ul); + EXPECT_EQ(plan.amount, 7832667ul); + EXPECT_EQ(plan.fee, 167333ul); EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); } } TEST(CardanoSigning, PlanForceFee) { - auto requestedAmount = 6500000; - auto availableAmount = 8000000; + auto requestedAmount = 6500000ul; + auto availableAmount = 8000000ul; auto input = createSampleInput(requestedAmount); { - auto fee = 170147; + auto fee = 170147ul; input.mutable_transfer_message()->set_force_fee(fee); auto signer = Signer(input); const auto plan = signer.doPlan(); @@ -166,7 +166,7 @@ TEST(CardanoSigning, PlanForceFee) { EXPECT_EQ(plan.error, Common::Proto::OK); } { // tiny fee - auto fee = 100; + auto fee = 100ul; input.mutable_transfer_message()->set_force_fee(fee); auto signer = Signer(input); const auto plan = signer.doPlan(); @@ -177,7 +177,7 @@ TEST(CardanoSigning, PlanForceFee) { EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); } { // large fee - auto fee = 1200000; + auto fee = 1200000ul; input.mutable_transfer_message()->set_force_fee(fee); auto signer = Signer(input); const auto plan = signer.doPlan(); @@ -188,26 +188,26 @@ TEST(CardanoSigning, PlanForceFee) { EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); } { // very large fee, larger than possible, truncated - auto fee = 3000000; + auto fee = 3000000ul; input.mutable_transfer_message()->set_force_fee(fee); auto signer = Signer(input); const auto plan = signer.doPlan(); EXPECT_EQ(plan.availableAmount, availableAmount); EXPECT_EQ(plan.amount, requestedAmount); - EXPECT_EQ(plan.fee, 1500000); - EXPECT_EQ(plan.change, 0); + EXPECT_EQ(plan.fee, 1500000ul); + EXPECT_EQ(plan.change, 0ul); EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); } { // force fee and max amount: fee is used, amount is max, change 0 - auto fee = 160000; + auto fee = 160000ul; input.mutable_transfer_message()->set_force_fee(fee); input.mutable_transfer_message()->set_use_max_amount(true); auto signer = Signer(input); const auto plan = signer.doPlan(); EXPECT_EQ(plan.availableAmount, availableAmount); - EXPECT_EQ(plan.amount, 7840000); + EXPECT_EQ(plan.amount, 7840000ul); EXPECT_EQ(plan.fee, fee); - EXPECT_EQ(plan.change, 0); + EXPECT_EQ(plan.change, 0ul); EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); } } @@ -218,11 +218,11 @@ TEST(CardanoSigning, PlanMissingPrivateKey) { auto signer = Signer(input); const auto plan = signer.doPlan(); - EXPECT_EQ(plan.utxos.size(), 2); - EXPECT_EQ(plan.availableAmount, 8000000); - EXPECT_EQ(plan.amount, 7000000); - EXPECT_EQ(plan.fee, 170196); - EXPECT_EQ(plan.change, 829804); + EXPECT_EQ(plan.utxos.size(), 2ul); + EXPECT_EQ(plan.availableAmount, 8000000ul); + EXPECT_EQ(plan.amount, 7000000ul); + EXPECT_EQ(plan.fee, 170196ul); + EXPECT_EQ(plan.change, 829804ul); EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); EXPECT_EQ(plan.error, Common::Proto::OK); } @@ -244,7 +244,7 @@ TEST(CardanoSigning, SignTransfer1) { const auto decode = Cbor::Decode(encoded); ASSERT_TRUE(decode.isValid()); EXPECT_EQ(decode.dumpToString(), "[{0: [[h\"554f2fd942a23d06835d26bbd78f0106fa94c8a551114a0bef81927f66467af0\", 0], [h\"f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e767\", 1]], 1: [[h\"01558dd902616f5cd01edcc62870cb4748c45403f1228218bee5b628b526f0ca9e7a2c04d548fbd6ce86f358be139fe680652536437d1d6fd5\", 7000000], [h\"01df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\", 829804]], 2: 170196, 3: 53333333}, {0: [[h\"6d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df290\", h\"7cf591599852b5f5e007fdc241062405c47e519266c0d884b0767c1d4f5eacce00db035998e53ed10ca4ba5ce4aac8693798089717ce6cf4415f345cc764200e\"]]}, null]"); - EXPECT_EQ(decode.getArrayElements().size(), 3); + EXPECT_EQ(decode.getArrayElements().size(), 3ul); } } @@ -257,13 +257,13 @@ TEST(CardanoSigning, PlanAndSignTransfer1) { auto signer = Signer(input); const auto plan = signer.doPlan(); - EXPECT_EQ(plan.availableAmount, 8000000); + EXPECT_EQ(plan.availableAmount, 8000000ul); EXPECT_EQ(plan.amount, amount); - EXPECT_EQ(plan.fee, 170196); + EXPECT_EQ(plan.fee, 170196ul); EXPECT_EQ(plan.change, 8000000 - amount - 170196); - ASSERT_EQ(plan.utxos.size(), 2); - EXPECT_EQ(plan.utxos[0].amount, 6500000); - EXPECT_EQ(plan.utxos[1].amount, 1500000); + ASSERT_EQ(plan.utxos.size(), 2ul); + EXPECT_EQ(plan.utxos[0].amount, 6500000ul); + EXPECT_EQ(plan.utxos[1].amount, 1500000ul); // perform sign with default plan const auto output = signer.sign(); @@ -305,13 +305,13 @@ TEST(CardanoSigning, PlanAndSignMaxAmount) { auto signer = Signer(input); const auto plan = signer.doPlan(); - EXPECT_EQ(plan.availableAmount, 8000000); - EXPECT_EQ(plan.amount, 8000000 - 167333); - EXPECT_EQ(plan.fee, 167333); - EXPECT_EQ(plan.change, 0); - ASSERT_EQ(plan.utxos.size(), 2); - EXPECT_EQ(plan.utxos[0].amount, 1500000); - EXPECT_EQ(plan.utxos[1].amount, 6500000); + EXPECT_EQ(plan.availableAmount, 8000000ul); + EXPECT_EQ(plan.amount, 8000000 - 167333ul); + EXPECT_EQ(plan.fee, 167333ul); + EXPECT_EQ(plan.change, 0ul); + ASSERT_EQ(plan.utxos.size(), 2ul); + EXPECT_EQ(plan.utxos[0].amount, 1500000ul); + EXPECT_EQ(plan.utxos[1].amount, 6500000ul); } auto signer = Signer(input); @@ -361,7 +361,7 @@ TEST(CardanoSigning, SignNegative) { } TEST(CardanoSigning, SignTransfer_0db1ea) { - const auto amount = 1100000; + const auto amount = 1100000ul; Proto::SigningInput input; auto* utxo1 = input.add_utxos(); @@ -382,7 +382,7 @@ TEST(CardanoSigning, SignTransfer_0db1ea) { input.mutable_transfer_message()->set_to_address("addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq"); input.mutable_transfer_message()->set_change_address(ownAddress1); input.mutable_transfer_message()->set_amount(amount); - auto fee = 170147; + auto fee = 170147ul; input.mutable_transfer_message()->set_use_max_amount(false); input.mutable_transfer_message()->set_force_fee(fee); // use force fee feature here input.set_ttl(54675589); @@ -392,11 +392,11 @@ TEST(CardanoSigning, SignTransfer_0db1ea) { auto signer = Signer(input); const auto plan = signer.doPlan(); - EXPECT_EQ(plan.availableAmount, 2800000); + EXPECT_EQ(plan.availableAmount, 2800000ul); EXPECT_EQ(plan.amount, amount); EXPECT_EQ(plan.fee, fee); - EXPECT_EQ(plan.change, 2800000 - amount - fee); - EXPECT_EQ(plan.utxos.size(), 2); + EXPECT_EQ(plan.change, 2800000ul - amount - fee); + EXPECT_EQ(plan.utxos.size(), 2ul); } // set plan with specific fee, to match the real transaction @@ -531,7 +531,7 @@ TEST(CardanoSigning, SignTransferToken) { { // check min ADA amount, set it const auto bundleProtoData = data(input.transfer_message().token_amount().SerializeAsString()); const auto minAdaAmount = TWCardanoMinAdaAmount(&bundleProtoData); - EXPECT_EQ(minAdaAmount, 1444443); + EXPECT_EQ(minAdaAmount, 1444443ul); input.mutable_transfer_message()->set_amount(minAdaAmount); } @@ -540,18 +540,18 @@ TEST(CardanoSigning, SignTransferToken) { auto signer = Signer(input); const auto plan = signer.doPlan(); - EXPECT_EQ(plan.availableAmount, 10051373); - EXPECT_EQ(plan.amount, 1444443); - EXPECT_EQ(plan.fee, 175966); - EXPECT_EQ(plan.change, 8430964); - EXPECT_EQ(plan.utxos.size(), 2); - EXPECT_EQ(plan.availableTokens.size(), 2); + EXPECT_EQ(plan.availableAmount, 10051373ul); + EXPECT_EQ(plan.amount, 1444443ul); + EXPECT_EQ(plan.fee, 175966ul); + EXPECT_EQ(plan.change, 8430964ul); + EXPECT_EQ(plan.utxos.size(), 2ul); + EXPECT_EQ(plan.availableTokens.size(), 2ul); EXPECT_EQ(plan.availableTokens.getAmount("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77_CUBY"), 5000000); EXPECT_EQ(plan.availableTokens.getAmount("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77_SUNDAE"), 80996569); - EXPECT_EQ(plan.outputTokens.size(), 1); + EXPECT_EQ(plan.outputTokens.size(), 1ul); EXPECT_EQ(plan.outputTokens.getAmount("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77_CUBY"), 0); EXPECT_EQ(plan.outputTokens.getAmount("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77_SUNDAE"), 20000000); - EXPECT_EQ(plan.changeTokens.size(), 2); + EXPECT_EQ(plan.changeTokens.size(), 2ul); EXPECT_EQ(plan.changeTokens.getAmount("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77_CUBY"), 5000000); EXPECT_EQ(plan.changeTokens.getAmount("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77_SUNDAE"), 60996569); } @@ -569,8 +569,8 @@ TEST(CardanoSigning, SignTransferToken) { // also test proto toProto / fromProto const Proto::TransactionPlan planProto = Signer::plan(input); const auto plan2 = TransactionPlan::fromProto(planProto); - EXPECT_EQ(plan2.amount, 1444443); - EXPECT_EQ(plan2.change, 8430964); + EXPECT_EQ(plan2.amount, 1444443ul); + EXPECT_EQ(plan2.change, 8430964ul); } } @@ -611,7 +611,7 @@ TEST(CardanoSigning, SignTransferToken_1dd248) { { // check min ADA amount const auto bundleProtoData = data(input.transfer_message().token_amount().SerializeAsString()); - EXPECT_EQ(TWCardanoMinAdaAmount(&bundleProtoData), 1444443); + EXPECT_EQ(TWCardanoMinAdaAmount(&bundleProtoData), 1444443ul); EXPECT_GT(input.transfer_message().amount(), TWCardanoMinAdaAmount(&bundleProtoData)); } @@ -620,16 +620,16 @@ TEST(CardanoSigning, SignTransferToken_1dd248) { auto signer = Signer(input); const auto plan = signer.doPlan(); - EXPECT_EQ(plan.availableAmount, 11758890); - EXPECT_EQ(plan.amount, 11758890 - 9984729 - 174161); - EXPECT_EQ(plan.fee, 174161); - EXPECT_EQ(plan.change, 9984729); - EXPECT_EQ(plan.utxos.size(), 2); - EXPECT_EQ(plan.availableTokens.size(), 1); + EXPECT_EQ(plan.availableAmount, 11758890ul); + EXPECT_EQ(plan.amount, 11758890 - 9984729 - 174161ul); + EXPECT_EQ(plan.fee, 174161ul); + EXPECT_EQ(plan.change, 9984729ul); + EXPECT_EQ(plan.utxos.size(), 2ul); + EXPECT_EQ(plan.availableTokens.size(), 1ul); EXPECT_EQ(plan.availableTokens.getAmount("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77_SUNDAE"), 20000000); - EXPECT_EQ(plan.outputTokens.size(), 1); + EXPECT_EQ(plan.outputTokens.size(), 1ul); EXPECT_EQ(plan.outputTokens.getAmount("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77_SUNDAE"), 11000000); - EXPECT_EQ(plan.changeTokens.size(), 1); + EXPECT_EQ(plan.changeTokens.size(), 1ul); EXPECT_EQ(plan.changeTokens.getAmount("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77_SUNDAE"), 9000000); } @@ -692,16 +692,16 @@ TEST(CardanoSigning, SignTransferTokenMaxAmount_620b71) { auto signer = Signer(input); const auto plan = signer.doPlan(); - EXPECT_EQ(plan.availableAmount, 2170871); - EXPECT_EQ(plan.amount, 2170871 - 167730); - EXPECT_EQ(plan.fee, 167730); - EXPECT_EQ(plan.change, 0); - EXPECT_EQ(plan.utxos.size(), 1); - EXPECT_EQ(plan.availableTokens.size(), 1); + EXPECT_EQ(plan.availableAmount, 2170871ul); + EXPECT_EQ(plan.amount, 2170871 - 167730ul); + EXPECT_EQ(plan.fee, 167730ul); + EXPECT_EQ(plan.change, 0ul); + EXPECT_EQ(plan.utxos.size(), 1ul); + EXPECT_EQ(plan.availableTokens.size(), 1ul); EXPECT_EQ(plan.availableTokens.getAmount("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77_SUNDAE"), 20000000); - EXPECT_EQ(plan.outputTokens.size(), 1); + EXPECT_EQ(plan.outputTokens.size(), 1ul); EXPECT_EQ(plan.outputTokens.getAmount("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77_SUNDAE"), 20000000); - EXPECT_EQ(plan.changeTokens.size(), 0); + EXPECT_EQ(plan.changeTokens.size(), 0ul); } // set plan with specific fee, to match the real transaction @@ -798,13 +798,13 @@ TEST(CardanoSigning, AnyPlan1) { ANY_PLAN(input, plan, TWCoinTypeCardano); EXPECT_EQ(plan.error(), Common::Proto::OK); - EXPECT_EQ(plan.amount(), 7000000); - EXPECT_EQ(plan.available_amount(), 8000000); - EXPECT_EQ(plan.fee(), 170196); - EXPECT_EQ(plan.change(), 829804); + EXPECT_EQ(plan.amount(), 7000000ul); + EXPECT_EQ(plan.available_amount(), 8000000ul); + EXPECT_EQ(plan.fee(), 170196ul); + EXPECT_EQ(plan.change(), 829804ul); ASSERT_EQ(plan.utxos_size(), 2); - EXPECT_EQ(plan.utxos(0).amount(), 6500000); - EXPECT_EQ(plan.utxos(1).amount(), 1500000); + EXPECT_EQ(plan.utxos(0).amount(), 6500000ul); + EXPECT_EQ(plan.utxos(1).amount(), 1500000ul); EXPECT_EQ(hex(plan.SerializeAsString()), "0880a4e80310c09fab0318d4b10a20ecd2324292010a220a20554f2fd942a23d06835d26bbd78f0106fa94c8a551114a0bef81927f66467af01267616464723171383034336d356865656179646e76746d6d6b7975686536717635686176766873663064323671336a7967737370786c796670796b3679716b77307968747976747230666c656b6a3834753634617a38326375666d716e36357a6473796c7a6b323318a0dd8c034293010a240a20f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76710011267616464723171383034336d356865656179646e76746d6d6b7975686536717635686176766873663064323671336a7967737370786c796670796b3679716b77307968747976747230666c656b6a3834753634617a38326375666d716e36357a6473796c7a6b323318e0c65b"); diff --git a/tests/Cardano/TWCardanoAddressTests.cpp b/tests/Cardano/TWCardanoAddressTests.cpp index be830e7f833..ab2d7689807 100644 --- a/tests/Cardano/TWCardanoAddressTests.cpp +++ b/tests/Cardano/TWCardanoAddressTests.cpp @@ -23,7 +23,7 @@ TEST(TWCardano, AddressFromPublicKey) { ASSERT_NE(nullptr, privateKey.get()); auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyEd25519Cardano(privateKey.get())); ASSERT_NE(nullptr, publicKey.get()); - ASSERT_EQ(128, publicKey.get()->impl.bytes.size()); + ASSERT_EQ(128ul, publicKey.get()->impl.bytes.size()); auto address = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKey(publicKey.get(), TWCoinTypeCardano)); auto addressString = WRAPS(TWAnyAddressDescription(address.get())); assertStringsEqual(addressString, "addr1qx4z6twzknkkux0hhp0kq6hvdfutczp56g56y5em8r8mgvxalp7nkkk25vuspleke2zltaetmlwrfxv7t049cq9jmwjswmfw6t"); @@ -43,11 +43,11 @@ TEST(TWCardano, AddressFromWallet) { )); auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeCardano)); auto privateKeyData = WRAPD(TWPrivateKeyData(privateKey.get())); - EXPECT_EQ(TWDataSize(privateKeyData.get()), 192); + EXPECT_EQ(TWDataSize(privateKeyData.get()), 192ul); auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyEd25519Cardano(privateKey.get())); auto publicKeyData = WRAPD(TWPublicKeyData(publicKey.get())); - EXPECT_EQ(TWDataSize(publicKeyData.get()), 128); + EXPECT_EQ(TWDataSize(publicKeyData.get()), 128ul); assertHexEqual(publicKeyData, "fafa7eb4146220db67156a03a5f7a79c666df83eb31abbfbe77c85e06d40da3110f3245ddf9132ecef98c670272ef39c03a232107733d4a1d28cb53318df26faf4b8d5201961e68f2e177ba594101f513ee70fe70a41324e8ea8eb787ffda6f4bf2eea84515a4e16c4ff06c92381822d910b5cbf9e9c144e1fb76a6291af7276"); auto address = WRAPS(TWCoinTypeDeriveAddress(TWCoinTypeCardano, privateKey.get())); diff --git a/tests/Cardano/TransactionTests.cpp b/tests/Cardano/TransactionTests.cpp index cce2c5be2bc..7f43daf0660 100644 --- a/tests/Cardano/TransactionTests.cpp +++ b/tests/Cardano/TransactionTests.cpp @@ -45,7 +45,7 @@ TEST(CardanoTransaction, Encode) { { const auto decode = Cbor::Decode(encoded); ASSERT_TRUE(decode.isValid()); - EXPECT_EQ(decode.getMapElements().size(), 4); + EXPECT_EQ(decode.getMapElements().size(), 4ul); EXPECT_EQ(decode.dumpToString(), "{0: [[h\"f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e767\", 1], [h\"554f2fd942a23d06835d26bbd78f0106fa94c8a551114a0bef81927f66467af0\", 0]], 1: [[h\"01df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\", 2000000], [h\"01558dd902616f5cd01edcc62870cb4748c45403f1228218bee5b628b526f0ca9e7a2c04d548fbd6ce86f358be139fe680652536437d1d6fd5\", 16749189]], 2: 165555, 3: 53333345}"); } } @@ -62,17 +62,17 @@ TEST(CardanoTransaction, minAdaAmount) { { // ADA only const auto tb = TokenBundle(); - EXPECT_EQ(tb.minAdaAmount(), 1000000); + EXPECT_EQ(tb.minAdaAmount(), 1000000ul); } { // 1 policyId, 1 6-char asset name const auto tb = TokenBundle({TokenAmount(policyId, "TOKEN1", 0)}); - EXPECT_EQ(tb.minAdaAmount(), 1444443); + EXPECT_EQ(tb.minAdaAmount(), 1444443ul); } { // 2 policyId, 2 4-char asset names auto tb = TokenBundle(); tb.add(TokenAmount("012345678901234567890POLICY1", "TOK1", 20)); tb.add(TokenAmount("012345678901234567890POLICY2", "TOK2", 20)); - EXPECT_EQ(tb.minAdaAmount(), 1629628); + EXPECT_EQ(tb.minAdaAmount(), 1629628ul); } { // 10 policyId, 10 6-char asset names auto tb = TokenBundle(); @@ -81,26 +81,26 @@ TEST(CardanoTransaction, minAdaAmount) { string name = "ASSET" + std::to_string(i); tb.add(TokenAmount(policyId1, name, 0)); } - EXPECT_EQ(tb.minAdaAmount(), 3370367); + EXPECT_EQ(tb.minAdaAmount(), 3370367ul); } - EXPECT_EQ(TokenBundle::minAdaAmountHelper(0, 0, 0), 1000000); // ADA only - EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 0, 0), 1370369); // 1 policyId, no asset name - EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 1, 1), 1444443); // 1 policyId, 1 1-char asset name - EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 1, 6), 1444443); // 1 policyId, 1 6-char asset name - EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 1, 32), 1555554); // 1 policyId, 1 32-char asset name - EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 110, 110*32), 23777754); // 1 policyId, 110 32-char asset name - EXPECT_EQ(TokenBundle::minAdaAmountHelper(2, 2, 8), 1629628); // 2 policyId, 2 4-char asset names - EXPECT_EQ(TokenBundle::minAdaAmountHelper(3, 5, 20), 1999998); // 3 policyId, 5 4-char asset names - EXPECT_EQ(TokenBundle::minAdaAmountHelper(10, 10, 10*6), 3370367); // 10 policyId, 10 6-char asset names - EXPECT_EQ(TokenBundle::minAdaAmountHelper(60, 60, 60*32), 21222201); // 60 policyId, 60 32-char asset names + EXPECT_EQ(TokenBundle::minAdaAmountHelper(0, 0, 0), 1000000ul); // ADA only + EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 0, 0), 1370369ul); // 1 policyId, no asset name + EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 1, 1), 1444443ul); // 1 policyId, 1 1-char asset name + EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 1, 6), 1444443ul); // 1 policyId, 1 6-char asset name + EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 1, 32), 1555554ul); // 1 policyId, 1 32-char asset name + EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 110, 110*32), 23777754ul); // 1 policyId, 110 32-char asset name + EXPECT_EQ(TokenBundle::minAdaAmountHelper(2, 2, 8), 1629628ul); // 2 policyId, 2 4-char asset names + EXPECT_EQ(TokenBundle::minAdaAmountHelper(3, 5, 20), 1999998ul); // 3 policyId, 5 4-char asset names + EXPECT_EQ(TokenBundle::minAdaAmountHelper(10, 10, 10*6), 3370367ul); // 10 policyId, 10 6-char asset names + EXPECT_EQ(TokenBundle::minAdaAmountHelper(60, 60, 60*32), 21222201ul); // 60 policyId, 60 32-char asset names } TEST(TWCardanoTransaction, minAdaAmount) { { // ADA-only const auto bundleProto = TokenBundle().toProto(); const auto bundleProtoData = data(bundleProto.SerializeAsString()); - EXPECT_EQ(TWCardanoMinAdaAmount(&bundleProtoData), 1000000); + EXPECT_EQ(TWCardanoMinAdaAmount(&bundleProtoData), 1000000ul); } { // 2 policyId, 2 4-char asset names auto bundle = TokenBundle(); @@ -108,6 +108,6 @@ TEST(TWCardanoTransaction, minAdaAmount) { bundle.add(TokenAmount("012345678901234567890POLICY2", "TOK2", 20)); const auto bundleProto = bundle.toProto(); const auto bundleProtoData = data(bundleProto.SerializeAsString()); - EXPECT_EQ(TWCardanoMinAdaAmount(&bundleProtoData), 1629628); + EXPECT_EQ(TWCardanoMinAdaAmount(&bundleProtoData), 1629628ul); } } diff --git a/tests/CborTests.cpp b/tests/CborTests.cpp index d8554de02cf..6016793dc4c 100644 --- a/tests/CborTests.cpp +++ b/tests/CborTests.cpp @@ -131,36 +131,36 @@ TEST(Cbor, EncInvalid) { } TEST(Cbor, DecInt) { - EXPECT_EQ(0, Decode(parse_hex("00")).getValue()); - EXPECT_EQ(1, Decode(parse_hex("01")).getValue()); - EXPECT_EQ(10, Decode(parse_hex("0a")).getValue()); - EXPECT_EQ(23, Decode(parse_hex("17")).getValue()); - EXPECT_EQ(24, Decode(parse_hex("1818")).getValue()); - EXPECT_EQ(25, Decode(parse_hex("1819")).getValue()); - EXPECT_EQ(26, Decode(parse_hex("181a")).getValue()); - EXPECT_EQ(27, Decode(parse_hex("181b")).getValue()); - EXPECT_EQ(28, Decode(parse_hex("181c")).getValue()); - EXPECT_EQ(29, Decode(parse_hex("181d")).getValue()); - EXPECT_EQ(30, Decode(parse_hex("181e")).getValue()); - EXPECT_EQ(31, Decode(parse_hex("181f")).getValue()); - EXPECT_EQ(32, Decode(parse_hex("1820")).getValue()); - EXPECT_EQ(0x3f, Decode(parse_hex("183f")).getValue()); - EXPECT_EQ(0x40, Decode(parse_hex("1840")).getValue()); - EXPECT_EQ(100, Decode(parse_hex("1864")).getValue()); - EXPECT_EQ(0x7f, Decode(parse_hex("187f")).getValue()); - EXPECT_EQ(0x80, Decode(parse_hex("1880")).getValue()); - EXPECT_EQ(0xff, Decode(parse_hex("18ff")).getValue()); - EXPECT_EQ(0x100, Decode(parse_hex("190100")).getValue()); - EXPECT_EQ(1000, Decode(parse_hex("1903e8")).getValue()); - EXPECT_EQ(0x8765, Decode(parse_hex("198765")).getValue()); - EXPECT_EQ(0xffff, Decode(parse_hex("19ffff")).getValue()); - EXPECT_EQ(0x00010000, Decode(parse_hex("1a00010000")).getValue()); - EXPECT_EQ(1000000, Decode(parse_hex("1a000f4240")).getValue()); - EXPECT_EQ(0x00800000, Decode(parse_hex("1a00800000")).getValue()); + EXPECT_EQ(0ul, Decode(parse_hex("00")).getValue()); + EXPECT_EQ(1ul, Decode(parse_hex("01")).getValue()); + EXPECT_EQ(10ul, Decode(parse_hex("0a")).getValue()); + EXPECT_EQ(23ul, Decode(parse_hex("17")).getValue()); + EXPECT_EQ(24ul, Decode(parse_hex("1818")).getValue()); + EXPECT_EQ(25ul, Decode(parse_hex("1819")).getValue()); + EXPECT_EQ(26ul, Decode(parse_hex("181a")).getValue()); + EXPECT_EQ(27ul, Decode(parse_hex("181b")).getValue()); + EXPECT_EQ(28ul, Decode(parse_hex("181c")).getValue()); + EXPECT_EQ(29ul, Decode(parse_hex("181d")).getValue()); + EXPECT_EQ(30ul, Decode(parse_hex("181e")).getValue()); + EXPECT_EQ(31ul, Decode(parse_hex("181f")).getValue()); + EXPECT_EQ(32ul, Decode(parse_hex("1820")).getValue()); + EXPECT_EQ(0x3ful, Decode(parse_hex("183f")).getValue()); + EXPECT_EQ(0x40ul, Decode(parse_hex("1840")).getValue()); + EXPECT_EQ(100ul, Decode(parse_hex("1864")).getValue()); + EXPECT_EQ(0x7ful, Decode(parse_hex("187f")).getValue()); + EXPECT_EQ(0x80ul, Decode(parse_hex("1880")).getValue()); + EXPECT_EQ(0xfful, Decode(parse_hex("18ff")).getValue()); + EXPECT_EQ(0x100ul, Decode(parse_hex("190100")).getValue()); + EXPECT_EQ(1000ul, Decode(parse_hex("1903e8")).getValue()); + EXPECT_EQ(0x8765ul, Decode(parse_hex("198765")).getValue()); + EXPECT_EQ(0xfffful, Decode(parse_hex("19ffff")).getValue()); + EXPECT_EQ(0x00010000ul, Decode(parse_hex("1a00010000")).getValue()); + EXPECT_EQ(1000000ul, Decode(parse_hex("1a000f4240")).getValue()); + EXPECT_EQ(0x00800000ul, Decode(parse_hex("1a00800000")).getValue()); EXPECT_EQ(0x87654321, Decode(parse_hex("1a87654321")).getValue()); EXPECT_EQ(0xffffffff, Decode(parse_hex("1affffffff")).getValue()); - EXPECT_EQ(0x0000000100000000, Decode(parse_hex("1b0000000100000000")).getValue()); - EXPECT_EQ(1000000000000, Decode(parse_hex("1b000000e8d4a51000")).getValue()); + EXPECT_EQ(0x0000000100000000ul, Decode(parse_hex("1b0000000100000000")).getValue()); + EXPECT_EQ(1000000000000ul, Decode(parse_hex("1b000000e8d4a51000")).getValue()); EXPECT_EQ(0x876543210fedcba9, Decode(parse_hex("1b876543210fedcba9")).getValue()); EXPECT_EQ(0xffffffffffffffff, Decode(parse_hex("1bffffffffffffffff")).getValue()); } @@ -174,27 +174,27 @@ TEST(Cbor, DecMinortypeInvalid) { TEST(Cbor, DecArray3) { Decode cbor = Decode(parse_hex("83010203")); - EXPECT_EQ(3, cbor.getArrayElements().size()); + EXPECT_EQ(3ul, cbor.getArrayElements().size()); } TEST(Cbor, DecArrayNested) { Data d1 = parse_hex("8301820203820405"); Decode cbor = Decode(d1); - EXPECT_EQ(3, cbor.getArrayElements().size()); + EXPECT_EQ(3ul, cbor.getArrayElements().size()); - EXPECT_EQ(1, cbor.getArrayElements()[0].getValue()); - EXPECT_EQ(2, cbor.getArrayElements()[1].getArrayElements().size()); - EXPECT_EQ(2, cbor.getArrayElements()[1].getArrayElements()[0].getValue()); - EXPECT_EQ(3, cbor.getArrayElements()[1].getArrayElements()[1].getValue()); - EXPECT_EQ(2, cbor.getArrayElements()[2].getArrayElements().size()); - EXPECT_EQ(4, cbor.getArrayElements()[2].getArrayElements()[0].getValue()); - EXPECT_EQ(5, cbor.getArrayElements()[2].getArrayElements()[1].getValue()); + EXPECT_EQ(1ul, cbor.getArrayElements()[0].getValue()); + EXPECT_EQ(2ul, cbor.getArrayElements()[1].getArrayElements().size()); + EXPECT_EQ(2ul, cbor.getArrayElements()[1].getArrayElements()[0].getValue()); + EXPECT_EQ(3ul, cbor.getArrayElements()[1].getArrayElements()[1].getValue()); + EXPECT_EQ(2ul, cbor.getArrayElements()[2].getArrayElements().size()); + EXPECT_EQ(4ul, cbor.getArrayElements()[2].getArrayElements()[0].getValue()); + EXPECT_EQ(5ul, cbor.getArrayElements()[2].getArrayElements()[1].getValue()); } TEST(Cbor, DecEncoded) { // sometimes getting the encoded version is useful during decoding too Decode cbor = Decode(parse_hex("8301820203820405")); - EXPECT_EQ(3, cbor.getArrayElements().size()); + EXPECT_EQ(3ul, cbor.getArrayElements().size()); EXPECT_EQ("820203", hex(cbor.getArrayElements()[1].encoded())); EXPECT_EQ("820405", hex(cbor.getArrayElements()[2].encoded())); } @@ -208,14 +208,14 @@ TEST(Cbor, DecMemoryref) { // also do some new allocation Decode* dummy = new Decode(parse_hex("5555555555555555")); // work with the child references - EXPECT_EQ(2, elems.size()); - EXPECT_EQ(3, elems[0].getArrayElements().size()); - EXPECT_EQ(3, elems[1].getArrayElements().size()); + EXPECT_EQ(2ul, elems.size()); + EXPECT_EQ(3ul, elems[0].getArrayElements().size()); + EXPECT_EQ(3ul, elems[1].getArrayElements().size()); delete dummy; } TEST(Cbor, GetValue) { - EXPECT_EQ(5, Decode(parse_hex("05")).getValue()); + EXPECT_EQ(5ul, Decode(parse_hex("05")).getValue()); } TEST(Cbor, GetValueInvalid) { @@ -263,7 +263,7 @@ TEST(Cbor, ArrayEmpty) { EXPECT_EQ("[]", Decode(cbor).dumpToString()); Decode decode(cbor); - EXPECT_EQ(0, decode.getArrayElements().size()); + EXPECT_EQ(0ul, decode.getArrayElements().size()); } TEST(Cbor, Array3) { @@ -278,10 +278,10 @@ TEST(Cbor, Array3) { EXPECT_EQ("[1, 2, 3]", Decode(cbor).dumpToString()); Decode decode(cbor); - EXPECT_EQ(3, decode.getArrayElements().size()); - EXPECT_EQ(1, decode.getArrayElements()[0].getValue()); - EXPECT_EQ(2, decode.getArrayElements()[1].getValue()); - EXPECT_EQ(3, decode.getArrayElements()[2].getValue()); + EXPECT_EQ(3ul, decode.getArrayElements().size()); + EXPECT_EQ(1ul, decode.getArrayElements()[0].getValue()); + EXPECT_EQ(2ul, decode.getArrayElements()[1].getValue()); + EXPECT_EQ(3ul, decode.getArrayElements()[2].getValue()); } TEST(Cbor, ArrayNested) { @@ -303,14 +303,14 @@ TEST(Cbor, ArrayNested) { Decode(cbor).dumpToString()); Decode decode(cbor); - EXPECT_EQ(3, decode.getArrayElements().size()); - EXPECT_EQ(1, decode.getArrayElements()[0].getValue()); - EXPECT_EQ(2, decode.getArrayElements()[1].getArrayElements().size()); - EXPECT_EQ(2, decode.getArrayElements()[1].getArrayElements()[0].getValue()); - EXPECT_EQ(3, decode.getArrayElements()[1].getArrayElements()[1].getValue()); - EXPECT_EQ(2, decode.getArrayElements()[2].getArrayElements().size()); - EXPECT_EQ(4, decode.getArrayElements()[2].getArrayElements()[0].getValue()); - EXPECT_EQ(5, decode.getArrayElements()[2].getArrayElements()[1].getValue()); + EXPECT_EQ(3ul, decode.getArrayElements().size()); + EXPECT_EQ(1ul, decode.getArrayElements()[0].getValue()); + EXPECT_EQ(2ul, decode.getArrayElements()[1].getArrayElements().size()); + EXPECT_EQ(2ul, decode.getArrayElements()[1].getArrayElements()[0].getValue()); + EXPECT_EQ(3ul, decode.getArrayElements()[1].getArrayElements()[1].getValue()); + EXPECT_EQ(2ul, decode.getArrayElements()[2].getArrayElements().size()); + EXPECT_EQ(4ul, decode.getArrayElements()[2].getArrayElements()[0].getValue()); + EXPECT_EQ(5ul, decode.getArrayElements()[2].getArrayElements()[1].getValue()); } TEST(Cbor, Array25) { @@ -326,8 +326,8 @@ TEST(Cbor, Array25) { Decode(cbor).dumpToString()); Decode decode(cbor); - EXPECT_EQ(25, decode.getArrayElements().size()); - for (int i = 1; i <= 25; ++i) { + EXPECT_EQ(25ul, decode.getArrayElements().size()); + for (auto i = 1ul; i <= 25; ++i) { EXPECT_EQ(i, decode.getArrayElements()[i - 1].getValue()); } } @@ -340,7 +340,7 @@ TEST(Cbor, MapEmpty) { EXPECT_EQ("{}", Decode(cbor).dumpToString()); Decode decode(cbor); - EXPECT_EQ(0, decode.getMapElements().size()); + EXPECT_EQ(0ul, decode.getMapElements().size()); } TEST(Cbor, Map2Num) { @@ -354,9 +354,9 @@ TEST(Cbor, Map2Num) { EXPECT_EQ("{1: 2, 3: 4}", Decode(cbor).dumpToString()); Decode decode(cbor); - EXPECT_EQ(2, decode.getMapElements().size()); - EXPECT_EQ(1, decode.getMapElements()[0].first.getValue()); - EXPECT_EQ(2, decode.getMapElements()[0].second.getValue()); + EXPECT_EQ(2ul, decode.getMapElements().size()); + EXPECT_EQ(1ul, decode.getMapElements()[0].first.getValue()); + EXPECT_EQ(2ul, decode.getMapElements()[0].second.getValue()); } TEST(Cbor, Map2WithArr) { @@ -374,13 +374,13 @@ TEST(Cbor, Map2WithArr) { Decode(cbor).dumpToString()); Decode decode(cbor); - EXPECT_EQ(2, decode.getMapElements().size()); + EXPECT_EQ(2ul, decode.getMapElements().size()); EXPECT_EQ("a", decode.getMapElements()[0].first.getString()); - EXPECT_EQ(1, decode.getMapElements()[0].second.getValue()); + EXPECT_EQ(1ul, decode.getMapElements()[0].second.getValue()); EXPECT_EQ("b", decode.getMapElements()[1].first.getString()); - EXPECT_EQ(2, decode.getMapElements()[1].second.getArrayElements().size()); - EXPECT_EQ(2, decode.getMapElements()[1].second.getArrayElements()[0].getValue()); - EXPECT_EQ(3, decode.getMapElements()[1].second.getArrayElements()[1].getValue()); + EXPECT_EQ(2ul, decode.getMapElements()[1].second.getArrayElements().size()); + EXPECT_EQ(2ul, decode.getMapElements()[1].second.getArrayElements()[0].getValue()); + EXPECT_EQ(3ul, decode.getMapElements()[1].second.getArrayElements()[1].getValue()); } TEST(Cbor, MapNested) { @@ -396,9 +396,9 @@ TEST(Cbor, MapNested) { Decode(cbor).dumpToString()); Decode decode(cbor); - EXPECT_EQ(1, decode.getMapElements().size()); + EXPECT_EQ(1ul, decode.getMapElements().size()); EXPECT_EQ("a", decode.getMapElements()[0].first.getString()); - EXPECT_EQ(1, decode.getMapElements()[0].second.getMapElements().size()); + EXPECT_EQ(1ul, decode.getMapElements()[0].second.getMapElements().size()); EXPECT_EQ("b", decode.getMapElements()[0].second.getMapElements()[0].first.getString()); EXPECT_EQ("c", decode.getMapElements()[0].second.getMapElements()[0].second.getString()); } @@ -406,9 +406,9 @@ TEST(Cbor, MapNested) { TEST(Cbor, MapIndef) { Decode cbor = Decode(parse_hex("bf01020304ff")); EXPECT_EQ("{_ 1: 2, 3: 4}", cbor.dumpToString()); - EXPECT_EQ(2, cbor.getMapElements().size()); - EXPECT_EQ(1, cbor.getMapElements()[0].first.getValue()); - EXPECT_EQ(2, cbor.getMapElements()[0].second.getValue()); + EXPECT_EQ(2ul, cbor.getMapElements().size()); + EXPECT_EQ(1ul, cbor.getMapElements()[0].first.getValue()); + EXPECT_EQ(2ul, cbor.getMapElements()[0].second.getValue()); } TEST(Cbor, MapIsValidInvalidTooShort) { @@ -455,9 +455,9 @@ TEST(Cbor, ArrayIndef) { Decode(cbor).dumpToString()); Decode decode(cbor); - EXPECT_EQ(2, decode.getArrayElements().size()); - EXPECT_EQ(1, decode.getArrayElements()[0].getValue()); - EXPECT_EQ(2, decode.getArrayElements()[1].getValue()); + EXPECT_EQ(2ul, decode.getArrayElements().size()); + EXPECT_EQ(1ul, decode.getArrayElements()[0].getValue()); + EXPECT_EQ(2ul, decode.getArrayElements()[1].getValue()); EXPECT_EQ("[_ 1, 2]", Decode(parse_hex("9f0102ff")).dumpToString()); EXPECT_EQ("", Decode(parse_hex("ff")).dumpToString()); diff --git a/tests/DataTests.cpp b/tests/DataTests.cpp index bbdc6f3ffd8..dec40018c9c 100644 --- a/tests/DataTests.cpp +++ b/tests/DataTests.cpp @@ -14,34 +14,34 @@ using namespace TW; TEST(DataTests, fromVector) { const Data data = {1, 2, 3}; - EXPECT_EQ(data.size(), 3); + EXPECT_EQ(data.size(), 3ul); EXPECT_EQ(data[1], 2); EXPECT_EQ(hex(data), "010203"); } TEST(DataTests, fromHex) { const Data data = parse_hex("01020304"); - EXPECT_EQ(data.size(), 4); + EXPECT_EQ(data.size(), 4ul); EXPECT_EQ(hex(data), "01020304"); } TEST(DataTests, fromString) { const Data data = TW::data(std::string("ABC")); - EXPECT_EQ(data.size(), 3); + EXPECT_EQ(data.size(), 3ul); EXPECT_EQ(hex(data), "414243"); } TEST(DataTests, fromBytes) { const std::vector vec = {1, 2, 3}; const Data data = TW::data(vec.data(), vec.size()); - EXPECT_EQ(data.size(), 3); + EXPECT_EQ(data.size(), 3ul); EXPECT_EQ(hex(data), "010203"); } TEST(DataTests, padLeft) { Data data = parse_hex("01020304"); pad_left(data, 10); - EXPECT_EQ(data.size(), 10); + EXPECT_EQ(data.size(), 10ul); EXPECT_EQ(hex(data), "00000000000001020304"); } @@ -49,20 +49,20 @@ TEST(DataTests, append) { Data data1 = parse_hex("01020304"); const Data data2 = parse_hex("aeaf"); append(data1, data2); - EXPECT_EQ(data1.size(), 6); + EXPECT_EQ(data1.size(), 6ul); EXPECT_EQ(hex(data1), "01020304aeaf"); } TEST(DataTests, appendByte) { Data data1 = parse_hex("01020304"); append(data1, 5); - EXPECT_EQ(data1.size(), 5); + EXPECT_EQ(data1.size(), 5ul); EXPECT_EQ(hex(data1), "0102030405"); } TEST(DataTests, subData) { const Data data = parse_hex("0102030405060708090a"); - EXPECT_EQ(data.size(), 10); + EXPECT_EQ(data.size(), 10ul); EXPECT_EQ(hex(subData(data, 2, 3)), "030405"); EXPECT_EQ(hex(subData(data, 0, 10)), "0102030405060708090a"); diff --git a/tests/Decred/TWAnySignerTests.cpp b/tests/Decred/TWAnySignerTests.cpp index e1d08bbb221..033d87a4a2c 100644 --- a/tests/Decred/TWAnySignerTests.cpp +++ b/tests/Decred/TWAnySignerTests.cpp @@ -103,7 +103,7 @@ TEST(TWAnySignerDecred, PlanAndSign) { ANY_SIGN(input, TWCoinTypeDecred); ASSERT_EQ(output.error(), Common::Proto::OK); - ASSERT_EQ(output.encoded().size(), 251); + ASSERT_EQ(output.encoded().size(), 251ul); ASSERT_EQ(hex(output.encoded()), "0100000001fdbfe9dd703f306794a467f175be5bd9748a7925033ea1cf9889d7cf4dd1155000000000000000000002809698000000000000001976a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ace23bc8010000000000001976a9142a194fc92e27fef9cc2b057bc9060c580cbb484888ac000000000000000001000000000000000000000000ffffffff6a47304402203e6ee9e16d6bc36bb4242f7a4cac333a1c2a150ea16143412b88b721f6ae16bf02201019affdf815a5c22e4b0fb7e4685c4707094922d6a41354f9055d3bb0f26e630121026cc34b92cefb3a4537b3edb0b6044c04af27c01583c577823ecc69a9a21119b6"); } diff --git a/tests/DerivationPathTests.cpp b/tests/DerivationPathTests.cpp index 4ed6493387a..563d247add2 100644 --- a/tests/DerivationPathTests.cpp +++ b/tests/DerivationPathTests.cpp @@ -32,10 +32,10 @@ TEST(DerivationPath, InitWithString) { ASSERT_EQ(path.indices[4], DerivationPathIndex(0, /* hardened: */false)); ASSERT_EQ(path.purpose(), 44); - ASSERT_EQ(path.coin(), 60); - ASSERT_EQ(path.account(), 0); - ASSERT_EQ(path.change(), 0); - ASSERT_EQ(path.address(), 0); + ASSERT_EQ(path.coin(), 60ul); + ASSERT_EQ(path.account(), 0ul); + ASSERT_EQ(path.change(), 0ul); + ASSERT_EQ(path.address(), 0ul); } TEST(DerivationPath, InitInvalid) { @@ -46,13 +46,13 @@ TEST(DerivationPath, InitInvalid) { TEST(DerivationPath, IndexOutOfBounds) { DerivationPath path; - EXPECT_EQ(path.indices.size(), 0); + EXPECT_EQ(path.indices.size(), 0ul); EXPECT_EQ(path.purpose(), TWPurposeBIP44); EXPECT_EQ(path.coin(), TWCoinTypeBitcoin); - EXPECT_EQ(path.account(), 0); - EXPECT_EQ(path.change(), 0); - EXPECT_EQ(path.address(), 0); + EXPECT_EQ(path.account(), 0ul); + EXPECT_EQ(path.change(), 0ul); + EXPECT_EQ(path.address(), 0ul); ASSERT_NO_THROW(path.setPurpose(TWPurposeBIP44)); ASSERT_NO_THROW(path.setCoin(TWCoinTypeBitcoin)); diff --git a/tests/ECash/TWECashTests.cpp b/tests/ECash/TWECashTests.cpp index 97fc2924a36..9a8a24b4f09 100644 --- a/tests/ECash/TWECashTests.cpp +++ b/tests/ECash/TWECashTests.cpp @@ -151,7 +151,7 @@ TEST(ECash, SignTransaction) { EXPECT_EQ(output.transaction().outputs_size(), 2); EXPECT_EQ(output.transaction().outputs(0).value(), amount); EXPECT_EQ(output.transaction().outputs(1).value(), 4325); - EXPECT_EQ(output.encoded().length(), 226); + EXPECT_EQ(output.encoded().length(), 226ul); ASSERT_EQ(hex(output.encoded()), "01000000" "01" diff --git a/tests/Elrond/TransactionFactoryTests.cpp b/tests/Elrond/TransactionFactoryTests.cpp index 6ae9d13d176..c86777cb46d 100644 --- a/tests/Elrond/TransactionFactoryTests.cpp +++ b/tests/Elrond/TransactionFactoryTests.cpp @@ -27,10 +27,10 @@ TEST(ElrondTransactionFactory, fromEGLDTransfer) { ASSERT_EQ(BOB_BECH32, transaction.receiver); ASSERT_EQ("", transaction.data); ASSERT_EQ("1000000000000000000", transaction.value); - ASSERT_EQ(50000, transaction.gasLimit); - ASSERT_EQ(1000000000, transaction.gasPrice); + ASSERT_EQ(50000ul, transaction.gasLimit); + ASSERT_EQ(1000000000ul, transaction.gasPrice); ASSERT_EQ("1", transaction.chainID); - ASSERT_EQ(1, transaction.version); + ASSERT_EQ(1ul, transaction.version); } TEST(ElrondTransactionFactory, fromESDTTransfer) { @@ -48,10 +48,10 @@ TEST(ElrondTransactionFactory, fromESDTTransfer) { ASSERT_EQ(BOB_BECH32, transaction.receiver); ASSERT_EQ("ESDTTransfer@4d59544f4b454e2d31323334@09184e72a000", transaction.data); ASSERT_EQ("0", transaction.value); - ASSERT_EQ(425000, transaction.gasLimit); - ASSERT_EQ(1000000000, transaction.gasPrice); + ASSERT_EQ(425000ul, transaction.gasLimit); + ASSERT_EQ(1000000000ul, transaction.gasPrice); ASSERT_EQ("1", transaction.chainID); - ASSERT_EQ(1, transaction.version); + ASSERT_EQ(1ul, transaction.version); } TEST(ElrondTransactionFactory, fromESDTNFTTransfer) { @@ -70,10 +70,10 @@ TEST(ElrondTransactionFactory, fromESDTNFTTransfer) { ASSERT_EQ(ALICE_BECH32, transaction.receiver); ASSERT_EQ("ESDTNFTTransfer@4c4b4d45582d616162393130@04@028ec3dfa01ac000@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8", transaction.data); ASSERT_EQ("0", transaction.value); - ASSERT_EQ(937500, transaction.gasLimit); - ASSERT_EQ(1000000000, transaction.gasPrice); + ASSERT_EQ(937500ul, transaction.gasLimit); + ASSERT_EQ(1000000000ul, transaction.gasPrice); ASSERT_EQ("1", transaction.chainID); - ASSERT_EQ(1, transaction.version); + ASSERT_EQ(1ul, transaction.version); } TEST(ElrondTransactionFactory, createTransfersWithProvidedNetworkConfig) { @@ -110,16 +110,16 @@ TEST(ElrondTransactionFactory, createTransfersWithProvidedNetworkConfig) { Transaction tx2 = factory.fromESDTTransfer(signingInputWithESDTTransfer); Transaction tx3 = factory.fromESDTNFTTransfer(signingInputWithESDTNFTTransfer); - ASSERT_EQ(60000, tx1.gasLimit); - ASSERT_EQ(1500000000, tx1.gasPrice); + ASSERT_EQ(60000ul, tx1.gasLimit); + ASSERT_EQ(1500000000ul, tx1.gasPrice); ASSERT_EQ("T", tx1.chainID); - ASSERT_EQ(560000, tx2.gasLimit); - ASSERT_EQ(1500000000, tx2.gasPrice); + ASSERT_EQ(560000ul, tx2.gasLimit); + ASSERT_EQ(1500000000ul, tx2.gasPrice); ASSERT_EQ("T", tx2.chainID); - ASSERT_EQ(1110000, tx3.gasLimit); - ASSERT_EQ(1500000000, tx3.gasPrice); + ASSERT_EQ(1110000ul, tx3.gasLimit); + ASSERT_EQ(1500000000ul, tx3.gasPrice); ASSERT_EQ("T", tx3.chainID); } @@ -144,16 +144,16 @@ TEST(ElrondTransactionFactory, createTransfersWithOverriddenNetworkParameters) { Transaction tx2 = factory.fromESDTTransfer(signingInputWithESDTTransfer); Transaction tx3 = factory.fromESDTNFTTransfer(signingInputWithESDTNFTTransfer); - ASSERT_EQ(50500, tx1.gasLimit); - ASSERT_EQ(1000000001, tx1.gasPrice); + ASSERT_EQ(50500ul, tx1.gasLimit); + ASSERT_EQ(1000000001ul, tx1.gasPrice); ASSERT_EQ("A", tx1.chainID); - ASSERT_EQ(5000000, tx2.gasLimit); - ASSERT_EQ(1000000002, tx2.gasPrice); + ASSERT_EQ(5000000ul, tx2.gasLimit); + ASSERT_EQ(1000000002ul, tx2.gasPrice); ASSERT_EQ("B", tx2.chainID); - ASSERT_EQ(10000000, tx3.gasLimit); - ASSERT_EQ(1000000003, tx3.gasPrice); + ASSERT_EQ(10000000ul, tx3.gasLimit); + ASSERT_EQ(1000000003ul, tx3.gasPrice); ASSERT_EQ("C", tx3.chainID); } diff --git a/tests/EncryptTests.cpp b/tests/EncryptTests.cpp index 9870f4e2937..2bf4979fd2c 100644 --- a/tests/EncryptTests.cpp +++ b/tests/EncryptTests.cpp @@ -22,24 +22,24 @@ inline void assertHexEqual(const Data& data, const char* expected) { } TEST(Encrypt, paddingSize) { - EXPECT_EQ(paddingSize(0, 16, TWAESPaddingModeZero), 0); - EXPECT_EQ(paddingSize(1, 16, TWAESPaddingModeZero), 15); - EXPECT_EQ(paddingSize(8, 16, TWAESPaddingModeZero), 8); - EXPECT_EQ(paddingSize(15, 16, TWAESPaddingModeZero), 1); - EXPECT_EQ(paddingSize(16, 16, TWAESPaddingModeZero), 0); - EXPECT_EQ(paddingSize(17, 16, TWAESPaddingModeZero), 15); - EXPECT_EQ(paddingSize(24, 16, TWAESPaddingModeZero), 8); - EXPECT_EQ(paddingSize(31, 16, TWAESPaddingModeZero), 1); - EXPECT_EQ(paddingSize(32, 16, TWAESPaddingModeZero), 0); - EXPECT_EQ(paddingSize(0, 16, TWAESPaddingModePKCS7), 16); - EXPECT_EQ(paddingSize(1, 16, TWAESPaddingModePKCS7), 15); - EXPECT_EQ(paddingSize(8, 16, TWAESPaddingModePKCS7), 8); - EXPECT_EQ(paddingSize(15, 16, TWAESPaddingModePKCS7), 1); - EXPECT_EQ(paddingSize(16, 16, TWAESPaddingModePKCS7), 16); - EXPECT_EQ(paddingSize(17, 16, TWAESPaddingModePKCS7), 15); - EXPECT_EQ(paddingSize(24, 16, TWAESPaddingModePKCS7), 8); - EXPECT_EQ(paddingSize(31, 16, TWAESPaddingModePKCS7), 1); - EXPECT_EQ(paddingSize(32, 16, TWAESPaddingModePKCS7), 16); + EXPECT_EQ(paddingSize(0, 16, TWAESPaddingModeZero), 0ul); + EXPECT_EQ(paddingSize(1, 16, TWAESPaddingModeZero), 15ul); + EXPECT_EQ(paddingSize(8, 16, TWAESPaddingModeZero), 8ul); + EXPECT_EQ(paddingSize(15, 16, TWAESPaddingModeZero), 1ul); + EXPECT_EQ(paddingSize(16, 16, TWAESPaddingModeZero), 0ul); + EXPECT_EQ(paddingSize(17, 16, TWAESPaddingModeZero), 15ul); + EXPECT_EQ(paddingSize(24, 16, TWAESPaddingModeZero), 8ul); + EXPECT_EQ(paddingSize(31, 16, TWAESPaddingModeZero), 1ul); + EXPECT_EQ(paddingSize(32, 16, TWAESPaddingModeZero), 0ul); + EXPECT_EQ(paddingSize(0, 16, TWAESPaddingModePKCS7), 16ul); + EXPECT_EQ(paddingSize(1, 16, TWAESPaddingModePKCS7), 15ul); + EXPECT_EQ(paddingSize(8, 16, TWAESPaddingModePKCS7), 8ul); + EXPECT_EQ(paddingSize(15, 16, TWAESPaddingModePKCS7), 1ul); + EXPECT_EQ(paddingSize(16, 16, TWAESPaddingModePKCS7), 16ul); + EXPECT_EQ(paddingSize(17, 16, TWAESPaddingModePKCS7), 15ul); + EXPECT_EQ(paddingSize(24, 16, TWAESPaddingModePKCS7), 8ul); + EXPECT_EQ(paddingSize(31, 16, TWAESPaddingModePKCS7), 1ul); + EXPECT_EQ(paddingSize(32, 16, TWAESPaddingModePKCS7), 16ul); } TEST(Encrypt, AESCBCEncrypt) { diff --git a/tests/Ethereum/AbiStructTests.cpp b/tests/Ethereum/AbiStructTests.cpp index 5888f1d1c37..cd7f66cb3d2 100644 --- a/tests/Ethereum/AbiStructTests.cpp +++ b/tests/Ethereum/AbiStructTests.cpp @@ -581,7 +581,7 @@ TEST(EthereumAbiStruct, ParamStructMakeStruct) { })"); ASSERT_NE(s.get(), nullptr); EXPECT_EQ(s->getType(), "Person"); - ASSERT_EQ(s->getCount(), 2); + ASSERT_EQ(s->getCount(), 2ul); EXPECT_EQ(s->encodeType(), "Person(string name,address wallet)"); EXPECT_EQ(hex(s->hashStruct()), "fc71e5fa27ff56c350aa531bc129ebdf613b772b6604664f5d8dbe21b85eb0c8"); } @@ -595,7 +595,7 @@ TEST(EthereumAbiStruct, ParamStructMakeStruct) { })"); ASSERT_NE(s.get(), nullptr); EXPECT_EQ(s->getType(), "Person"); - ASSERT_EQ(s->getCount(), 2); + ASSERT_EQ(s->getCount(), 2ul); EXPECT_EQ(s->encodeType(), "Person(string name,address[] wallets)"); EXPECT_EQ(hex(s->hashStruct()), "9b4846dd48b866f0ac54d61b9b21a9e746f921cefa4ee94c4c0a1c49c774f67f"); } @@ -605,7 +605,7 @@ TEST(EthereumAbiStruct, ParamStructMakeStruct) { R"({"Person": [{"name": "name", "type": "string"}, {"name": "wallet", "type": "address"}],"Mail": [{"name": "from", "type": "Person"},{"name": "to", "type": "Person"},{"name": "contents", "type": "string"}]})"); ASSERT_NE(s.get(), nullptr); EXPECT_EQ(s->getType(), "Mail"); - ASSERT_EQ(s->getCount(), 3); + ASSERT_EQ(s->getCount(), 3ul); EXPECT_EQ(s->encodeType(), "Mail(Person from,Person to,string contents)Person(string name,address wallet)"); EXPECT_EQ(hex(s->hashStruct()), "c52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e"); } @@ -675,7 +675,7 @@ TEST(EthereumAbiStruct, ParamStructMakeStruct) { TEST(EthereumAbiStruct, ParamFactoryMakeTypes) { { std::vector> tt = ParamStruct::makeTypes(R"({"Person": [{"name": "name", "type": "string"}, {"name": "wallet", "type": "address"}]})"); - ASSERT_EQ(tt.size(), 1); + ASSERT_EQ(tt.size(), 1ul); EXPECT_EQ(tt[0]->encodeType(), "Person(string name,address wallet)"); } { @@ -684,7 +684,7 @@ TEST(EthereumAbiStruct, ParamFactoryMakeTypes) { "Person": [{"name": "name", "type": "string"}, {"name": "wallet", "type": "address"}], "Mail": [{"name": "from", "type": "Person"}, {"name": "to", "type": "Person"}, {"name": "contents", "type": "string"}] })"); - ASSERT_EQ(tt.size(), 2); + ASSERT_EQ(tt.size(), 2ul); EXPECT_EQ(tt[0]->encodeType(), "Mail(Person from,Person to,string contents)Person(string name,address wallet)"); EXPECT_EQ(tt[1]->encodeType(), "Person(string name,address wallet)"); } @@ -695,11 +695,11 @@ TEST(EthereumAbiStruct, ParamFactoryMakeTypes) { EXPECT_EXCEPTION(ParamStruct::makeTypes("0"), "Expecting object"); EXPECT_EXCEPTION(ParamStruct::makeTypes("[]"), "Expecting object"); EXPECT_EXCEPTION(ParamStruct::makeTypes("[{}]"), "Expecting object"); - EXPECT_EQ(ParamStruct::makeTypes("{}").size(), 0); + EXPECT_EQ(ParamStruct::makeTypes("{}").size(), 0ul); EXPECT_EXCEPTION(ParamStruct::makeTypes("{\"a\": 0}"), "Expecting array"); EXPECT_EXCEPTION(ParamStruct::makeTypes(R"({"name": 0})"), "Expecting array"); // order does not matter - EXPECT_EQ(ParamStruct::makeTypes(R"({"Mail": [{"name": "from", "type": "Person"}, {"name": "to", "type": "Person"}, {"name": "contents", "type": "string"}], "Person": [{"name": "name", "type": "string"}, {"name": "wallet", "type": "address"}]})").size(), 2); + EXPECT_EQ(ParamStruct::makeTypes(R"({"Mail": [{"name": "from", "type": "Person"}, {"name": "to", "type": "Person"}, {"name": "contents", "type": "string"}], "Person": [{"name": "name", "type": "string"}, {"name": "wallet", "type": "address"}]})").size(), 2ul); } } @@ -708,7 +708,7 @@ TEST(EthereumAbiStruct, ParamFactoryMakeType) { std::shared_ptr t = ParamStruct::makeType("Person", R"([{"name": "name", "type": "string"}, {"name": "wallet", "type": "address"}])"); EXPECT_NE(t.get(), nullptr); EXPECT_EQ(t->getType(), "Person"); - ASSERT_EQ(t->getCount(), 2); + ASSERT_EQ(t->getCount(), 2ul); ASSERT_EQ(t->encodeType(), "Person(string name,address wallet)"); } { // edge cases @@ -740,7 +740,7 @@ TEST(EthereumAbiStruct, ParamNamedMethods) { EXPECT_EQ(hex(encoded), "000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000"); size_t offset = 0; EXPECT_EQ(pn->decode(encoded, offset), true); - EXPECT_EQ(offset, 64); + EXPECT_EQ(offset, 64ul); pn->setValueJson("World"); EXPECT_EQ(ps->getVal(), "World"); } @@ -749,7 +749,7 @@ TEST(EthereumAbiStruct, ParamSetNamed) { const auto pn1 = std::make_shared("param1", std::make_shared("Hello")); const auto pn2 = std::make_shared("param2", std::make_shared("World")); auto ps = std::make_shared(std::vector>{pn1, pn2}); - EXPECT_EQ(ps->getCount(), 2); + EXPECT_EQ(ps->getCount(), 2ul); EXPECT_EQ(ps->addParam(std::shared_ptr(nullptr)), -1); EXPECT_EQ(ps->findParamByName("NO_SUCH_PARAM"), nullptr); auto pf1 = ps->findParamByName("param2"); @@ -762,14 +762,14 @@ TEST(EthereumAbiStruct, ParamStructMethods) { const auto pn2 = std::make_shared("param2", std::make_shared("World")); auto ps = std::make_shared("struct", std::vector>{pn1, pn2}); - EXPECT_EQ(ps->getSize(), 2); + EXPECT_EQ(ps->getSize(), 2ul); EXPECT_EQ(ps->isDynamic(), true); Data encoded; ps->encode(encoded); EXPECT_EQ(hex(encoded), ""); size_t offset = 0; EXPECT_EQ(ps->decode(encoded, offset), true); - EXPECT_EQ(offset, 0); + EXPECT_EQ(offset, 0ul); EXPECT_FALSE(ps->setValueJson("dummy")); EXPECT_EQ(ps->findParamByName("param2")->getName(), "param2"); } diff --git a/tests/Ethereum/AbiTests.cpp b/tests/Ethereum/AbiTests.cpp index 81e62b5fee1..7dbc0b708b6 100644 --- a/tests/Ethereum/AbiTests.cpp +++ b/tests/Ethereum/AbiTests.cpp @@ -63,7 +63,7 @@ TEST(EthereumAbi, ParamBool) { EXPECT_EQ("bool", param.getType()); EXPECT_FALSE(param.isDynamic()); - EXPECT_EQ(32, param.getSize()); + EXPECT_EQ(32ul, param.getSize()); } { auto param = ParamBool(false); @@ -94,7 +94,7 @@ TEST(EthereumAbi, ParamUInt8) { EXPECT_EQ("uint8", param.getType()); EXPECT_FALSE(param.isDynamic()); - EXPECT_EQ(32, param.getSize()); + EXPECT_EQ(32ul, param.getSize()); } { auto param = ParamUInt8(101); @@ -125,7 +125,7 @@ TEST(EthereumAbi, ParamUInt16) { EXPECT_EQ("uint16", param.getType()); EXPECT_FALSE(param.isDynamic()); - EXPECT_EQ(32, param.getSize()); + EXPECT_EQ(32ul, param.getSize()); } { auto param = ParamUInt16(101); @@ -150,13 +150,13 @@ TEST(EthereumAbi, ParamUInt16) { TEST(EthereumAbi, ParamUInt32) { { auto param = ParamUInt32(101); - EXPECT_EQ(101, param.getVal()); + EXPECT_EQ(101ul, param.getVal()); param.setVal(1234); - EXPECT_EQ(1234, param.getVal()); + EXPECT_EQ(1234ul, param.getVal()); EXPECT_EQ("uint32", param.getType()); EXPECT_FALSE(param.isDynamic()); - EXPECT_EQ(32, param.getSize()); + EXPECT_EQ(32ul, param.getSize()); } { auto param = ParamUInt32(101); @@ -165,7 +165,7 @@ TEST(EthereumAbi, ParamUInt32) { EXPECT_EQ("0000000000000000000000000000000000000000000000000000000000000065", hex(encoded)); size_t offset = 0; EXPECT_TRUE(param.decode(encoded, offset)); - EXPECT_EQ(101, param.getVal()); + EXPECT_EQ(101ul, param.getVal()); } { auto param = ParamUInt32(1234); @@ -174,20 +174,20 @@ TEST(EthereumAbi, ParamUInt32) { EXPECT_EQ("00000000000000000000000000000000000000000000000000000000000004d2", hex(encoded)); size_t offset = 0; EXPECT_TRUE(param.decode(encoded, offset)); - EXPECT_EQ(1234, param.getVal()); + EXPECT_EQ(1234ul, param.getVal()); } } TEST(EthereumAbi, ParamUInt64) { { auto param = ParamUInt64(101); - EXPECT_EQ(101, param.getVal()); + EXPECT_EQ(101ul, param.getVal()); param.setVal(1234); - EXPECT_EQ(1234, param.getVal()); + EXPECT_EQ(1234ul, param.getVal()); EXPECT_EQ("uint64", param.getType()); EXPECT_FALSE(param.isDynamic()); - EXPECT_EQ(32, param.getSize()); + EXPECT_EQ(32ul, param.getSize()); } { auto param = ParamUInt64(101); @@ -196,7 +196,7 @@ TEST(EthereumAbi, ParamUInt64) { EXPECT_EQ("0000000000000000000000000000000000000000000000000000000000000065", hex(encoded)); size_t offset = 0; EXPECT_TRUE(param.decode(encoded, offset)); - EXPECT_EQ(101, param.getVal()); + EXPECT_EQ(101ul, param.getVal()); } { auto param = ParamUInt64(1234); @@ -205,7 +205,7 @@ TEST(EthereumAbi, ParamUInt64) { EXPECT_EQ("00000000000000000000000000000000000000000000000000000000000004d2", hex(encoded)); size_t offset = 0; EXPECT_TRUE(param.decode(encoded, offset)); - EXPECT_EQ(1234, param.getVal()); + EXPECT_EQ(1234ul, param.getVal()); } } @@ -219,7 +219,7 @@ TEST(EthereumAbi, ParamUInt256) { EXPECT_EQ("uint256", param.getType()); EXPECT_FALSE(param.isDynamic()); - EXPECT_EQ(32, param.getSize()); + EXPECT_EQ(32ul, param.getSize()); } { auto param = ParamUInt256(uint256_t(101)); @@ -268,7 +268,7 @@ TEST(EthereumAbi, ParamUInt80) { EXPECT_EQ("uint80", param.getType()); EXPECT_FALSE(param.isDynamic()); - EXPECT_EQ(32, param.getSize()); + EXPECT_EQ(32ul, param.getSize()); // above number of bits, masked param.setVal(load(Data(parse_hex("1010101010101010101010101010101010101010101010101010101010101010")))); @@ -306,7 +306,7 @@ TEST(EthereumAbi, ParamInt80) { EXPECT_EQ("int80", param.getType()); EXPECT_FALSE(param.isDynamic()); - EXPECT_EQ(32, param.getSize()); + EXPECT_EQ(32ul, param.getSize()); param.setVal(int256_t(-101)); EXPECT_EQ(int256_t(-101), param.getVal()); @@ -362,7 +362,7 @@ TEST(EthereumAbi, ParamString) { EXPECT_EQ("string", param.getType()); EXPECT_TRUE(param.isDynamic()); - EXPECT_EQ(3 * 32, param.getSize()); + EXPECT_EQ(3 * 32ul, param.getSize()); } { auto param = ParamString(helloStr); @@ -373,8 +373,8 @@ TEST(EthereumAbi, ParamString) { "48656c6c6f20576f726c64212020202048656c6c6f20576f726c642120202020" "48656c6c6f20576f726c64210000000000000000000000000000000000000000", hex(encoded)); - EXPECT_EQ(3 * 32, encoded.size()); - EXPECT_EQ(3 * 32, param.getSize()); + EXPECT_EQ(3 * 32ul, encoded.size()); + EXPECT_EQ(3 * 32ul, param.getSize()); size_t offset = 0; EXPECT_TRUE(param.decode(encoded, offset)); EXPECT_EQ(helloStr, param.getVal()); @@ -390,7 +390,7 @@ TEST(EthereumAbi, ParamAddress) { EXPECT_EQ("address", param.getType()); EXPECT_FALSE(param.isDynamic()); - EXPECT_EQ(32, param.getSize()); + EXPECT_EQ(32ul, param.getSize()); } { auto param = ParamAddress(val1); @@ -425,20 +425,20 @@ TEST(EthereumAbi, ParamByteArray) { EXPECT_EQ("bytes", param.getType()); EXPECT_TRUE(param.isDynamic()); - EXPECT_EQ(2 * 32, param.getSize()); + EXPECT_EQ(2 * 32ul, param.getSize()); } { auto param = ParamByteArray(data10); Data encoded; param.encode(encoded); - EXPECT_EQ(2 * 32, encoded.size()); - EXPECT_EQ(2 * 32, param.getSize()); + EXPECT_EQ(2 * 32ul, encoded.size()); + EXPECT_EQ(2 * 32ul, param.getSize()); EXPECT_EQ( "000000000000000000000000000000000000000000000000000000000000000a" "3132333435363738393000000000000000000000000000000000000000000000", hex(encoded)); - EXPECT_EQ(2 * 32, encoded.size()); - EXPECT_EQ(2 * 32, param.getSize()); + EXPECT_EQ(2 * 32ul, encoded.size()); + EXPECT_EQ(2 * 32ul, param.getSize()); size_t offset = 0; EXPECT_TRUE(param.decode(encoded, offset)); EXPECT_EQ(data10, param.getVal()); @@ -453,14 +453,14 @@ TEST(EthereumAbi, ParamByteArrayFix) { EXPECT_EQ("bytes10", param.getType()); EXPECT_FALSE(param.isDynamic()); - EXPECT_EQ(32, param.getSize()); + EXPECT_EQ(32ul, param.getSize()); } { auto param = ParamByteArrayFix(10, data10); Data encoded; param.encode(encoded); - EXPECT_EQ(32, encoded.size()); - EXPECT_EQ(32, param.getSize()); + EXPECT_EQ(32ul, encoded.size()); + EXPECT_EQ(32ul, param.getSize()); EXPECT_EQ( "3132333435363738393000000000000000000000000000000000000000000000", hex(encoded)); @@ -476,14 +476,14 @@ TEST(EthereumAbi, ParamArrayByte) { param.addParam(std::make_shared(49)); param.addParam(std::make_shared(50)); param.addParam(std::make_shared(51)); - EXPECT_EQ(3, param.getVal().size()); + EXPECT_EQ(3ul, param.getVal().size()); EXPECT_EQ(49, (std::dynamic_pointer_cast(param.getVal()[0]))->getVal()); EXPECT_EQ(51, (std::dynamic_pointer_cast(param.getVal()[2]))->getVal()); EXPECT_EQ("uint8[]", param.getType()); EXPECT_TRUE(param.isDynamic()); - EXPECT_EQ((3 + 1) * 32, param.getSize()); - EXPECT_EQ(3, param.getCount()); + EXPECT_EQ((3 + 1) * 32ul, param.getSize()); + EXPECT_EQ(3ul, param.getCount()); } { auto param = ParamArray(); @@ -492,19 +492,19 @@ TEST(EthereumAbi, ParamArrayByte) { param.addParam(std::make_shared(51)); Data encoded; param.encode(encoded); - EXPECT_EQ(4 * 32, encoded.size()); - EXPECT_EQ(4 * 32, param.getSize()); + EXPECT_EQ(4 * 32ul, encoded.size()); + EXPECT_EQ(4 * 32ul, param.getSize()); EXPECT_EQ( "0000000000000000000000000000000000000000000000000000000000000003" "0000000000000000000000000000000000000000000000000000000000000031" "0000000000000000000000000000000000000000000000000000000000000032" "0000000000000000000000000000000000000000000000000000000000000033", hex(encoded)); - EXPECT_EQ(4 * 32, encoded.size()); - EXPECT_EQ(4 * 32, param.getSize()); + EXPECT_EQ(4 * 32ul, encoded.size()); + EXPECT_EQ(4 * 32ul, param.getSize()); size_t offset = 0; EXPECT_TRUE(param.decode(encoded, offset)); - EXPECT_EQ(3, param.getVal().size()); + EXPECT_EQ(3ul, param.getVal().size()); EXPECT_EQ(49, (std::dynamic_pointer_cast(param.getVal()[0]))->getVal()); EXPECT_EQ(51, (std::dynamic_pointer_cast(param.getVal()[2]))->getVal()); } @@ -514,11 +514,11 @@ TEST(EthereumAbi, ParamArrayEmpty) { auto param = ParamArray(); param.setProto(std::make_shared(0)); - EXPECT_EQ(0, param.getCount()); + EXPECT_EQ(0ul, param.getCount()); Data encoded; param.encode(encoded); - EXPECT_EQ(32, encoded.size()); - EXPECT_EQ(32, param.getSize()); + EXPECT_EQ(32ul, encoded.size()); + EXPECT_EQ(32ul, param.getSize()); EXPECT_EQ( "0000000000000000000000000000000000000000000000000000000000000000", hex(encoded)); @@ -531,12 +531,12 @@ TEST(EthereumAbi, ParamArrayAddress) { auto param = ParamArray(); param.addParam(std::make_shared(Data(parse_hex("f784682c82526e245f50975190ef0fff4e4fc077")))); param.addParam(std::make_shared(Data(parse_hex("2e00cd222cb42b616d86d037cc494e8ab7f5c9a3")))); - EXPECT_EQ(2, param.getVal().size()); + EXPECT_EQ(2ul, param.getVal().size()); EXPECT_EQ("address[]", param.getType()); EXPECT_TRUE(param.isDynamic()); - EXPECT_EQ((2 + 1) * 32, param.getSize()); - EXPECT_EQ(2, param.getCount()); + EXPECT_EQ((2 + 1) * 32ul, param.getSize()); + EXPECT_EQ(2ul, param.getCount()); } { auto param = ParamArray(); @@ -544,19 +544,19 @@ TEST(EthereumAbi, ParamArrayAddress) { param.addParam(std::make_shared(Data(parse_hex("2e00cd222cb42b616d86d037cc494e8ab7f5c9a3")))); Data encoded; param.encode(encoded); - EXPECT_EQ(3 * 32, encoded.size()); - EXPECT_EQ(3 * 32, param.getSize()); + EXPECT_EQ(3 * 32ul, encoded.size()); + EXPECT_EQ(3 * 32ul, param.getSize()); EXPECT_EQ( "0000000000000000000000000000000000000000000000000000000000000002" "000000000000000000000000f784682c82526e245f50975190ef0fff4e4fc077" "0000000000000000000000002e00cd222cb42b616d86d037cc494e8ab7f5c9a3", hex(encoded)); - EXPECT_EQ(3 * 32, encoded.size()); - EXPECT_EQ(3 * 32, param.getSize()); + EXPECT_EQ(3 * 32ul, encoded.size()); + EXPECT_EQ(3 * 32ul, param.getSize()); size_t offset = 0; EXPECT_TRUE(param.decode(encoded, offset)); - EXPECT_EQ(2, param.getCount()); - EXPECT_EQ(2, param.getVal().size()); + EXPECT_EQ(2ul, param.getCount()); + EXPECT_EQ(2ul, param.getVal().size()); EXPECT_EQ( "2e00cd222cb42b616d86d037cc494e8ab7f5c9a3", hex((std::dynamic_pointer_cast(param.getVal()[1]))->getData())); @@ -568,12 +568,12 @@ TEST(EthereumAbi, ParamArrayOfByteArray) { param.addParam(std::make_shared(parse_hex("1011"))); param.addParam(std::make_shared(parse_hex("102222"))); param.addParam(std::make_shared(parse_hex("10333333"))); - EXPECT_EQ(3, param.getVal().size()); + EXPECT_EQ(3ul, param.getVal().size()); EXPECT_EQ("bytes[]", param.getType()); EXPECT_TRUE(param.isDynamic()); - EXPECT_EQ((1 + 3 + 3 * 2) * 32, param.getSize()); - EXPECT_EQ(3, param.getCount()); + EXPECT_EQ((1 + 3 + 3 * 2) * 32ul, param.getSize()); + EXPECT_EQ(3ul, param.getCount()); } TEST(EthereumAbi, ParamArrayBytesContract) { @@ -582,17 +582,17 @@ TEST(EthereumAbi, ParamArrayBytesContract) { param.addParam(std::make_shared(parse_hex("0x304e6adee71cd96d4ba1c4b512b0c5bee30d2b6becf61e574c32a17a67156fa9ed3c4c6f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000"))); param.addParam(std::make_shared(parse_hex("0x8b95dd71e71cd96d4ba1c4b512b0c5bee30d2b6becf61e574c32a17a67156fa9ed3c4c6f000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001447331175b23c2f067204b506ca1501c26731c990000000000000000000000000"))); param.addParam(std::make_shared(parse_hex("0x8b95dd71e71cd96d4ba1c4b512b0c5bee30d2b6becf61e574c32a17a67156fa9ed3c4c6f00000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000014d30f834b53d8f7e851e87b90ffa65757a35b8505000000000000000000000000"))); - EXPECT_EQ(4, param.getCount()); - EXPECT_EQ(4, param.getVal().size()); + EXPECT_EQ(4ul, param.getCount()); + EXPECT_EQ(4ul, param.getVal().size()); EXPECT_EQ("bytes[]", param.getType()); EXPECT_TRUE(param.isDynamic()); Data encoded; param.encode(encoded); - EXPECT_EQ(896, encoded.size()); + EXPECT_EQ(896ul, encoded.size()); - EXPECT_EQ(896, param.getSize()); + EXPECT_EQ(896ul, param.getSize()); } TEST(EthereumAbi, ParamTupleStatic) { @@ -602,8 +602,8 @@ TEST(EthereumAbi, ParamTupleStatic) { param.addParam(std::make_shared(123)); EXPECT_EQ("(bool,uint64)", param.getType()); EXPECT_FALSE(param.isDynamic()); - EXPECT_EQ(2, param.getCount()); - EXPECT_EQ(64, param.getSize()); + EXPECT_EQ(2ul, param.getCount()); + EXPECT_EQ(64ul, param.getSize()); Data encoded; param.encode(encoded); EXPECT_EQ("0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000007b", hex(encoded)); @@ -613,7 +613,7 @@ TEST(EthereumAbi, ParamTupleStatic) { param2.addParam(std::make_shared()); param2.addParam(std::make_shared()); EXPECT_TRUE(param2.decode(encoded, offset)); - EXPECT_EQ(2, param2.getCount()); + EXPECT_EQ(2ul, param2.getCount()); Data encoded2; param2.encode(encoded2); EXPECT_EQ("0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000007b", hex(encoded)); @@ -625,8 +625,8 @@ TEST(EthereumAbi, ParamTupleStatic) { param.addParam(std::make_shared(parse_hex("000102030405060708090a0b0c0d0e0f10111213"))); EXPECT_EQ("(uint64,address)", param.getType()); EXPECT_FALSE(param.isDynamic()); - EXPECT_EQ(2, param.getCount()); - EXPECT_EQ(64, param.getSize()); + EXPECT_EQ(2ul, param.getCount()); + EXPECT_EQ(64ul, param.getSize()); Data encoded; param.encode(encoded); EXPECT_EQ("00000000000000000000000000000000000000000000000000000000000001c8000000000000000000000000000102030405060708090a0b0c0d0e0f10111213", hex(encoded)); @@ -641,8 +641,8 @@ TEST(EthereumAbi, ParamTupleDynamic) { param.addParam(std::make_shared(parse_hex("00010203040506070809"))); EXPECT_EQ("(string,uint64,bytes)", param.getType()); EXPECT_TRUE(param.isDynamic()); - EXPECT_EQ(3, param.getCount()); - EXPECT_EQ(7 * 32, param.getSize()); + EXPECT_EQ(3ul, param.getCount()); + EXPECT_EQ(7 * 32ul, param.getSize()); Data encoded; param.encode(encoded); EXPECT_EQ( @@ -694,8 +694,8 @@ TEST(EthereumAbi, EncodeArrayByte) { "1022220000000000000000000000000000000000000000000000000000000000", hex(encoded) ); - EXPECT_EQ((1 + 2 + 2 * 2) * 32, encoded.size()); - EXPECT_EQ((1 + 2 + 2 * 2) * 32, p.getSize()); + EXPECT_EQ((1 + 2 + 2 * 2) * 32ul, encoded.size()); + EXPECT_EQ((1 + 2 + 2 * 2) * 32ul, p.getSize()); } TEST(EthereumAbi, DecodeUInt) { @@ -705,7 +705,7 @@ TEST(EthereumAbi, DecodeUInt) { bool res = ParamNumberType::decodeNumber(encoded, decoded, offset); EXPECT_TRUE(res); EXPECT_EQ(uint256_t(42), decoded); - EXPECT_EQ(32, offset); + EXPECT_EQ(32ul, offset); } TEST(EthereumAbi, DecodeUInt8) { @@ -715,7 +715,7 @@ TEST(EthereumAbi, DecodeUInt8) { bool res = ParamNumberType::decodeNumber(encoded, decoded, offset); EXPECT_TRUE(res); EXPECT_EQ(24, decoded); - EXPECT_EQ(32, offset); + EXPECT_EQ(32ul, offset); } TEST(EthereumAbi, DecodeUInt8WithOffset) { @@ -725,7 +725,7 @@ TEST(EthereumAbi, DecodeUInt8WithOffset) { bool res = ParamNumberType::decodeNumber(encoded, decoded, offset); EXPECT_TRUE(res); EXPECT_EQ(24, decoded); - EXPECT_EQ(3 + 32, offset); + EXPECT_EQ(3 + 32ul, offset); } TEST(EthereumAbi, DecodeUIntWithOffset) { @@ -735,7 +735,7 @@ TEST(EthereumAbi, DecodeUIntWithOffset) { bool res = decode(encoded, decoded, offset); EXPECT_TRUE(res); EXPECT_EQ(uint256_t(42), decoded); - EXPECT_EQ(3 + 32, offset); + EXPECT_EQ(3 + 32ul, offset); } TEST(EthereumAbi, DecodeUIntErrorTooShort) { @@ -745,7 +745,7 @@ TEST(EthereumAbi, DecodeUIntErrorTooShort) { bool res = decode(encoded, decoded, offset); EXPECT_FALSE(res); EXPECT_EQ(uint256_t(0), decoded); - EXPECT_EQ(0, offset); + EXPECT_EQ(0ul, offset); } TEST(EthereumAbi, DecodeArrayUint) { @@ -756,12 +756,12 @@ TEST(EthereumAbi, DecodeArrayUint) { std::vector decoded; bool res = ParamByteArray::decodeBytes(encoded, decoded, offset); EXPECT_TRUE(res); - EXPECT_EQ(10, decoded.size()); + EXPECT_EQ(10ul, decoded.size()); if (decoded.size() >= 2) { EXPECT_EQ(49u, decoded[0]); EXPECT_EQ(50u, decoded[1]); } - EXPECT_EQ(32 + 32, offset); + EXPECT_EQ(32 + 32ul, offset); } TEST(EthereumAbi, DecodeArrayTooShort) { @@ -791,7 +791,7 @@ TEST(EthereumAbi, DecodeByteArray) { bool res = ParamByteArray::decodeBytes(encoded, decoded, offset); EXPECT_TRUE(res); EXPECT_EQ("31323334353637383930", hex(decoded)); - EXPECT_EQ(32 + 32, offset); + EXPECT_EQ(32 + 32ul, offset); } TEST(EthereumAbi, DecodeByteArray10) { @@ -800,10 +800,10 @@ TEST(EthereumAbi, DecodeByteArray10) { Data decoded; bool res = ParamByteArrayFix::decodeBytesFix(encoded, 10, decoded, offset); EXPECT_TRUE(res); - EXPECT_EQ(10, decoded.size()); + EXPECT_EQ(10ul, decoded.size()); EXPECT_EQ(49u, decoded[0]); EXPECT_EQ(50u, decoded[1]); - EXPECT_EQ(32, offset); + EXPECT_EQ(32ul, offset); } TEST(EthereumAbi, DecodeArrayOfByteArray) { @@ -823,9 +823,9 @@ TEST(EthereumAbi, DecodeArrayOfByteArray) { param.addParam(std::make_shared(Data())); bool res = param.decode(encoded, offset); EXPECT_TRUE(res); - EXPECT_EQ(2, param.getCount()); - EXPECT_EQ(7 * 32, offset); - EXPECT_EQ(2, param.getVal().size()); + EXPECT_EQ(2ul, param.getCount()); + EXPECT_EQ(7 * 32ul, offset); + EXPECT_EQ(2ul, param.getVal().size()); } ///// Parameters encode & decode @@ -839,8 +839,8 @@ TEST(EthereumAbi, EncodeParamsSimple) { Data encoded; p.encode(encoded); - EXPECT_EQ(3 * 32, encoded.size()); - EXPECT_EQ(3 * 32, p.getSize()); + EXPECT_EQ(3 * 32ul, encoded.size()); + EXPECT_EQ(3 * 32ul, p.getSize()); EXPECT_EQ( "0000000000000000000000000000000000000000000000000000000000000010" "0000000000000000000000000000000000000000000000000000000000000011" @@ -864,8 +864,8 @@ TEST(EthereumAbi, EncodeParamsMixed) { Data encoded; p.encode(encoded); - EXPECT_EQ(13 * 32, encoded.size()); - EXPECT_EQ(13 * 32, p.getSize()); + EXPECT_EQ(13 * 32ul, encoded.size()); + EXPECT_EQ(13 * 32ul, p.getSize()); EXPECT_EQ( "0000000000000000000000000000000000000000000000000000000000000045" "00000000000000000000000000000000000000000000000000000000000000a0" @@ -916,7 +916,7 @@ TEST(EthereumAbi, DecodeParamsSimple) { EXPECT_EQ(uint256_t(16u), (std::dynamic_pointer_cast(p.getParam(0)))->getVal()); EXPECT_EQ(uint256_t(17u), (std::dynamic_pointer_cast(p.getParam(1)))->getVal()); EXPECT_EQ(true, (std::dynamic_pointer_cast(p.getParam(2)))->getVal()); - EXPECT_EQ(3 * 32, offset); + EXPECT_EQ(3 * 32ul, offset); } TEST(EthereumAbi, DecodeParamsMixed) { @@ -950,12 +950,12 @@ TEST(EthereumAbi, DecodeParamsMixed) { bool res = p.decode(encoded, offset); EXPECT_TRUE(res); EXPECT_EQ(uint256_t(69u), (std::dynamic_pointer_cast(p.getParam(0)))->getVal()); - EXPECT_EQ(3, (std::dynamic_pointer_cast(p.getParam(1)))->getCount()); + EXPECT_EQ(3ul, (std::dynamic_pointer_cast(p.getParam(1)))->getCount()); EXPECT_EQ(1, (std::dynamic_pointer_cast((std::dynamic_pointer_cast(p.getParam(1)))->getParam(0)))->getVal()); EXPECT_EQ(3, (std::dynamic_pointer_cast((std::dynamic_pointer_cast(p.getParam(1)))->getParam(2)))->getVal()); EXPECT_EQ(true, (std::dynamic_pointer_cast(p.getParam(2)))->getVal()); EXPECT_EQ("Hello", (std::dynamic_pointer_cast(p.getParam(3)))->getVal()); - EXPECT_EQ(13 * 32, offset); + EXPECT_EQ(13 * 32ul, offset); } ///// Function encode & decode @@ -969,7 +969,7 @@ TEST(EthereumAbi, EncodeSignature) { Data encoded; func.encode(encoded); - EXPECT_EQ(encoded.size(), 32 * 2 + 4); + EXPECT_EQ(encoded.size(), 32 * 2 + 4ul); EXPECT_EQ(hex(encoded.begin(), encoded.begin() + 4), "72ed38b6"); EXPECT_EQ(hex(encoded.begin() + 4, encoded.begin() + 36 ), "0000000000000000000000000000000000000000000000000000000000000045"); EXPECT_EQ(hex(encoded.begin() + 36, encoded.begin() + 68 ), "0000000000000000000000000000000000000000000000000000000000000001"); @@ -989,7 +989,7 @@ TEST(EthereumAbi, EncodeFunctionWithDynamicArgumentsCase1) { Data encoded; func.encode(encoded); - EXPECT_EQ(encoded.size(), 32 * 9 + 4); + EXPECT_EQ(encoded.size(), 32 * 9 + 4ul); EXPECT_EQ(hex(encoded.begin() + 0, encoded.begin() + 4 ), "a5643bf2"); EXPECT_EQ(hex(encoded.begin() + 4, encoded.begin() + 36 ), "0000000000000000000000000000000000000000000000000000000000000060"); EXPECT_EQ(hex(encoded.begin() + 36, encoded.begin() + 68 ), "0000000000000000000000000000000000000000000000000000000000000001"); @@ -1016,7 +1016,7 @@ TEST(EthereumAbi, EncodeFunctionWithDynamicArgumentsCase2) { Data encoded; func.encode(encoded); - EXPECT_EQ(encoded.size(), 32 * 9 + 4); + EXPECT_EQ(encoded.size(), 32 * 9 + 4ul); EXPECT_EQ(hex(encoded.begin() + 0, encoded.begin() + 4 ), "47b941bf"); EXPECT_EQ(hex(encoded.begin() + 4, encoded.begin() + 36 ), "0000000000000000000000000000000000000000000000000000000000000123"); EXPECT_EQ(hex(encoded.begin() + 36, encoded.begin() + 68 ), "0000000000000000000000000000000000000000000000000000000000000080"); @@ -1043,15 +1043,15 @@ TEST(EthereumAbi, DecodeFunctionOutputCase1) { // original output value std::shared_ptr param; EXPECT_TRUE(func.getOutParam(0, param)); - EXPECT_EQ(0, (std::dynamic_pointer_cast(param))->getVal()); + EXPECT_EQ(0ul, (std::dynamic_pointer_cast(param))->getVal()); size_t offset = 0; bool res = func.decodeOutput(encoded, offset); EXPECT_TRUE(res); - EXPECT_EQ(32, offset); + EXPECT_EQ(32ul, offset); // new output value - EXPECT_EQ(0x45, (std::dynamic_pointer_cast(param))->getVal()); + EXPECT_EQ(0x45ul, (std::dynamic_pointer_cast(param))->getVal()); } TEST(EthereumAbi, DecodeFunctionOutputCase2) { @@ -1075,12 +1075,12 @@ TEST(EthereumAbi, DecodeFunctionOutputCase2) { size_t offset = 0; bool res = func.decodeOutput(encoded, offset); EXPECT_TRUE(res); - EXPECT_EQ(128, offset); + EXPECT_EQ(128ul, offset); // new output values std::shared_ptr param; EXPECT_TRUE(func.getOutParam(0, param)); - EXPECT_EQ(2, (std::dynamic_pointer_cast(param))->getCount()); + EXPECT_EQ(2ul, (std::dynamic_pointer_cast(param))->getCount()); EXPECT_EQ(4, (std::dynamic_pointer_cast((std::dynamic_pointer_cast(param))->getParam(0)))->getVal()); EXPECT_EQ(5, (std::dynamic_pointer_cast((std::dynamic_pointer_cast(param))->getParam(1)))->getVal()); } @@ -1102,7 +1102,7 @@ TEST(EthereumAbi, DecodeInputSignature) { EXPECT_EQ(69u, (std::dynamic_pointer_cast(param))->getVal()); EXPECT_TRUE(func.getInParam(1, param)); EXPECT_EQ(true, (std::dynamic_pointer_cast(param))->getVal()); - EXPECT_EQ(4 + 2 * 32, offset); + EXPECT_EQ(4 + 2 * 32ul, offset); } TEST(EthereumAbi, DecodeFunctionInputWithDynamicArgumentsCase1) { @@ -1134,16 +1134,16 @@ TEST(EthereumAbi, DecodeFunctionInputWithDynamicArgumentsCase1) { EXPECT_TRUE(res); std::shared_ptr param; EXPECT_TRUE(func.getInParam(0, param)); - EXPECT_EQ(4, (std::dynamic_pointer_cast(param))->getCount()); + EXPECT_EQ(4ul, (std::dynamic_pointer_cast(param))->getCount()); EXPECT_EQ(0x64, (std::dynamic_pointer_cast(param))->getVal()[0]); EXPECT_EQ(0x65, (std::dynamic_pointer_cast(param))->getVal()[3]); EXPECT_TRUE(func.getInParam(1, param)); EXPECT_EQ(true, (std::dynamic_pointer_cast(param))->getVal()); EXPECT_TRUE(func.getInParam(2, param)); - EXPECT_EQ(3, (std::dynamic_pointer_cast(param))->getCount()); + EXPECT_EQ(3ul, (std::dynamic_pointer_cast(param))->getCount()); EXPECT_EQ(uint256_t(1), (std::dynamic_pointer_cast((std::dynamic_pointer_cast(param))->getVal()[0]))->getVal()); EXPECT_EQ(uint256_t(3), (std::dynamic_pointer_cast((std::dynamic_pointer_cast(param))->getVal()[2]))->getVal()); - EXPECT_EQ(4 + 9 * 32, offset); + EXPECT_EQ(4 + 9 * 32ul, offset); } TEST(EthereumAbi, DecodeFunctionInputWithDynamicArgumentsCase2) { @@ -1177,15 +1177,15 @@ TEST(EthereumAbi, DecodeFunctionInputWithDynamicArgumentsCase2) { EXPECT_TRUE(func.getInParam(0, param)); EXPECT_EQ(uint256_t(0x123), (std::dynamic_pointer_cast(param))->getVal()); EXPECT_TRUE(func.getInParam(1, param)); - EXPECT_EQ(2, (std::dynamic_pointer_cast(param))->getCount()); - EXPECT_EQ(0x456, (std::dynamic_pointer_cast((std::dynamic_pointer_cast(param))->getVal()[0]))->getVal()); - EXPECT_EQ(0x789, (std::dynamic_pointer_cast((std::dynamic_pointer_cast(param))->getVal()[1]))->getVal()); + EXPECT_EQ(2ul, (std::dynamic_pointer_cast(param))->getCount()); + EXPECT_EQ(0x456ul, (std::dynamic_pointer_cast((std::dynamic_pointer_cast(param))->getVal()[0]))->getVal()); + EXPECT_EQ(0x789ul, (std::dynamic_pointer_cast((std::dynamic_pointer_cast(param))->getVal()[1]))->getVal()); EXPECT_TRUE(func.getInParam(2, param)); - EXPECT_EQ(10, (std::dynamic_pointer_cast(param))->getCount()); + EXPECT_EQ(10ul, (std::dynamic_pointer_cast(param))->getCount()); EXPECT_EQ("31323334353637383930", hex((std::dynamic_pointer_cast(param))->getVal())); EXPECT_TRUE(func.getInParam(3, param)); EXPECT_EQ(std::string("Hello, world!"), (std::dynamic_pointer_cast(param))->getVal()); - EXPECT_EQ(4 + 9 * 32, offset); + EXPECT_EQ(4 + 9 * 32ul, offset); } TEST(EthereumAbi, DecodeFunctionContractMulticall) { @@ -1211,7 +1211,7 @@ TEST(EthereumAbi, DecodeFunctionContractMulticall) { "000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000" "000000000000000000000000000000000014d30f834b53d8f7e851e87b90ffa65757a35b850500000000000000" "000000000000000000000000000000000000000000000000000000000000000000"); - ASSERT_EQ(4 + 928, encoded.size()); + ASSERT_EQ(4 + 928ul, encoded.size()); auto func = Function("multicall", std::vector>{ std::make_shared(std::vector>{ @@ -1226,7 +1226,7 @@ TEST(EthereumAbi, DecodeFunctionContractMulticall) { size_t offset = 0; bool res = func.decodeInput(encoded, offset); EXPECT_TRUE(res); - EXPECT_EQ(4 + 29 * 32, offset); + EXPECT_EQ(4 + 29 * 32ul, offset); } TEST(EthereumAbi, ParamFactoryMake) { @@ -1294,18 +1294,18 @@ TEST(EthereumAbi, ParamFactoryGetArrayValue) { { auto pArray = std::make_shared(std::make_shared()); const auto vals = ParamFactory::getArrayValue(pArray, pArray->getType()); - ASSERT_EQ(vals.size(), 1); + ASSERT_EQ(vals.size(), 1ul); EXPECT_EQ(vals[0], "0"); } { // wrong type, not array auto pArray = std::make_shared(std::make_shared()); const auto vals = ParamFactory::getArrayValue(pArray, "bool"); - EXPECT_EQ(vals.size(), 0); + EXPECT_EQ(vals.size(), 0ul); } { // wrong param, not array auto pArray = std::make_shared(); const auto vals = ParamFactory::getArrayValue(pArray, "uint8[]"); - EXPECT_EQ(vals.size(), 0); + EXPECT_EQ(vals.size(), 0ul); } } @@ -1457,7 +1457,7 @@ TEST(EthereumAbi, ParamFactorySetGetValue) { EXPECT_EQ("", ParamFactory::getValue(p, p->getType())); EXPECT_TRUE(p->setValueJson("ABCdefGHI")); EXPECT_EQ("ABCdefGHI", ParamFactory::getValue(p, p->getType())); - EXPECT_EQ(9, p->getCount()); + EXPECT_EQ(9ul, p->getCount()); } { auto p = std::make_shared(); @@ -1550,7 +1550,7 @@ TEST(EthereumAbi, ParamSetMethods) { auto p = ParamSet(std::vector>{ std::make_shared(16u), std::make_shared(true) }); - EXPECT_EQ(p.getCount(), 2); + EXPECT_EQ(p.getCount(), 2ul); EXPECT_EQ(p.addParam(std::shared_ptr(nullptr)), -1); std::shared_ptr getparam; @@ -1574,7 +1574,7 @@ TEST(EthereumAbi, ParametersMethods) { std::make_shared(16u), std::make_shared(true) }); EXPECT_TRUE(p.isDynamic()); - EXPECT_EQ(p.getCount(), 2); + EXPECT_EQ(p.getCount(), 2ul); EXPECT_FALSE(p.setValueJson("value")); EXPECT_EQ(hex(p.hashStruct()), "755311b9e2cee471a91b161ccc5deed933d844b5af2b885543cc3c04eb640983"); } diff --git a/tests/Ethereum/ContractCallTests.cpp b/tests/Ethereum/ContractCallTests.cpp index f7e27e1e634..22461161e54 100644 --- a/tests/Ethereum/ContractCallTests.cpp +++ b/tests/Ethereum/ContractCallTests.cpp @@ -153,7 +153,7 @@ TEST(ContractCall, Multicall) { "000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000" "000000000000000000000000000000000014d30f834b53d8f7e851e87b90ffa65757a35b850500000000000000" "000000000000000000000000000000000000000000000000000000000000000000"); - ASSERT_EQ(4 + 928, call.size()); + ASSERT_EQ(4 + 928ul, call.size()); auto path = TESTS_ROOT + "/Ethereum/Data/ens.json"; auto abi = load_json(path); auto decoded = decodeCall(call, abi); diff --git a/tests/Ethereum/RLPTests.cpp b/tests/Ethereum/RLPTests.cpp index ed8dd1181c4..34e76bf6cc8 100644 --- a/tests/Ethereum/RLPTests.cpp +++ b/tests/Ethereum/RLPTests.cpp @@ -205,9 +205,9 @@ TEST(RLP, DecodeList) { { // long list, with 2-byte size const std::string elem = "0123"; - const int n = 500; + const std::size_t n = 500; std::vector longarr; - for (auto i = 0; i < n; ++i) longarr.push_back(elem); + for (auto i = 0ul; i < n; ++i) longarr.push_back(elem); const Data encoded = RLP::encodeList(longarr); ASSERT_EQ(hex(subData(encoded, 0, 20)), "f909c48430313233843031323384303132338430"); @@ -221,12 +221,12 @@ TEST(RLP, DecodeList) { { // long list, with 3-byte size const std::string elem = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; - const int n = 650; + const std::size_t n = 650; std::vector longarr; - for (auto i = 0; i < n; ++i) longarr.push_back(elem); + for (auto i = 0ul; i < n; ++i) longarr.push_back(elem); const Data encoded = RLP::encodeList(longarr); - ASSERT_EQ(encoded.size(), 66304); + ASSERT_EQ(encoded.size(), 66304ul); ASSERT_EQ(hex(subData(encoded, 0, 30)), "fa0102fcb864303132333435363738393031323334353637383930313233"); auto decoded = RLP::decode(encoded); diff --git a/tests/Ethereum/TWAnySignerTests.cpp b/tests/Ethereum/TWAnySignerTests.cpp index b57e9b26232..f822ae9e888 100644 --- a/tests/Ethereum/TWAnySignerTests.cpp +++ b/tests/Ethereum/TWAnySignerTests.cpp @@ -314,7 +314,7 @@ TEST(TWAnySignerEthereum, PlanNotSupported) { auto inputData = input.SerializeAsString(); auto inputTWData = WRAPD(TWDataCreateWithBytes((const uint8_t *)inputData.data(), inputData.size())); auto outputTWData = WRAPD(TWAnySignerPlan(inputTWData.get(), TWCoinTypeEthereum)); - EXPECT_EQ(TWDataSize(outputTWData.get()), 0); + EXPECT_EQ(TWDataSize(outputTWData.get()), 0ul); } TEST(TWAnySignerEthereum, SignERC1559Transfer_1442) { diff --git a/tests/Ethereum/TWEthereumAbiTests.cpp b/tests/Ethereum/TWEthereumAbiTests.cpp index f64d3886540..be8a59d4731 100644 --- a/tests/Ethereum/TWEthereumAbiTests.cpp +++ b/tests/Ethereum/TWEthereumAbiTests.cpp @@ -41,7 +41,7 @@ TEST(TWEthereumAbi, FuncCreate1) { EXPECT_EQ(0, p2index); // check back get value auto p2val2 = TWEthereumAbiFunctionGetParamUInt64(func, p2index, true); - EXPECT_EQ(9, p2val2); + EXPECT_EQ(9ul, p2val2); auto type = WRAPS(TWEthereumAbiFunctionGetType(func)); std::string type2 = TWStringUTF8Bytes(type.get()); @@ -187,7 +187,7 @@ TEST(TWEthereumAbi, EncodeFuncMonster) { // check back out params EXPECT_EQ(1, TWEthereumAbiFunctionGetParamUInt8(func, 0, false)); - EXPECT_EQ(4, TWEthereumAbiFunctionGetParamUInt64(func, 3, false)); + EXPECT_EQ(4ul, TWEthereumAbiFunctionGetParamUInt64(func, 3, false)); EXPECT_EQ(true, TWEthereumAbiFunctionGetParamBool(func, 12, false)); EXPECT_EQ(std::string("Hello, world!"), std::string(TWStringUTF8Bytes(WRAPS(TWEthereumAbiFunctionGetParamString(func, 13, false)).get()))); WRAPD(TWEthereumAbiFunctionGetParamAddress(func, 14, false)); @@ -200,7 +200,7 @@ TEST(TWEthereumAbi, EncodeFuncMonster) { auto encoded = WRAPD(TWEthereumAbiEncode(func)); Data enc2 = data(TWDataBytes(encoded.get()), TWDataSize(encoded.get())); - EXPECT_EQ(4 + 76 * 32, enc2.size()); + EXPECT_EQ(4ul + 76 * 32, enc2.size()); // delete TWEthereumAbiFunctionDelete(func); @@ -216,14 +216,14 @@ TEST(TWEthereumAbi, DecodeOutputFuncCase1) { EXPECT_EQ(0, TWEthereumAbiFunctionAddParamUInt64(func, 0, true)); // original output value - EXPECT_EQ(0, TWEthereumAbiFunctionGetParamUInt64(func, 0, true)); + EXPECT_EQ(0ul, TWEthereumAbiFunctionGetParamUInt64(func, 0, true)); // decode auto encoded = WRAPD(TWDataCreateWithHexString(WRAPS(TWStringCreateWithUTF8Bytes("0000000000000000000000000000000000000000000000000000000000000045")).get())); EXPECT_EQ(true, TWEthereumAbiDecodeOutput(func, encoded.get())); // new output value - EXPECT_EQ(0x45, TWEthereumAbiFunctionGetParamUInt64(func, 0, true)); + EXPECT_EQ(0x45ul, TWEthereumAbiFunctionGetParamUInt64(func, 0, true)); // delete TWEthereumAbiFunctionDelete(func); @@ -238,11 +238,11 @@ TEST(TWEthereumAbi, GetParamWrongType) { // GetParameter with correct types EXPECT_EQ(1, TWEthereumAbiFunctionGetParamUInt8(func, 0, true)); - EXPECT_EQ(2, TWEthereumAbiFunctionGetParamUInt64(func, 1, true)); + EXPECT_EQ(2ul, TWEthereumAbiFunctionGetParamUInt64(func, 1, true)); // GetParameter with wrong type, default value (0) is returned EXPECT_EQ(0, TWEthereumAbiFunctionGetParamUInt8(func, 1, true)); - EXPECT_EQ(0, TWEthereumAbiFunctionGetParamUInt64(func, 0, true)); + EXPECT_EQ(0ul, TWEthereumAbiFunctionGetParamUInt64(func, 0, true)); EXPECT_EQ("00", hex(*(static_cast(WRAPD(TWEthereumAbiFunctionGetParamUInt256(func, 0, true)).get())))); EXPECT_EQ(false, TWEthereumAbiFunctionGetParamBool(func, 0, true)); EXPECT_EQ("", std::string(TWStringUTF8Bytes(WRAPS(TWEthereumAbiFunctionGetParamString(func, 0, true)).get()))); @@ -250,7 +250,7 @@ TEST(TWEthereumAbi, GetParamWrongType) { // GetParameter with wrong index, default value (0) is returned EXPECT_EQ(0, TWEthereumAbiFunctionGetParamUInt8(func, 99, true)); - EXPECT_EQ(0, TWEthereumAbiFunctionGetParamUInt64(func, 99, true)); + EXPECT_EQ(0ul, TWEthereumAbiFunctionGetParamUInt64(func, 99, true)); EXPECT_EQ("00", hex(*(static_cast(WRAPD(TWEthereumAbiFunctionGetParamUInt256(func, 99, true)).get())))); EXPECT_EQ(false, TWEthereumAbiFunctionGetParamBool(func, 99, true)); EXPECT_EQ("", std::string(TWStringUTF8Bytes(WRAPS(TWEthereumAbiFunctionGetParamString(func, 99, true)).get()))); diff --git a/tests/Ethereum/ValueDecoderTests.cpp b/tests/Ethereum/ValueDecoderTests.cpp index 78d52a80f4c..fa459be1dcc 100644 --- a/tests/Ethereum/ValueDecoderTests.cpp +++ b/tests/Ethereum/ValueDecoderTests.cpp @@ -50,7 +50,7 @@ TEST(EthereumAbiValueDecoder, decodeArray) { "0000000000000000000000000000000000000000000000000000000000000033" ); auto res = ABI::ValueDecoder::decodeArray(input, "uint8[]"); - EXPECT_EQ(3, res.size()); + EXPECT_EQ(3ul, res.size()); EXPECT_EQ("49", res[0]); EXPECT_EQ("50", res[1]); EXPECT_EQ("51", res[2]); @@ -63,7 +63,7 @@ TEST(EthereumAbiValueDecoder, decodeArray) { "0000000000000000000000002e00cd222cb42b616d86d037cc494e8ab7f5c9a3" ); auto res = ABI::ValueDecoder::decodeArray(input, "address[]"); - EXPECT_EQ(2, res.size()); + EXPECT_EQ(2ul, res.size()); EXPECT_EQ("0xf784682c82526e245f50975190ef0fff4e4fc077", res[0]); EXPECT_EQ("0x2e00cd222cb42b616d86d037cc494e8ab7f5c9a3", res[1]); } @@ -79,7 +79,7 @@ TEST(EthereumAbiValueDecoder, decodeArray) { "1022220000000000000000000000000000000000000000000000000000000000" ); auto res = ABI::ValueDecoder::decodeArray(input, "bytes[]"); - EXPECT_EQ(2, res.size()); + EXPECT_EQ(2ul, res.size()); EXPECT_EQ("0x1011", res[0]); EXPECT_EQ("0x102222", res[1]); } diff --git a/tests/Ethereum/ValueEncoderTests.cpp b/tests/Ethereum/ValueEncoderTests.cpp index bc6f8fd22a5..28a663aef58 100644 --- a/tests/Ethereum/ValueEncoderTests.cpp +++ b/tests/Ethereum/ValueEncoderTests.cpp @@ -121,16 +121,16 @@ TEST(EthereumAbiValueEncoder, uint256FromInt256) { } TEST(EthereumAbiValueEncoder, pad32) { - EXPECT_EQ(64, ABI::ValueEncoder::paddedTo32(40)); - EXPECT_EQ(32, ABI::ValueEncoder::paddedTo32(32)); - EXPECT_EQ(64, ABI::ValueEncoder::paddedTo32(33)); - EXPECT_EQ(64, ABI::ValueEncoder::paddedTo32(63)); - EXPECT_EQ(64, ABI::ValueEncoder::paddedTo32(64)); - EXPECT_EQ(96, ABI::ValueEncoder::paddedTo32(65)); - EXPECT_EQ(24, ABI::ValueEncoder::padNeeded32(40)); - EXPECT_EQ(0, ABI::ValueEncoder::padNeeded32(32)); - EXPECT_EQ(31, ABI::ValueEncoder::padNeeded32(33)); - EXPECT_EQ(1, ABI::ValueEncoder::padNeeded32(63)); - EXPECT_EQ(0, ABI::ValueEncoder::padNeeded32(64)); - EXPECT_EQ(31, ABI::ValueEncoder::padNeeded32(65)); + EXPECT_EQ(64ul, ABI::ValueEncoder::paddedTo32(40)); + EXPECT_EQ(32ul, ABI::ValueEncoder::paddedTo32(32)); + EXPECT_EQ(64ul, ABI::ValueEncoder::paddedTo32(33)); + EXPECT_EQ(64ul, ABI::ValueEncoder::paddedTo32(63)); + EXPECT_EQ(64ul, ABI::ValueEncoder::paddedTo32(64)); + EXPECT_EQ(96ul, ABI::ValueEncoder::paddedTo32(65)); + EXPECT_EQ(24ul, ABI::ValueEncoder::padNeeded32(40)); + EXPECT_EQ(0ul, ABI::ValueEncoder::padNeeded32(32)); + EXPECT_EQ(31ul, ABI::ValueEncoder::padNeeded32(33)); + EXPECT_EQ(1ul, ABI::ValueEncoder::padNeeded32(63)); + EXPECT_EQ(0ul, ABI::ValueEncoder::padNeeded32(64)); + EXPECT_EQ(31ul, ABI::ValueEncoder::padNeeded32(65)); } diff --git a/tests/FIO/AddressTests.cpp b/tests/FIO/AddressTests.cpp index f78e3ae25f2..df478710d40 100644 --- a/tests/FIO/AddressTests.cpp +++ b/tests/FIO/AddressTests.cpp @@ -24,7 +24,7 @@ TEST(FIOAddress, ValidateString) { TEST(FIOAddress, ValidateData) { Address address("FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o"); - EXPECT_EQ(address.bytes.size(), 37); + EXPECT_EQ(address.bytes.size(), 37ul); Data addrData = TW::data(address.bytes.data(), address.bytes.size()); EXPECT_EQ(Address::isValid(addrData), true); diff --git a/tests/FIO/EncryptionTests.cpp b/tests/FIO/EncryptionTests.cpp index 55aa29793f1..75f7f009401 100644 --- a/tests/FIO/EncryptionTests.cpp +++ b/tests/FIO/EncryptionTests.cpp @@ -75,7 +75,7 @@ TEST(FIOEncryption, checkDecryptMessageTooShort) { Data randomBuffer(size_t size) { Data d(size); - for (auto i = 0; i < size; ++i) { + for (auto i = 0ul; i < size; ++i) { d[i] = (TW::byte)(256.0 * rand() / RAND_MAX); } return d; @@ -116,21 +116,21 @@ TEST(FIOEncryption, getSharedSecret) { const PrivateKey privateKey(parse_hex("2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90")); const PublicKey publicKey(parse_hex("024edfcf9dfe6c0b5c83d1ab3f78d1b39a46ebac6798e08e19761f5ed89ec83c10"), TWPublicKeyTypeSECP256k1); Data secret = Encryption::getSharedSecret(privateKey, publicKey); - EXPECT_EQ(secret.size(), 64); + EXPECT_EQ(secret.size(), 64ul); EXPECT_EQ(hex(secret), "a71b4ec5a9577926a1d2aa1d9d99327fd3b68f6a1ea597200a0d890bd3331df300a2d49fec0b2b3e6969ce9263c5d6cf47c191c1ef149373ecc9f0d98116b598"); } { const PrivateKey privateKey(parse_hex("81b637d8fcd2c6da6359e6963113a1170de795e4b725b84d1e0b4cfd9ec58ce9")); const PublicKey publicKey(parse_hex("039997a497d964fc1a62885b05a51166a65a90df00492c8d7cf61d6accf54803be"), TWPublicKeyTypeSECP256k1); Data secret = Encryption::getSharedSecret(privateKey, publicKey); - EXPECT_EQ(secret.size(), 64); + EXPECT_EQ(secret.size(), 64ul); EXPECT_EQ(hex(secret), "a71b4ec5a9577926a1d2aa1d9d99327fd3b68f6a1ea597200a0d890bd3331df300a2d49fec0b2b3e6969ce9263c5d6cf47c191c1ef149373ecc9f0d98116b598"); } { const PrivateKey privateKey(parse_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")); const PublicKey publicKey(parse_hex("03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd"), TWPublicKeyTypeSECP256k1); Data secret = Encryption::getSharedSecret(privateKey, publicKey); - EXPECT_EQ(secret.size(), 64); + EXPECT_EQ(secret.size(), 64ul); EXPECT_EQ(hex(secret), "3f0840df1912e24d85f39008a56550c31403e096fce7fa9d7886fab8e5c2ceb66b4139c8f4f4172fd9f455e76c2e8913a3d734f51a1951090ce9ec660671957d"); } } diff --git a/tests/FIO/TWFIOTests.cpp b/tests/FIO/TWFIOTests.cpp index 81ea60022a7..932d96d3674 100644 --- a/tests/FIO/TWFIOTests.cpp +++ b/tests/FIO/TWFIOTests.cpp @@ -26,7 +26,7 @@ TEST(TWFIO, Address) { ASSERT_NE(nullptr, privateKey.get()); auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(privateKey.get(), false)); ASSERT_NE(nullptr, publicKey.get()); - ASSERT_EQ(65, publicKey.get()->impl.bytes.size()); + ASSERT_EQ(65ul, publicKey.get()->impl.bytes.size()); auto address = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKey(publicKey.get(), TWCoinTypeFIO)); auto addressString = WRAPS(TWAnyAddressDescription(address.get())); assertStringsEqual(addressString, "FIO6m1fMdTpRkRBnedvYshXCxLFiC5suRU8KDfx8xxtXp2hntxpnf"); diff --git a/tests/FIO/TransactionBuilderTests.cpp b/tests/FIO/TransactionBuilderTests.cpp index 04b36498cf2..816c8025fb1 100644 --- a/tests/FIO/TransactionBuilderTests.cpp +++ b/tests/FIO/TransactionBuilderTests.cpp @@ -241,9 +241,9 @@ TEST(FIONewFundsContent, deserialize) { TEST(FIOTransactionBuilder, expirySetDefault) { uint32_t expiry = 1579790000; EXPECT_EQ(TransactionBuilder::expirySetDefaultIfNeeded(expiry), false); - EXPECT_EQ(expiry, 1579790000); + EXPECT_EQ(expiry, 1579790000ul); expiry = 0; - EXPECT_EQ(expiry, 0); + EXPECT_EQ(expiry, 0ul); EXPECT_EQ(TransactionBuilder::expirySetDefaultIfNeeded(expiry), true); EXPECT_TRUE(expiry > 1579790000); } @@ -350,7 +350,7 @@ TEST(FIOTransactionBuilder, encodeString) { { Data data; const string text = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; - EXPECT_EQ(text.length(), 130); + EXPECT_EQ(text.length(), 130ul); TW::FIO::encodeString(text, data); // length on 2 bytes EXPECT_EQ(hex(data), "8201" + hex(text)); diff --git a/tests/HDWallet/HDWalletTests.cpp b/tests/HDWallet/HDWalletTests.cpp index 0756525ab9b..701f3ed5dd8 100644 --- a/tests/HDWallet/HDWalletTests.cpp +++ b/tests/HDWallet/HDWalletTests.cpp @@ -31,13 +31,13 @@ TEST(HDWallet, generate) { HDWallet wallet = HDWallet(128, passphrase); EXPECT_TRUE(Mnemonic::isValid(wallet.getMnemonic())); EXPECT_EQ(wallet.getPassphrase(), passphrase); - EXPECT_EQ(wallet.getEntropy().size(), 16); + EXPECT_EQ(wallet.getEntropy().size(), 16ul); } { HDWallet wallet = HDWallet(256, passphrase); EXPECT_TRUE(Mnemonic::isValid(wallet.getMnemonic())); EXPECT_EQ(wallet.getPassphrase(), passphrase); - EXPECT_EQ(wallet.getEntropy().size(), 32); + EXPECT_EQ(wallet.getEntropy().size(), 32ul); } } @@ -67,37 +67,37 @@ TEST(HDWallet, createFromMnemonic) { TEST(HDWallet, entropyLength_createFromMnemonic) { { // 12 words HDWallet wallet = HDWallet("oil oil oil oil oil oil oil oil oil oil oil oil", ""); - EXPECT_EQ(wallet.getEntropy().size(), 16); + EXPECT_EQ(wallet.getEntropy().size(), 16ul); EXPECT_EQ(hex(wallet.getEntropy()), "99d33a674ce99d33a674ce99d33a674c"); } { // 12 words, from https://github.com/trezor/python-mnemonic/blob/master/vectors.json HDWallet wallet = HDWallet("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", ""); - EXPECT_EQ(wallet.getEntropy().size(), 16); + EXPECT_EQ(wallet.getEntropy().size(), 16ul); EXPECT_EQ(hex(wallet.getEntropy()), "00000000000000000000000000000000"); } { // 15 words HDWallet wallet = HDWallet("history step cheap card humble screen raise seek robot slot coral roof spoil wreck caution", ""); - EXPECT_EQ(wallet.getEntropy().size(), 20); + EXPECT_EQ(wallet.getEntropy().size(), 20ul); EXPECT_EQ(hex(wallet.getEntropy()), "6c3aac9b9146ef832c4e18bb3980c0dddd25fc49"); } { // 18 words HDWallet wallet = HDWallet("caught hockey split gun symbol code payment copy broccoli silly shed secret stove tell citizen staff photo high", ""); - EXPECT_EQ(wallet.getEntropy().size(), 24); + EXPECT_EQ(wallet.getEntropy().size(), 24ul); EXPECT_EQ(hex(wallet.getEntropy()), "246d8f48b3fdc65a2869801c791715614d6bbd8a56a0a3ad"); } { // 21 words HDWallet wallet = HDWallet("diary shine country alpha bridge coast loan hungry hip media sell crucial swarm share gospel lake visa coin dizzy physical basket", ""); - EXPECT_EQ(wallet.getEntropy().size(), 28); + EXPECT_EQ(wallet.getEntropy().size(), 28ul); EXPECT_EQ(hex(wallet.getEntropy()), "3d58bcc40381bc59a0c37a6bf14f0d9a3db78a5933e5f4a5ad00d1f1"); } { // 24 words HDWallet wallet = HDWallet("poet spider smile swift roof pilot subject save hand diet ice universe over brown inspire ugly wide economy symbol shove episode patient plug swamp", ""); - EXPECT_EQ(wallet.getEntropy().size(), 32); + EXPECT_EQ(wallet.getEntropy().size(), 32ul); EXPECT_EQ(hex(wallet.getEntropy()), "a73a3732edebbb49f5fdfe68c7b5c0f6e9de3a1d5760faa8c771e384bf4229b6"); } { // 24 words, from https://github.com/trezor/python-mnemonic/blob/master/vectors.json HDWallet wallet = HDWallet("letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", ""); - EXPECT_EQ(wallet.getEntropy().size(), 32); + EXPECT_EQ(wallet.getEntropy().size(), 32ul); EXPECT_EQ(hex(wallet.getEntropy()), "8080808080808080808080808080808080808080808080808080808080808080"); } } diff --git a/tests/Keystore/StoredKeyTests.cpp b/tests/Keystore/StoredKeyTests.cpp index 0b26eec95a0..e504b2e1bba 100644 --- a/tests/Keystore/StoredKeyTests.cpp +++ b/tests/Keystore/StoredKeyTests.cpp @@ -36,7 +36,7 @@ TEST(StoredKey, CreateWithMnemonic) { EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); const Data& mnemo2Data = key.payload.decrypt(password); EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(mnemonic)); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); EXPECT_EQ(key.wallet(password).getMnemonic(), string(mnemonic)); const auto json = key.json(); @@ -62,7 +62,7 @@ TEST(StoredKey, CreateWithMnemonicRandom) { const Data& mnemo2Data = key.payload.decrypt(password); EXPECT_TRUE(mnemo2Data.size() >= 36); EXPECT_TRUE(Mnemonic::isValid(string(mnemo2Data.begin(), mnemo2Data.end()))); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); } TEST(StoredKey, CreateWithMnemonicAddDefaultAddress) { @@ -72,7 +72,7 @@ TEST(StoredKey, CreateWithMnemonicAddDefaultAddress) { const Data& mnemo2Data = key.payload.decrypt(password); EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(mnemonic)); - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); EXPECT_EQ(key.accounts[0].coin, coinTypeBc); EXPECT_EQ(key.accounts[0].address, "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"); EXPECT_EQ(key.accounts[0].publicKey, "02df6fc590ab3101bbe0bb5765cbaeab9b5dcfe09ac9315d707047cbd13bc7e006"); @@ -84,7 +84,7 @@ TEST(StoredKey, CreateWithPrivateKeyAddDefaultAddress) { const auto privateKey = parse_hex("3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"); auto key = StoredKey::createWithPrivateKeyAddDefaultAddress("name", password, coinTypeBc, privateKey); EXPECT_EQ(key.type, StoredKeyType::privateKey); - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); EXPECT_EQ(key.accounts[0].coin, coinTypeBc); EXPECT_EQ(key.accounts[0].address, "bc1q375sq4kl2nv0mlmup3vm8znn4eqwu7mt6hkwhr"); EXPECT_EQ(hex(key.privateKey(coinTypeBc, password).bytes), hex(privateKey)); @@ -108,46 +108,46 @@ TEST(StoredKey, CreateWithPrivateKeyAddDefaultAddressInvalid) { TEST(StoredKey, AccountGetCreate) { auto key = StoredKey::createWithMnemonic("name", password, mnemonic, TWStoredKeyEncryptionLevelDefault); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); // not exists EXPECT_FALSE(key.account(coinTypeBc).has_value()); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); auto wallet = key.wallet(password); // not exists, wallet null, not create EXPECT_FALSE(key.account(coinTypeBc, nullptr).has_value()); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); // not exists, wallet nonnull, create std::optional acc3 = key.account(coinTypeBc, &wallet); EXPECT_TRUE(acc3.has_value()); EXPECT_EQ(acc3->coin, coinTypeBc); - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); // exists std::optional acc4 = key.account(coinTypeBc); EXPECT_TRUE(acc4.has_value()); EXPECT_EQ(acc4->coin, coinTypeBc); - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); // exists, wallet nonnull, not create std::optional acc5 = key.account(coinTypeBc, &wallet); EXPECT_TRUE(acc5.has_value()); EXPECT_EQ(acc5->coin, coinTypeBc); - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); // exists, wallet null, not create std::optional acc6 = key.account(coinTypeBc, nullptr); EXPECT_TRUE(acc6.has_value()); EXPECT_EQ(acc6->coin, coinTypeBc); - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); } TEST(StoredKey, AccountGetDoesntChange) { auto key = StoredKey::createWithMnemonic("name", password, mnemonic, TWStoredKeyEncryptionLevelDefault); auto wallet = key.wallet(password); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); vector coins = {coinTypeBc, coinTypeEth, coinTypeBnb}; // retrieve multiple accounts, which will be created @@ -162,7 +162,7 @@ TEST(StoredKey, AccountGetDoesntChange) { } // Check again; make sure returned references don't change - for (auto i = 0; i < accounts.size(); ++i) { + for (auto i = 0ul; i < accounts.size(); ++i) { // check EXPECT_EQ(accounts[i].coin, coins[i]); } @@ -170,24 +170,24 @@ TEST(StoredKey, AccountGetDoesntChange) { TEST(StoredKey, AddRemoveAccount) { auto key = StoredKey::createWithMnemonic("name", password, mnemonic, TWStoredKeyEncryptionLevelDefault); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); { const auto derivationPath = DerivationPath("m/84'/0'/0'/0/0"); key.addAccount("bc1qaucw06s3agez8tyyk4zj9kt0q2934e3mcewdpf", coinTypeBc, TWDerivationDefault, derivationPath, "", "zpub6rxtad3SPT1C5GUDjPiKQ5oJN5DBeMbdUR7LrdYt12VbU7TBSpGUkdLvfVYGuj1N5edkDoZ3bu1fdN1HprQYfCBdsSH5CaAAygHGsanwtTe"); - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); } { const auto derivationPath = DerivationPath("m/714'/0'/0'/0/0"); key.addAccount("bnb1utrnnjym7ustgw7pgyvtmnxay4qmt3ahh276nu", coinTypeBnb, TWDerivationDefault, derivationPath, "", ""); key.addAccount("0x23b02dC8f67eD6cF8DCa47935791954286ffe7c9", coinTypeBsc, TWDerivationDefault, derivationPath, "", ""); - EXPECT_EQ(key.accounts.size(), 3); + EXPECT_EQ(key.accounts.size(), 3ul); } { const auto derivationPath = DerivationPath("m/60'/0'/0'/0/0"); key.addAccount("0xC0d97f61A84A0708225F15d54978D628Fe2C5E62", coinTypeEth, TWDerivationDefault, derivationPath, "", ""); key.addAccount("0xC0d97f61A84A0708225F15d54978D628Fe2C5E62", coinTypeBscLegacy, TWDerivationDefault, derivationPath, "", ""); - EXPECT_EQ(key.accounts.size(), 5); + EXPECT_EQ(key.accounts.size(), 5ul); } key.removeAccount(coinTypeBc); @@ -195,56 +195,56 @@ TEST(StoredKey, AddRemoveAccount) { key.removeAccount(coinTypeBsc); key.removeAccount(coinTypeEth); key.removeAccount(coinTypeBscLegacy); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); } TEST(StoredKey, AddRemoveAccountDerivation) { auto key = StoredKey::createWithMnemonic("name", Data(), mnemonic, TWStoredKeyEncryptionLevelDefault); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); const auto derivationPath = DerivationPath("m/84'/0'/0'/0/0"); { key.addAccount("bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny", coinTypeBc, TWDerivationDefault, derivationPath, "", "zpub6qbsWdbcKW9sC6shTKK4VEhfWvDCoWpfLnnVfYKHLHt31wKYUwH3aFDz4WLjZvjHZ5W4qVEyk37cRwzTbfrrT1Gnu8SgXawASnkdQ994atn"); - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); } { key.addAccount("1NyRyFewhZcWMa9XCj3bBxSXPXyoSg8dKz", coinTypeBc, TWDerivationBitcoinLegacy, derivationPath, "", "xpub6CR52eaUuVb4kXAVyHC2i5ZuqJ37oWNPZFtjXaazFPXZD45DwWBYEBLdrF7fmCR9pgBuCA9Q57zZfyJjDUBDNtWkhWuGHNYKLgDHpqrHsxV"); - EXPECT_EQ(key.accounts.size(), 2); + EXPECT_EQ(key.accounts.size(), 2ul); } key.removeAccount(coinTypeBc, TWDerivationDefault); - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); key.removeAccount(coinTypeBc, TWDerivationDefault); // try 2nd time - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); key.removeAccount(coinTypeBc, TWDerivationBitcoinLegacy); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); key.removeAccount(coinTypeBc, TWDerivationBitcoinLegacy); // try 2nd time - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); } TEST(StoredKey, AddRemoveAccountDerivationPath) { auto key = StoredKey::createWithMnemonic("name", Data(), mnemonic, TWStoredKeyEncryptionLevelDefault); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); const auto derivationPath0 = DerivationPath("m/84'/0'/0'/0/0"); { key.addAccount("bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny", coinTypeBc, TWDerivationDefault, derivationPath0, "", "zpub6qbsWdbcKW9sC6shTKK4VEhfWvDCoWpfLnnVfYKHLHt31wKYUwH3aFDz4WLjZvjHZ5W4qVEyk37cRwzTbfrrT1Gnu8SgXawASnkdQ994atn"); - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); } const auto derivationPath1 = DerivationPath("m/84'/0'/0'/1/0"); { key.addAccount("bc1qumuzptwdr6jlsqum8jnzz80rdg8nx6x29m2qpu", coinTypeBc, TWDerivationDefault, derivationPath1, "", "zpub6rxtad3SPT1C5GUDjPiKQ5oJN5DBeMbdUR7LrdYt12VbU7TBSpGUkdLvfVYGuj1N5edkDoZ3bu1fdN1HprQYfCBdsSH5CaAAygHGsanwtTe"); - EXPECT_EQ(key.accounts.size(), 2); + EXPECT_EQ(key.accounts.size(), 2ul); } key.removeAccount(coinTypeBc, derivationPath0); - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); key.removeAccount(coinTypeBc, derivationPath0); // try 2nd time - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); key.removeAccount(coinTypeBc, derivationPath1); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); key.removeAccount(coinTypeBc, derivationPath1); // try 2nd time - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); } TEST(StoredKey, FixAddress) { @@ -298,8 +298,8 @@ TEST(StoredKey, LoadPBKDF2Key) { const auto& payload = key.payload; ASSERT_TRUE(payload.params.kdfParams.which() == 1); - EXPECT_EQ(boost::get(payload.params.kdfParams).desiredKeyLength, 32); - EXPECT_EQ(boost::get(payload.params.kdfParams).iterations, 262144); + EXPECT_EQ(boost::get(payload.params.kdfParams).desiredKeyLength, 32ul); + EXPECT_EQ(boost::get(payload.params.kdfParams).iterations, 262144ul); EXPECT_EQ(hex(boost::get(payload.params.kdfParams).salt), "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd"); EXPECT_EQ(hex(payload.decrypt(TW::data("testpassword"))), "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d"); @@ -347,10 +347,10 @@ TEST(StoredKey, ReadWallet) { EXPECT_EQ(hex(header.params.cipherParams.iv), "83dbcc02d8ccb40e466191a123791e0e"); ASSERT_TRUE(header.params.kdfParams.which() == 0); - EXPECT_EQ(boost::get(header.params.kdfParams).desiredKeyLength, 32); - EXPECT_EQ(boost::get(header.params.kdfParams).n, 262144); - EXPECT_EQ(boost::get(header.params.kdfParams).p, 8); - EXPECT_EQ(boost::get(header.params.kdfParams).r, 1); + EXPECT_EQ(boost::get(header.params.kdfParams).desiredKeyLength, 32ul); + EXPECT_EQ(boost::get(header.params.kdfParams).n, 262144ul); + EXPECT_EQ(boost::get(header.params.kdfParams).p, 8ul); + EXPECT_EQ(boost::get(header.params.kdfParams).r, 1ul); EXPECT_EQ(hex(boost::get(header.params.kdfParams).salt), "ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19"); } @@ -413,9 +413,9 @@ TEST(StoredKey, DecodingBitcoinAddress) { TEST(StoredKey, RemoveAccount) { auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/legacy-mnemonic.json"); - EXPECT_EQ(key.accounts.size(), 2); + EXPECT_EQ(key.accounts.size(), 2ul); key.removeAccount(TWCoinTypeEthereum); - EXPECT_EQ(key.accounts.size(), 1); + EXPECT_EQ(key.accounts.size(), 1ul); EXPECT_EQ(key.accounts[0].coin, coinTypeBc); } @@ -472,7 +472,7 @@ TEST(StoredKey, CreateMinimalEncryptionParameters) { EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); const Data& mnemo2Data = key.payload.decrypt(password); EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(mnemonic)); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); EXPECT_EQ(key.wallet(password).getMnemonic(), string(mnemonic)); const auto json = key.json(); @@ -490,7 +490,7 @@ TEST(StoredKey, CreateWeakEncryptionParameters) { EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); const Data& mnemo2Data = key.payload.decrypt(password); EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(mnemonic)); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); EXPECT_EQ(key.wallet(password).getMnemonic(), string(mnemonic)); const auto json = key.json(); @@ -508,7 +508,7 @@ TEST(StoredKey, CreateStandardEncryptionParameters) { EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); const Data& mnemo2Data = key.payload.decrypt(password); EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(mnemonic)); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); EXPECT_EQ(key.wallet(password).getMnemonic(), string(mnemonic)); const auto json = key.json(); @@ -527,13 +527,13 @@ TEST(StoredKey, CreateMultiAccounts) { // Multiple accounts for the same coin const Data& mnemo2Data = key.payload.decrypt(password); EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(mnemonic)); EXPECT_EQ(key.wallet(password).getMnemonic(), string(mnemonic)); - EXPECT_EQ(key.accounts.size(), 0); + EXPECT_EQ(key.accounts.size(), 0ul); const auto expectedBtc1 = "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"; const auto expectedBtc2 = "1NyRyFewhZcWMa9XCj3bBxSXPXyoSg8dKz"; const auto expectedSol1 = "HiipoCKL8hX2RVmJTz3vaLy34hS2zLhWWMkUWtw85TmZ"; const auto wallet = key.wallet(password); - int expectedAccounts = 0; + auto expectedAccounts = 0ul; { // Create default Bitcoin account const auto coin = TWCoinTypeBitcoin; @@ -547,7 +547,7 @@ TEST(StoredKey, CreateMultiAccounts) { // Multiple accounts for the same coin EXPECT_EQ(key.accounts.size(), ++expectedAccounts); EXPECT_EQ(key.accounts[expectedAccounts - 1].address, expectedBtc1); EXPECT_EQ(key.account(coin)->address, expectedBtc1); - EXPECT_EQ(key.getAccounts(coin).size(), 1); + EXPECT_EQ(key.getAccounts(coin).size(), 1ul); EXPECT_EQ(key.getAccounts(coin)[0].address, expectedBtc1); } { // Create default Solana account @@ -561,7 +561,7 @@ TEST(StoredKey, CreateMultiAccounts) { // Multiple accounts for the same coin EXPECT_EQ(key.accounts.size(), ++expectedAccounts); EXPECT_EQ(key.accounts[expectedAccounts - 1].address, expectedSol1); EXPECT_EQ(key.account(coin)->address, expectedSol1); - EXPECT_EQ(key.getAccounts(coin).size(), 1); + EXPECT_EQ(key.getAccounts(coin).size(), 1ul); EXPECT_EQ(key.getAccounts(coin)[0].address, expectedSol1); } { // Create alternative P2PK Bitcoin account (different address format) @@ -576,7 +576,7 @@ TEST(StoredKey, CreateMultiAccounts) { // Multiple accounts for the same coin EXPECT_EQ(key.accounts[expectedAccounts - 1].address, expectedBtc2); EXPECT_EQ(key.account(coin)->address, expectedBtc1); EXPECT_EQ(key.account(coin, TWDerivationBitcoinLegacy, wallet).address, expectedBtc2); - EXPECT_EQ(key.getAccounts(coin).size(), 2); + EXPECT_EQ(key.getAccounts(coin).size(), 2ul); EXPECT_EQ(key.getAccounts(coin)[0].address, expectedBtc1); EXPECT_EQ(key.getAccounts(coin)[1].address, expectedBtc2); } @@ -593,7 +593,7 @@ TEST(StoredKey, CreateMultiAccounts) { // Multiple accounts for the same coin // Now we have 2 Solana addresses, 1st is returned here EXPECT_EQ(key.account(coin)->address, expectedSol1); EXPECT_EQ(key.account(coin, TWDerivationSolanaSolana, wallet).address, expectedSol2); - EXPECT_EQ(key.getAccounts(coin).size(), 2); + EXPECT_EQ(key.getAccounts(coin).size(), 2ul); EXPECT_EQ(key.getAccounts(coin)[0].address, expectedSol1); EXPECT_EQ(key.getAccounts(coin)[1].address, expectedSol2); } @@ -615,7 +615,7 @@ TEST(StoredKey, CreateMultiAccounts) { // Multiple accounts for the same coin EXPECT_EQ(key.accounts[expectedAccounts - 1].address, expectedBtc3); // Now we have 2 Bitcoin addresses, 1st is returned here EXPECT_EQ(key.account(coin)->address, expectedBtc1); - EXPECT_EQ(key.getAccounts(coin).size(), 3); + EXPECT_EQ(key.getAccounts(coin).size(), 3ul); EXPECT_EQ(key.getAccounts(coin)[0].address, expectedBtc1); EXPECT_EQ(key.getAccounts(coin)[1].address, expectedBtc2); EXPECT_EQ(key.getAccounts(coin)[2].address, expectedBtc3); @@ -628,18 +628,18 @@ TEST(StoredKey, CreateWithMnemonicAlternativeDerivation) { auto key = StoredKey::createWithMnemonicAddDefaultAddress("name", password, mnemonic, coin); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); - ASSERT_EQ(key.accounts.size(), 1); + ASSERT_EQ(key.accounts.size(), 1ul); EXPECT_EQ(key.accounts[0].coin, coin); EXPECT_EQ(key.accounts[0].address, "HiipoCKL8hX2RVmJTz3vaLy34hS2zLhWWMkUWtw85TmZ"); EXPECT_EQ(key.accounts[0].publicKey, "f86b18399096c8134dd185f1e72dd7e26528772a2a998abfd81c5f8c547223d0"); EXPECT_EQ(hex(key.privateKey(coin, password).bytes), "d81b5c525979e487736b69cb84ed8331559de17294f38491b304555c26687e83"); EXPECT_EQ(hex(key.privateKey(coin, TWDerivationDefault, password).bytes), "d81b5c525979e487736b69cb84ed8331559de17294f38491b304555c26687e83"); - ASSERT_EQ(key.accounts.size(), 1); + ASSERT_EQ(key.accounts.size(), 1ul); // alternative derivation, different keys EXPECT_EQ(hex(key.privateKey(coin, TWDerivationSolanaSolana, password).bytes), "d49a5fa7f77593534c7afd2ba8dc8e9d8b007bc6ec65fe8df25ffe6fafc57151"); - ASSERT_EQ(key.accounts.size(), 2); + ASSERT_EQ(key.accounts.size(), 2ul); EXPECT_EQ(key.accounts[1].coin, coin); EXPECT_EQ(key.accounts[1].address, "CgWJeEWkiYqosy1ba7a3wn9HAQuHyK48xs3LM4SSDc1C"); EXPECT_EQ(key.accounts[1].publicKey, "ad8f57924dce62f9040f93b4f6ce3c3d39afde7e29bcb4013dad59db7913c4c7"); diff --git a/tests/NEO/TransactionTests.cpp b/tests/NEO/TransactionTests.cpp index 1c0aa39ecf5..8224ac771b2 100644 --- a/tests/NEO/TransactionTests.cpp +++ b/tests/NEO/TransactionTests.cpp @@ -22,9 +22,9 @@ TEST(NEOTransaction, SerializeDeserializeEmpty) { auto transaction = Transaction(); EXPECT_EQ(transaction, transaction); - EXPECT_EQ(0, transaction.attributes.size()); - EXPECT_EQ(0, transaction.inInputs.size()); - EXPECT_EQ(0, transaction.outputs.size()); + EXPECT_EQ(0ul, transaction.attributes.size()); + EXPECT_EQ(0ul, transaction.inInputs.size()); + EXPECT_EQ(0ul, transaction.outputs.size()); auto serialized = transaction.serialize(); auto deserializedTransaction = Transaction(); @@ -246,5 +246,5 @@ TEST(NEOTransaction, SerializeSize) { EXPECT_EQ(hex(verSerialized), hex(serialized)); EXPECT_EQ(verSerialized, serialized); - EXPECT_EQ(serialized.size(), transaction.size()); + EXPECT_EQ(serialized.size(), static_cast(transaction.size())); } diff --git a/tests/Ontology/ParamsBuilderTests.cpp b/tests/Ontology/ParamsBuilderTests.cpp index bb8a3540d1e..f39da1249b0 100644 --- a/tests/Ontology/ParamsBuilderTests.cpp +++ b/tests/Ontology/ParamsBuilderTests.cpp @@ -51,7 +51,7 @@ TEST(ParamsBuilder, pushInt) { "050000000010", "08ffffffffffffff00", "08ffffffffffffff0f"}; - for (auto index = 0; index < numVector.size(); index++) { + for (auto index = 0ul; index < numVector.size(); index++) { auto builder = ParamsBuilder(); builder.push(numVector[index]); EXPECT_EQ(codeVector[index], hex(builder.getBytes())); @@ -81,4 +81,4 @@ TEST(ParamsBuilder, transferInvokeCode) { "ad76586a7cc8516a7cc86c51c1087472616e736665721400000000000000000000000000000000000000010068" "164f6e746f6c6f67792e4e61746976652e496e766f6b65"; EXPECT_EQ(hexInvokeCode, hex(invokeCode)); -} \ No newline at end of file +} diff --git a/tests/Ontology/TransactionTests.cpp b/tests/Ontology/TransactionTests.cpp index 0c8d4c7b254..63db8af8e0f 100644 --- a/tests/Ontology/TransactionTests.cpp +++ b/tests/Ontology/TransactionTests.cpp @@ -50,7 +50,7 @@ TEST(OntologyTransaction, validity) { "6e746f6c6f67792e4e61746976652e496e766f6b6500014140e03a09d85f56d2ceb5817a1f3a430bab9bf0f469" "da38afe4a5b33de258a06236d8e0a59d25918a49825455c99f91de9caf8071e38a589a530519705af9081eca23" "21031bec1250aa8f78275f99a6663688f31085848d0ed92f1203e447125f927b7486ac"; - EXPECT_EQ(520, hex(tx.serialize()).length()); + EXPECT_EQ(520ul, hex(tx.serialize()).length()); EXPECT_EQ(hexTx.substr(0, 20), hex(tx.serialize()).substr(0, 20)); auto signer2 = Signer(PrivateKey(parse_hex("4646464646464646464646464646464646464646464646464646464646464652"))); signer2.addSign(tx); @@ -59,7 +59,7 @@ TEST(OntologyTransaction, validity) { hex(result).find("21031bec1250aa8f78275f99a6663688f31085848d0ed92f1203e447125f927b7486ac"); auto verifyPosition2 = hex(result).find("2103d9fd62df332403d9114f3fa3da0d5aec9dfa42948c2f50738d52470469a1a1eeac"); - EXPECT_EQ(450, verifyPosition1); - EXPECT_EQ(654, verifyPosition2); - EXPECT_EQ(724, hex(result).length()); -} \ No newline at end of file + EXPECT_EQ(450ul, verifyPosition1); + EXPECT_EQ(654ul, verifyPosition2); + EXPECT_EQ(724ul, hex(result).length()); +} diff --git a/tests/PrivateKeyTests.cpp b/tests/PrivateKeyTests.cpp index e020e83245f..1f33ef7f8a8 100644 --- a/tests/PrivateKeyTests.cpp +++ b/tests/PrivateKeyTests.cpp @@ -174,7 +174,7 @@ TEST(PrivateKey, PrivateKeyExtended) { )); EXPECT_EQ("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5", hex(privateKeyNonext.bytes)); auto publicKeyNonext = privateKeyNonext.getPublicKey(TWPublicKeyTypeED25519); - EXPECT_EQ(32, publicKeyNonext.bytes.size()); + EXPECT_EQ(32ul, publicKeyNonext.bytes.size()); const auto fullkey = "b0884d248cb301edd1b34cf626ba6d880bb3ae8fd91b4696446999dc4f0b5744" @@ -194,7 +194,7 @@ TEST(PrivateKey, PrivateKeyExtended) { EXPECT_EQ("ed7f28be986cbe06819165f2ee41b403678a098961013cf4a2f3e9ea61fb6c1a", hex(privateKeyExt.secondChainCode())); auto publicKeyExt = privateKeyExt.getPublicKey(TWPublicKeyTypeED25519Cardano); - EXPECT_EQ(2*64, publicKeyExt.bytes.size()); + EXPECT_EQ(2*64ul, publicKeyExt.bytes.size()); // Try other constructor for extended key auto privateKeyExtOne = PrivateKey( @@ -346,7 +346,7 @@ TEST(PrivateKey, SignNIST256p1) { ); } -int isCanonical(uint8_t by, uint8_t sig[64]) { +int isCanonical([[maybe_unused]] uint8_t by, [[maybe_unused]] uint8_t sig[64]) { return 1; } @@ -369,14 +369,14 @@ TEST(PrivateKey, SignShortDigest) { Data shortDigest = TW::data("12345"); { Data actual = privateKey.sign(shortDigest, TWCurveSECP256k1); - EXPECT_EQ(actual.size(), 0); + EXPECT_EQ(actual.size(), 0ul); } { Data actual = privateKey.sign(shortDigest, TWCurveNIST256p1); - EXPECT_EQ(actual.size(), 0); + EXPECT_EQ(actual.size(), 0ul); } { Data actual = privateKey.sign(shortDigest, TWCurveSECP256k1, isCanonical); - EXPECT_EQ(actual.size(), 0); + EXPECT_EQ(actual.size(), 0ul); } } diff --git a/tests/PublicKeyTests.cpp b/tests/PublicKeyTests.cpp index 33f21c231d7..1154e3d8d6f 100644 --- a/tests/PublicKeyTests.cpp +++ b/tests/PublicKeyTests.cpp @@ -19,7 +19,7 @@ TEST(PublicKeyTests, CreateFromPrivateSecp256k1) { const Data key = parse_hex("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5"); auto privateKey = PrivateKey(key); auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); - EXPECT_EQ(publicKey.bytes.size(), 33); + EXPECT_EQ(publicKey.bytes.size(), 33ul); EXPECT_EQ(hex(publicKey.bytes), "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1"); EXPECT_EQ(publicKey.isCompressed(), true); EXPECT_TRUE(PublicKey::isValid(publicKey.bytes, TWPublicKeyTypeSECP256k1)); @@ -47,7 +47,7 @@ TEST(PublicKeyTests, CreateBlake) { { auto publicKey = PrivateKey(parse_hex(privateKeyHex)).getPublicKey(TWPublicKeyTypeED25519Blake2b); EXPECT_EQ(hex(publicKey.bytes), publicKeyKeyHex); - EXPECT_EQ(publicKey.bytes.size(), 32); + EXPECT_EQ(publicKey.bytes.size(), 32ul); } { const auto publicKey = PublicKey(parse_hex(publicKeyKeyHex), TWPublicKeyTypeED25519Blake2b); @@ -60,14 +60,14 @@ TEST(PublicKeyTests, CompressedExtended) { auto privateKey = PrivateKey(key); auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); EXPECT_EQ(publicKey.type, TWPublicKeyTypeSECP256k1); - EXPECT_EQ(publicKey.bytes.size(), 33); + EXPECT_EQ(publicKey.bytes.size(), 33ul); EXPECT_EQ(publicKey.isCompressed(), true); EXPECT_TRUE(PublicKey::isValid(publicKey.bytes, TWPublicKeyTypeSECP256k1)); EXPECT_EQ(hex(publicKey.bytes), std::string("0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1")); auto extended = publicKey.extended(); EXPECT_EQ(extended.type, TWPublicKeyTypeSECP256k1Extended); - EXPECT_EQ(extended.bytes.size(), 65); + EXPECT_EQ(extended.bytes.size(), 65ul); EXPECT_EQ(extended.isCompressed(), false); EXPECT_TRUE(PublicKey::isValid(extended.bytes, TWPublicKeyTypeSECP256k1Extended)); EXPECT_EQ(hex(extended.bytes), std::string("0499c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c166b489a4b7c491e7688e6ebea3a71fc3a1a48d60f98d5ce84c93b65e423fde91")); @@ -75,20 +75,20 @@ TEST(PublicKeyTests, CompressedExtended) { auto compressed = extended.compressed(); EXPECT_EQ(compressed.type, TWPublicKeyTypeSECP256k1); EXPECT_TRUE(compressed == publicKey); - EXPECT_EQ(compressed.bytes.size(), 33); + EXPECT_EQ(compressed.bytes.size(), 33ul); EXPECT_EQ(compressed.isCompressed(), true); EXPECT_TRUE(PublicKey::isValid(compressed.bytes, TWPublicKeyTypeSECP256k1)); EXPECT_EQ(hex(compressed.bytes), std::string("0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1")); auto extended2 = extended.extended(); EXPECT_EQ(extended2.type, TWPublicKeyTypeSECP256k1Extended); - EXPECT_EQ(extended2.bytes.size(), 65); + EXPECT_EQ(extended2.bytes.size(), 65ul); EXPECT_EQ(extended2.isCompressed(), false); auto compressed2 = compressed.compressed(); EXPECT_EQ(compressed2.type, TWPublicKeyTypeSECP256k1); EXPECT_TRUE(compressed2 == publicKey); - EXPECT_EQ(compressed2.bytes.size(), 33); + EXPECT_EQ(compressed2.bytes.size(), 33ul); EXPECT_EQ(compressed2.isCompressed(), true); } @@ -97,14 +97,14 @@ TEST(PublicKeyTests, CompressedExtendedNist) { auto privateKey = PrivateKey(key); auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeNIST256p1); EXPECT_EQ(publicKey.type, TWPublicKeyTypeNIST256p1); - EXPECT_EQ(publicKey.bytes.size(), 33); + EXPECT_EQ(publicKey.bytes.size(), 33ul); EXPECT_EQ(publicKey.isCompressed(), true); EXPECT_TRUE(PublicKey::isValid(publicKey.bytes, TWPublicKeyTypeNIST256p1)); EXPECT_EQ(hex(publicKey.bytes), std::string("026d786ab8fda678cf50f71d13641049a393b325063b8c0d4e5070de48a2caf9ab")); auto extended = publicKey.extended(); EXPECT_EQ(extended.type, TWPublicKeyTypeNIST256p1Extended); - EXPECT_EQ(extended.bytes.size(), 65); + EXPECT_EQ(extended.bytes.size(), 65ul); EXPECT_EQ(extended.isCompressed(), false); EXPECT_TRUE(PublicKey::isValid(extended.bytes, TWPublicKeyTypeNIST256p1Extended)); EXPECT_EQ(hex(extended.bytes), std::string("046d786ab8fda678cf50f71d13641049a393b325063b8c0d4e5070de48a2caf9ab918b4fe46ccbf56701fb210d67d91c5779468f6b3fdc7a63692b9b62543f47ae")); @@ -112,20 +112,20 @@ TEST(PublicKeyTests, CompressedExtendedNist) { auto compressed = extended.compressed(); EXPECT_EQ(compressed.type, TWPublicKeyTypeNIST256p1); EXPECT_TRUE(compressed == publicKey); - EXPECT_EQ(compressed.bytes.size(), 33); + EXPECT_EQ(compressed.bytes.size(), 33ul); EXPECT_EQ(compressed.isCompressed(), true); EXPECT_TRUE(PublicKey::isValid(compressed.bytes, TWPublicKeyTypeNIST256p1)); EXPECT_EQ(hex(compressed.bytes), std::string("026d786ab8fda678cf50f71d13641049a393b325063b8c0d4e5070de48a2caf9ab")); auto extended2 = extended.extended(); EXPECT_EQ(extended2.type, TWPublicKeyTypeNIST256p1Extended); - EXPECT_EQ(extended2.bytes.size(), 65); + EXPECT_EQ(extended2.bytes.size(), 65ul); EXPECT_EQ(extended2.isCompressed(), false); auto compressed2 = compressed.compressed(); EXPECT_EQ(compressed2.type, TWPublicKeyTypeNIST256p1); EXPECT_TRUE(compressed2 == publicKey); - EXPECT_EQ(compressed2.bytes.size(), 33); + EXPECT_EQ(compressed2.bytes.size(), 33ul); EXPECT_EQ(compressed2.isCompressed(), true); } @@ -134,7 +134,7 @@ TEST(PublicKeyTests, CompressedExtendedED25519) { auto privateKey = PrivateKey(key); auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519); EXPECT_EQ(publicKey.type, TWPublicKeyTypeED25519); - EXPECT_EQ(publicKey.bytes.size(), 32); + EXPECT_EQ(publicKey.bytes.size(), 32ul); EXPECT_EQ(publicKey.isCompressed(), true); EXPECT_TRUE(PublicKey::isValid(publicKey.bytes, TWPublicKeyTypeED25519)); EXPECT_EQ(hex(publicKey.bytes), std::string("4870d56d074c50e891506d78faa4fb69ca039cc5f131eb491e166b975880e867")); @@ -142,13 +142,13 @@ TEST(PublicKeyTests, CompressedExtendedED25519) { auto extended = publicKey.extended(); EXPECT_EQ(extended.type, TWPublicKeyTypeED25519); EXPECT_TRUE(extended == publicKey); - EXPECT_EQ(extended.bytes.size(), 32); + EXPECT_EQ(extended.bytes.size(), 32ul); EXPECT_EQ(extended.isCompressed(), true); auto compressed = publicKey.compressed(); EXPECT_EQ(compressed.type, TWPublicKeyTypeED25519); EXPECT_TRUE(compressed == publicKey); - EXPECT_EQ(compressed.bytes.size(), 32); + EXPECT_EQ(compressed.bytes.size(), 32ul); EXPECT_EQ(compressed.isCompressed(), true); } @@ -196,8 +196,8 @@ TEST(PublicKeyTests, VerifyAsDER) { const Data messageData = TW::data(message); const Data digest = Hash::sha256(messageData); - const auto signature = privateKey.signAsDER(digest, TWCurveSECP256k1); - EXPECT_EQ(signature.size(), 70); + const auto signature = privateKey.signAsDER(digest); + EXPECT_EQ(signature.size(), 70ul); EXPECT_EQ(hex(signature), "304402200f5d5a9e5fc4b82a625312f3be5d3e8ad017d882de86c72c92fcefa924e894c102202071772a14201a3a0debf381b5e8dea39fadb9bcabdc02ee71ab018f55bf717f"); const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); diff --git a/tests/Ripple/AddressTests.cpp b/tests/Ripple/AddressTests.cpp index f73660b0090..107a3007056 100644 --- a/tests/Ripple/AddressTests.cpp +++ b/tests/Ripple/AddressTests.cpp @@ -40,10 +40,10 @@ TEST(RippleXAddress, FromString) { const auto address = XAddress(xAddress); const auto address2 = XAddress(xAddress2); - ASSERT_EQ(address.tag, 12345); + ASSERT_EQ(address.tag, 12345ul); ASSERT_EQ(address.string(), xAddress); - ASSERT_EQ(address2.tag, 0); + ASSERT_EQ(address2.tag, 0ul); ASSERT_EQ(address2.string(), xAddress2); } diff --git a/tests/Ripple/TransactionTests.cpp b/tests/Ripple/TransactionTests.cpp index 4162ebbfe2a..f7c33b701bf 100644 --- a/tests/Ripple/TransactionTests.cpp +++ b/tests/Ripple/TransactionTests.cpp @@ -122,5 +122,5 @@ TEST(RippleTransaction, preImage) { /* account */ "81145b812c9d57731e27a2da8b1830195f88ef32a3b6" /* destination */ "8314b5f762798a53d543a014caf8b297cff8f2f937e8" ); - ASSERT_EQ(unsignedTx.size(), 114); + ASSERT_EQ(unsignedTx.size(), 114ul); } diff --git a/tests/Solana/SignerTests.cpp b/tests/Solana/SignerTests.cpp index 12ed74128a5..2ca7fdf04e7 100644 --- a/tests/Solana/SignerTests.cpp +++ b/tests/Solana/SignerTests.cpp @@ -45,13 +45,13 @@ TEST(SolanaSigner, CompiledInstruction) { auto compiledInstruction = CompiledInstruction(instruction, addresses); EXPECT_EQ(compiledInstruction.programIdIndex, 2); - ASSERT_EQ(compiledInstruction.accounts.size(), 5); + ASSERT_EQ(compiledInstruction.accounts.size(), 5ul); EXPECT_EQ(compiledInstruction.accounts[0], 1); EXPECT_EQ(compiledInstruction.accounts[1], 0); EXPECT_EQ(compiledInstruction.accounts[2], 2); EXPECT_EQ(compiledInstruction.accounts[3], 1); EXPECT_EQ(compiledInstruction.accounts[4], 0); - ASSERT_EQ(compiledInstruction.data.size(), 4); + ASSERT_EQ(compiledInstruction.data.size(), 4ul); } TEST(SolanaSigner, CompiledInstructionFindAccount) { diff --git a/tests/Solana/TransactionTests.cpp b/tests/Solana/TransactionTests.cpp index 9ee66466647..a06f6928460 100644 --- a/tests/Solana/TransactionTests.cpp +++ b/tests/Solana/TransactionTests.cpp @@ -124,7 +124,7 @@ TEST(SolanaTransaction, CreateTokenAccountTransaction) { EXPECT_EQ(message.header.numRequiredSignatures, 1); EXPECT_EQ(message.header.numCreditOnlySignedAccounts, 0); EXPECT_EQ(message.header.numCreditOnlyUnsignedAccounts, 5); - ASSERT_EQ(message.accountKeys.size(), 7); + ASSERT_EQ(message.accountKeys.size(), 7ul); EXPECT_EQ(message.accountKeys[0].string(), "B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); EXPECT_EQ(message.accountKeys[1].string(), "EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); EXPECT_EQ(message.accountKeys[2].string(), "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"); @@ -133,9 +133,9 @@ TEST(SolanaTransaction, CreateTokenAccountTransaction) { EXPECT_EQ(message.accountKeys[5].string(), "SysvarRent111111111111111111111111111111111"); EXPECT_EQ(message.accountKeys[6].string(), "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); EXPECT_EQ(Base58::bitcoin.encode(message.recentBlockhash.bytes), "9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); - ASSERT_EQ(message.instructions.size(), 1); + ASSERT_EQ(message.instructions.size(), 1ul); EXPECT_EQ(message.instructions[0].programId.string(), "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); - ASSERT_EQ(message.instructions[0].accounts.size(), 7); + ASSERT_EQ(message.instructions[0].accounts.size(), 7ul); EXPECT_EQ(message.instructions[0].accounts[0].account.string(), "B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); EXPECT_EQ(message.instructions[0].accounts[1].account.string(), "EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); EXPECT_EQ(message.instructions[0].accounts[2].account.string(), "B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); @@ -166,10 +166,10 @@ TEST(SolanaTransaction, TransferTokenTransaction_3vZ67C) { EXPECT_EQ(message.header.numRequiredSignatures, 1); EXPECT_EQ(message.header.numCreditOnlySignedAccounts, 0); EXPECT_EQ(message.header.numCreditOnlyUnsignedAccounts, 2); - ASSERT_EQ(message.accountKeys.size(), 5); - ASSERT_EQ(message.instructions.size(), 1); + ASSERT_EQ(message.accountKeys.size(), 5ul); + ASSERT_EQ(message.instructions.size(), 1ul); EXPECT_EQ(message.instructions[0].programId.string(), "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); - ASSERT_EQ(message.instructions[0].accounts.size(), 4); + ASSERT_EQ(message.instructions[0].accounts.size(), 4ul); auto transaction = Transaction(message); transaction.signatures.clear(); Signature signature("3vZ67CGoRYkuT76TtpP2VrtTPBfnvG2xj6mUTvvux46qbnpThgQDgm27nC3yQVUZrABFjT9Qo7vA74tCjtV5P9Xg"); diff --git a/tests/THORChain/SwapTests.cpp b/tests/THORChain/SwapTests.cpp index e5bd97af933..adb3340a417 100644 --- a/tests/THORChain/SwapTests.cpp +++ b/tests/THORChain/SwapTests.cpp @@ -56,7 +56,7 @@ TEST(THORChainSwap, SwapBtcEth) { EXPECT_EQ(tx.to_address(), VaultBtc); EXPECT_EQ(tx.change_address(), Address1Btc); EXPECT_EQ(tx.output_op_return(), "=:ETH.ETH:0xb9f5771c27664bf2282d98e09d7f50cec7cb01a7:140000000000000000"); - EXPECT_EQ(tx.coin_type(), 0); + EXPECT_EQ(tx.coin_type(), 0ul); EXPECT_EQ(tx.private_key_size(), 0); EXPECT_FALSE(tx.has_plan()); @@ -109,7 +109,7 @@ TEST(THORChainSwap, SwapBtcBnb) { EXPECT_EQ(tx.to_address(), VaultBtc); EXPECT_EQ(tx.change_address(), Address1Btc); EXPECT_EQ(tx.output_op_return(), "SWAP:BNB.BNB:bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx:140000000"); - EXPECT_EQ(tx.coin_type(), 0); + EXPECT_EQ(tx.coin_type(), 0ul); EXPECT_EQ(tx.private_key_size(), 0); EXPECT_FALSE(tx.has_plan()); diff --git a/tests/THORChain/TWSwapTests.cpp b/tests/THORChain/TWSwapTests.cpp index 0b2281a7e23..7a589d9cf0e 100644 --- a/tests/THORChain/TWSwapTests.cpp +++ b/tests/THORChain/TWSwapTests.cpp @@ -58,7 +58,7 @@ TEST(TWTHORChainSwap, SwapBtcToEth) { // invoke swap const auto outputTWData = WRAPD(TWTHORChainSwapBuildSwap(inputTWData.get())); const auto outputData = data(TWDataBytes(outputTWData.get()), TWDataSize(outputTWData.get())); - EXPECT_EQ(outputData.size(), 178); + EXPECT_EQ(outputData.size(), 178ul); // parse result in proto Proto::SwapOutput outputProto; EXPECT_TRUE(outputProto.ParseFromArray(outputData.data(), static_cast(outputData.size()))); @@ -74,7 +74,7 @@ TEST(TWTHORChainSwap, SwapBtcToEth) { EXPECT_EQ(txInput.to_address(), "bc1q6m9u2qsu8mh8y7v8rr2ywavtj8g5arzlyhcej7"); EXPECT_EQ(txInput.change_address(), "bc1qpjult34k9spjfym8hss2jrwjgf0xjf40ze0pp8"); EXPECT_EQ(txInput.output_op_return(), "=:ETH.ETH:0xb9f5771c27664bf2282d98e09d7f50cec7cb01a7:140000000000000000"); - EXPECT_EQ(txInput.coin_type(), 0); + EXPECT_EQ(txInput.coin_type(), 0ul); // sign tx input for signed full tx // set few fields before signing @@ -138,7 +138,7 @@ TEST(TWTHORChainSwap, SwapEthBnb) { // invoke swap const auto outputTWData = WRAPD(TWTHORChainSwapBuildSwap(inputTWData.get())); const auto outputData = data(TWDataBytes(outputTWData.get()), TWDataSize(outputTWData.get())); - EXPECT_EQ(outputData.size(), 311); + EXPECT_EQ(outputData.size(), 311ul); // parse result in proto Proto::SwapOutput outputProto; EXPECT_TRUE(outputProto.ParseFromArray(outputData.data(), static_cast(outputData.size()))); @@ -192,7 +192,7 @@ TEST(TWTHORChainSwap, SwapBnbBtc) { // invoke swap const auto outputTWData = WRAPD(TWTHORChainSwapBuildSwap(inputTWData.get())); const auto outputData = data(TWDataBytes(outputTWData.get()), TWDataSize(outputTWData.get())); - EXPECT_EQ(outputData.size(), 149); + EXPECT_EQ(outputData.size(), 149ul); // parse result in proto Proto::SwapOutput outputProto; EXPECT_TRUE(outputProto.ParseFromArray(outputData.data(), static_cast(outputData.size()))); @@ -219,7 +219,7 @@ TEST(TWTHORChainSwap, NegativeInvalidInput) { const auto outputTWData = WRAPD(TWTHORChainSwapBuildSwap(inputTWData.get())); const auto outputData = data(TWDataBytes(outputTWData.get()), TWDataSize(outputTWData.get())); - EXPECT_EQ(outputData.size(), 39); + EXPECT_EQ(outputData.size(), 39ul); EXPECT_EQ(hex(outputData), "1a2508021221436f756c64206e6f7420646573657269616c697a6520696e7075742070726f746f"); EXPECT_EQ(hex(data(std::string("Could not deserialize input proto"))), "436f756c64206e6f7420646573657269616c697a6520696e7075742070726f746f"); } diff --git a/tests/TransactionCompilerTests.cpp b/tests/TransactionCompilerTests.cpp index fae197ae817..62b1a9d75c0 100644 --- a/tests/TransactionCompilerTests.cpp +++ b/tests/TransactionCompilerTests.cpp @@ -43,7 +43,7 @@ TEST(TransactionCompiler, BinanceCompileWithSignatures) { { // Check, by parsing - EXPECT_EQ(txInputData.size(), 88); + EXPECT_EQ(txInputData.size(), 88ul); Binance::Proto::SigningInput input; ASSERT_TRUE(input.ParseFromArray(txInputData.data(), (int)txInputData.size())); EXPECT_EQ(input.chain_id(), "Binance-Chain-Nile"); @@ -54,7 +54,7 @@ TEST(TransactionCompiler, BinanceCompileWithSignatures) { /// Step 2: Obtain preimage hash const auto preImageHashes = TransactionCompiler::preImageHashes(coin, txInputData); - ASSERT_GT(preImageHashes.size(), 0); + ASSERT_GT(preImageHashes.size(), 0ul); TxCompiler::Proto::PreSigningOutput output; ASSERT_TRUE(output.ParseFromArray(preImageHashes.data(), int(preImageHashes.size()))); @@ -78,7 +78,7 @@ TEST(TransactionCompiler, BinanceCompileWithSignatures) { const auto ExpectedTx = "b801f0625dee0a462a2c87fa0a1f0a1440c2979694bbc961023d1d27be6fc4d21a9febe612070a03424e421001121f0a14bffe47abfaede50419c577f1074fee6dd1535cd112070a03424e421001126a0a26eb5ae98721026a35920088d98c3888ca68c53dfc93f4564602606cbb87f0fe5ee533db38e50212401b1181faec30b60a2ddaa2804c253cf264c69180ec31814929b5de62088c0c5a45e8a816d1208fc5366bb8b041781a6771248550d04094c3d7a504f9e8310679"; { - EXPECT_EQ(outputData.size(), 189); + EXPECT_EQ(outputData.size(), 189ul); Binance::Proto::SigningOutput output; ASSERT_TRUE(output.ParseFromArray(outputData.data(), (int)outputData.size())); @@ -267,11 +267,11 @@ TEST(TransactionCompiler, BitcoinCompileWithSignatures) { const auto ExpectedTx = "010000000001036021efcf7555f90627364339fc921139dd40a06ccb2cb2a2a4f8f4ea7a2dc74d0000000000ffffffffd6892a5aa54e3b8fe430efd23f49a8950733aaa9d7c915d9989179f48dd1905e0100000000ffffffff07c42b969286be06fae38528c85f0a1ce508d4df837eb5ac4cf5f2a7a9d65fa80000000000ffffffff02804f1200000000001600145360df8231ac5965147c9d90ca930a2aafb05232cb92040000000000160014bd92088bb7e82d611a9b94fbb74a0908152b784f02473044022041294880caa09bb1b653775310fcdd1458da6b8e7d7fae34e37966414fe115820220646397c9d2513edc5974ecc336e9b287de0cdf071c366f3b3dc3ff309213e4e401210217142f69535e4dad0dc7060df645c55a174cc1bfa5b9eb2e59aad2ae96072dfc0247304402201857bc6e6e48b46046a4bd204136fc77e24c240943fb5a1f0e86387aae59b34902200a7f31478784e51c49f46ef072745a4f263d7efdbc9c6784aa2571ff4f6f2a400121024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382024730440220764e3d5b3971c4b3e70b23fb700a7462a6fe519d9830e863a1f8388c402ad0b102207e777f7972c636961f92375a2774af3b7a2a04190251bbcb31d19c70927952dc0121024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb49338200000000"; { - EXPECT_EQ(outputData.size(), 786); + EXPECT_EQ(outputData.size(), 786ul); Bitcoin::Proto::SigningOutput output; ASSERT_TRUE(output.ParseFromArray(outputData.data(), (int)outputData.size())); - EXPECT_EQ(output.encoded().size(), 518); + EXPECT_EQ(output.encoded().size(), 518ul); EXPECT_EQ(hex(output.encoded()), ExpectedTx); } @@ -295,10 +295,10 @@ TEST(TransactionCompiler, BitcoinCompileWithSignatures) { { // Negative: not enough signatures const Data outputData = TransactionCompiler::compileWithSignatures(coin, txInputData, {signatureVec[0]}, pubkeyVec); - EXPECT_GT(outputData.size(), 1); + EXPECT_GT(outputData.size(), 1ul); Bitcoin::Proto::SigningOutput output; ASSERT_TRUE(output.ParseFromArray(outputData.data(), (int)outputData.size())); - EXPECT_EQ(output.encoded().size(), 0); + EXPECT_EQ(output.encoded().size(), 0ul); EXPECT_EQ(output.error(), Common::Proto::Error_invalid_params); } { // Negative: invalid public key @@ -311,10 +311,10 @@ TEST(TransactionCompiler, BitcoinCompileWithSignatures) { {parse_hex("415502201857bc6e6e48b46046a4bd204136fc77e24c240943fb5a1f0e86387aae59b34902200a7f31478784e51c49f46ef072745a4f263d7efdbc9c6784aa2571ff4f6f3b51"), signatureVec[1], signatureVec[2]}, pubkeyVec); - EXPECT_EQ(outputData.size(), 2); + EXPECT_EQ(outputData.size(), 2ul); Bitcoin::Proto::SigningOutput output; ASSERT_TRUE(output.ParseFromArray(outputData.data(), (int)outputData.size())); - EXPECT_EQ(output.encoded().size(), 0); + EXPECT_EQ(output.encoded().size(), 0ul); EXPECT_EQ(output.error(), Common::Proto::Error_signing); } } @@ -356,7 +356,7 @@ TEST(TransactionCompiler, EthereumCompileWithSignatures) { /// Step 2: Obtain preimage hash const auto preImageHashes = TransactionCompiler::preImageHashes(coin, txInputData); - ASSERT_GT(preImageHashes.size(), 0); + ASSERT_GT(preImageHashes.size(), 0ul); TxCompiler::Proto::PreSigningOutput output; ASSERT_TRUE(output.ParseFromArray(preImageHashes.data(), int(preImageHashes.size()))); @@ -380,11 +380,11 @@ TEST(TransactionCompiler, EthereumCompileWithSignatures) { const auto ExpectedTx = "f86c0b8504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a0360a84fb41ad07f07c845fedc34cde728421803ebbaae392fc39c116b29fc07ba053bd9d1376e15a191d844db458893b928f3efbfee90c9febf51ab84c97966779"; { - EXPECT_EQ(outputData.size(), 183); + EXPECT_EQ(outputData.size(), 183ul); Ethereum::Proto::SigningOutput output; ASSERT_TRUE(output.ParseFromArray(outputData.data(), (int)outputData.size())); - EXPECT_EQ(output.encoded().size(), 110); + EXPECT_EQ(output.encoded().size(), 110ul); EXPECT_EQ(hex(output.encoded()), ExpectedTx); } diff --git a/tests/WalletConsoleTests.cpp b/tests/WalletConsoleTests.cpp index ec592aaf2dc..0e7dbf5a25c 100644 --- a/tests/WalletConsoleTests.cpp +++ b/tests/WalletConsoleTests.cpp @@ -26,7 +26,7 @@ static const string mnemonic1 = "edge defense waste choose enrich upon flee junk int countLines(const string& text) { int lines = 0; - for(int i = 0; i < text.length(); ++i) + for(auto i = 0ul; i < text.length(); ++i) { if (text[i] == '\n') ++lines; } diff --git a/tests/algorithm/erase_tests.cpp b/tests/algorithm/erase_tests.cpp index 42645f46757..6a0ca0c41aa 100644 --- a/tests/algorithm/erase_tests.cpp +++ b/tests/algorithm/erase_tests.cpp @@ -14,14 +14,14 @@ TEST(Algorithm, Erase) { std::iota(cnt.begin(), cnt.end(), '0'); cnt.back() = '3'; std::size_t nbElementsErased = TW::erase(cnt, '3'); - ASSERT_EQ(cnt.size(), 8); - ASSERT_EQ(nbElementsErased, 2); + ASSERT_EQ(cnt.size(), 8ul); + ASSERT_EQ(nbElementsErased, 2ul); } TEST(Algorithm, EraseIf) { std::vector cnt(10); std::iota(cnt.begin(), cnt.end(), '0'); auto erased = TW::erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; }); - ASSERT_EQ(cnt.size(), 5); - ASSERT_EQ(erased, 5); -} \ No newline at end of file + ASSERT_EQ(cnt.size(), 5ul); + ASSERT_EQ(erased, 5ul); +} diff --git a/tests/interface/TWBase32Tests.cpp b/tests/interface/TWBase32Tests.cpp index d426ed1e23b..c8d826dad86 100644 --- a/tests/interface/TWBase32Tests.cpp +++ b/tests/interface/TWBase32Tests.cpp @@ -22,7 +22,7 @@ TEST(TWBase32, Decode) { auto result = WRAPD(TWBase32Decode(encodedInput.get())); ASSERT_NE(result, nullptr); - ASSERT_EQ(TWDataSize(result.get()), 10); + ASSERT_EQ(TWDataSize(result.get()), 10ul); auto data = *reinterpret_cast(result.get()); std::string str(data.begin(), data.end()); @@ -36,7 +36,7 @@ TEST(TWBase32, DecodeWithAlphabet) { auto result = WRAPD(TWBase32DecodeWithAlphabet(encodedInput.get(), filecoinAlphabet.get())); ASSERT_NE(result, nullptr); - ASSERT_EQ(TWDataSize(result.get()), 39); + ASSERT_EQ(TWDataSize(result.get()), 39ul); auto data = *reinterpret_cast(result.get()); std::string str(data.begin(), data.end()); diff --git a/tests/interface/TWDataTests.cpp b/tests/interface/TWDataTests.cpp index 6e648769c57..73c287d5a2e 100644 --- a/tests/interface/TWDataTests.cpp +++ b/tests/interface/TWDataTests.cpp @@ -12,7 +12,7 @@ TEST(TWData, CreateWithHexString) { { const auto data = WRAPD(TWDataCreateWithHexString(STRING("deadbeef").get())); - ASSERT_EQ(TWDataSize(data.get()), 4); + ASSERT_EQ(TWDataSize(data.get()), 4ul); EXPECT_EQ(TWDataBytes(data.get())[0], 0xde); EXPECT_EQ(TWDataBytes(data.get())[1], 0xad); EXPECT_EQ(TWDataBytes(data.get())[2], 0xbe); @@ -22,7 +22,7 @@ TEST(TWData, CreateWithHexString) { { const auto data = WRAPD(TWDataCreateWithHexString(STRING("00").get())); - ASSERT_EQ(TWDataSize(data.get()), 1); + ASSERT_EQ(TWDataSize(data.get()), 1ul); EXPECT_EQ(TWDataBytes(data.get())[0], 0); assertHexEqual(data, "00"); } @@ -60,10 +60,10 @@ TEST(TWData, CreateWithBytes) { } TEST(TWData, CreateWithSize) { - int n = 12; + std::size_t n = 12; const auto data = WRAPD(TWDataCreateWithSize(n)); ASSERT_EQ(TWDataSize(data.get()), n); - for (int i = 0; i < n; ++i) { + for (auto i = 0ul; i < n; ++i) { EXPECT_EQ(TWDataBytes(data.get())[i], 0); } } diff --git a/tests/interface/TWDataVectorTests.cpp b/tests/interface/TWDataVectorTests.cpp index 4f25c22acdf..38779f4bb92 100644 --- a/tests/interface/TWDataVectorTests.cpp +++ b/tests/interface/TWDataVectorTests.cpp @@ -17,7 +17,7 @@ TEST(TWDataVector, CreateDelete) { auto vec = TWDataVectorCreate(); ASSERT_TRUE(vec != nullptr); - EXPECT_EQ(TWDataVectorSize(vec), 0); + EXPECT_EQ(TWDataVectorSize(vec), 0ul); TWDataVectorDelete(vec); } @@ -26,7 +26,7 @@ TEST(TWDataVector, CreateWrapAutoDelete) { auto vec = WRAP(TWDataVector, TWDataVectorCreate()); ASSERT_TRUE(vec.get() != nullptr); - EXPECT_EQ(TWDataVectorSize(vec.get()), 0); + EXPECT_EQ(TWDataVectorSize(vec.get()), 0ul); } TEST(TWDataVector, CreateWithData) { @@ -35,7 +35,7 @@ TEST(TWDataVector, CreateWithData) { const auto vec = WRAP(TWDataVector, TWDataVectorCreateWithData(elem1.get())); ASSERT_TRUE(vec.get() != nullptr); - ASSERT_EQ(TWDataVectorSize(vec.get()), 1); + ASSERT_EQ(TWDataVectorSize(vec.get()), 1ul); const auto readElem1 = WRAPD(TWDataVectorGet(vec.get(), 0)); EXPECT_EQ(hex(*static_cast(readElem1.get())), "deadbeef"); @@ -45,13 +45,13 @@ TEST(TWDataVector, Add) { const auto vec = WRAP(TWDataVector, TWDataVectorCreate()); ASSERT_TRUE(vec.get() != nullptr); - EXPECT_EQ(TWDataVectorSize(vec.get()), 0); + EXPECT_EQ(TWDataVectorSize(vec.get()), 0ul); const auto elem1d = parse_hex("deadbeef"); const auto elem1 = WRAPD(TWDataCreateWithBytes(elem1d.data(), elem1d.size())); TWDataVectorAdd(vec.get(), elem1.get()); - ASSERT_EQ(TWDataVectorSize(vec.get()), 1); + ASSERT_EQ(TWDataVectorSize(vec.get()), 1ul); const auto readElem1 = WRAPD(TWDataVectorGet(vec.get(), 0)); EXPECT_EQ(hex(*static_cast(readElem1.get())), "deadbeef"); @@ -59,7 +59,7 @@ TEST(TWDataVector, Add) { const auto elem2 = WRAPD(TWDataCreateWithBytes(elem2d.data(), elem2d.size())); TWDataVectorAdd(vec.get(), elem2.get()); - ASSERT_EQ(TWDataVectorSize(vec.get()), 2); + ASSERT_EQ(TWDataVectorSize(vec.get()), 2ul); const auto readElem2 = WRAPD(TWDataVectorGet(vec.get(), 1)); EXPECT_EQ(hex(*static_cast(readElem2.get())), "0202"); } @@ -70,7 +70,7 @@ TEST(TWDataVector, Get) { const auto vec = WRAP(TWDataVector, TWDataVectorCreateWithData(elem1.get())); ASSERT_TRUE(vec.get() != nullptr); - ASSERT_EQ(TWDataVectorSize(vec.get()), 1); + ASSERT_EQ(TWDataVectorSize(vec.get()), 1ul); { // Get element const auto readElem1 = WRAPD(TWDataVectorGet(vec.get(), 0)); diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp index 099b3b377cf..dddffb8b517 100644 --- a/tests/interface/TWHDWalletTests.cpp +++ b/tests/interface/TWHDWalletTests.cpp @@ -290,7 +290,7 @@ TEST(HDWallet, DeriveCardano) { auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeCardano)); auto privateKeyData = WRAPD(TWPrivateKeyData(privateKey.get())); - EXPECT_EQ(TWDataSize(privateKeyData.get()), 192); + EXPECT_EQ(TWDataSize(privateKeyData.get()), 192ul); auto address = WRAPS(TWCoinTypeDeriveAddress(TWCoinTypeCardano, privateKey.get())); assertHexEqual(privateKeyData, "f8a3b8ad30e62c369b939336c2035aba26d1ffad135e6f346f2a370517a14952e73d20aeadf906bc8b531900fb6c3ed4a05b16973c10ae24650b68b26fae4ee5d97418ba7f3b2707fae963041ff5f174195d1578da09478ad2d17a1ecc00cad478a8ca3be214870accd41f008d70e3b4b59b5981ca933d6d3f389ad317a14952166d8fd329ae3fab4712da739efc2ded9b3eef2b1a8e225dd3dddeb4f065a729b297d9fa76b8852eef235c25aac8f0ff6209ab7251f2a84c83b3b5f1161f7c59"); diff --git a/tests/interface/TWPublicKeyTests.cpp b/tests/interface/TWPublicKeyTests.cpp index d20fa431dcb..39d06485ff9 100644 --- a/tests/interface/TWPublicKeyTests.cpp +++ b/tests/interface/TWPublicKeyTests.cpp @@ -49,20 +49,20 @@ TEST(TWPublicKeyTests, CompressedExtended) { const auto privateKey = WRAP(TWPrivateKey, new TWPrivateKey{ key }); auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(privateKey.get(), true)); EXPECT_EQ(TWPublicKeyKeyType(publicKey.get()), TWPublicKeyTypeSECP256k1); - EXPECT_EQ(publicKey.get()->impl.bytes.size(), 33); + EXPECT_EQ(publicKey.get()->impl.bytes.size(), 33ul); EXPECT_EQ(TWPublicKeyIsCompressed(publicKey.get()), true); EXPECT_TRUE(TWPublicKeyIsValid(publicKey.get(), TWPublicKeyTypeSECP256k1)); auto extended = WRAP(TWPublicKey, TWPublicKeyUncompressed(publicKey.get())); EXPECT_EQ(TWPublicKeyKeyType(extended.get()), TWPublicKeyTypeSECP256k1Extended); - EXPECT_EQ(extended.get()->impl.bytes.size(), 65); + EXPECT_EQ(extended.get()->impl.bytes.size(), 65ul); EXPECT_EQ(TWPublicKeyIsCompressed(extended.get()), false); EXPECT_TRUE(TWPublicKeyIsValid(extended.get(), TWPublicKeyTypeSECP256k1Extended)); auto compressed = WRAP(TWPublicKey, TWPublicKeyCompressed(extended.get())); //EXPECT_TRUE(compressed == publicKey.get()); EXPECT_EQ(TWPublicKeyKeyType(compressed.get()), TWPublicKeyTypeSECP256k1); - EXPECT_EQ(compressed.get()->impl.bytes.size(), 33); + EXPECT_EQ(compressed.get()->impl.bytes.size(), 33ul); EXPECT_EQ(TWPublicKeyIsCompressed(compressed.get()), true); EXPECT_TRUE(TWPublicKeyIsValid(compressed.get(), TWPublicKeyTypeSECP256k1)); } diff --git a/tests/interface/TWStoredKeyTests.cpp b/tests/interface/TWStoredKeyTests.cpp index ff1518b3ed4..9c34ea41a89 100644 --- a/tests/interface/TWStoredKeyTests.cpp +++ b/tests/interface/TWStoredKeyTests.cpp @@ -109,11 +109,11 @@ TEST(TWStoredKey, addressAddRemove) { const auto accountAddress = WRAPS(TWAccountAddress(accountCoin.get())); EXPECT_EQ(string(TWStringUTF8Bytes(accountAddress.get())), "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"); - EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 1); + EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 1ul); const auto accountIdx = WRAP(TWAccount, TWStoredKeyAccount(key.get(), 0)); TWStoredKeyRemoveAccountForCoin(key.get(), coin); - EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 0); + EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 0ul); const auto addressAdd = "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"; const auto derivationPath = "m/84'/0'/0'/0/0"; @@ -126,7 +126,7 @@ TEST(TWStoredKey, addressAddRemove) { WRAPS(TWStringCreateWithUTF8Bytes(derivationPath)).get(), WRAPS(TWStringCreateWithUTF8Bytes(pubKey)).get(), WRAPS(TWStringCreateWithUTF8Bytes(extPubKeyAdd)).get()); - EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 1); + EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 1ul); // invalid account index EXPECT_EQ(TWStoredKeyAccount(key.get(), 1001), nullptr); @@ -144,17 +144,17 @@ TEST(TWStoredKey, addressAddRemoveDerivationPath) { const auto accountAddress = WRAPS(TWAccountAddress(accountCoin.get())); EXPECT_EQ(string(TWStringUTF8Bytes(accountAddress.get())), "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"); - EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 1); + EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 1ul); const auto accountIdx = WRAP(TWAccount, TWStoredKeyAccount(key.get(), 0)); const auto derivationPath0 = "m/84'/0'/0'/0/0"; const auto derivationPath1 = "m/84'/0'/0'/1/0"; TWStoredKeyRemoveAccountForCoinDerivationPath(key.get(), coin, WRAPS(TWStringCreateWithUTF8Bytes(derivationPath1)).get()); - EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 1); + EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 1ul); TWStoredKeyRemoveAccountForCoinDerivationPath(key.get(), coin, WRAPS(TWStringCreateWithUTF8Bytes(derivationPath0)).get()); - EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 0); + EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 0ul); } TEST(TWStoredKey, addressAddDerivation) { @@ -173,7 +173,7 @@ TEST(TWStoredKey, addressAddDerivation) { const auto accountAddress2 = WRAPS(TWAccountAddress(accountCoin2.get())); EXPECT_EQ(string(TWStringUTF8Bytes(accountAddress2.get())), "1NyRyFewhZcWMa9XCj3bBxSXPXyoSg8dKz"); - EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 2); + EXPECT_EQ(TWStoredKeyAccountCount(key.get()), 2ul); } TEST(TWStoredKey, exportJSON) { @@ -202,7 +202,7 @@ TEST(TWStoredKey, storeAndImportJSON) { Data json(length); size_t idx = 0; // read the slow way, ifs.read gave some false warnings with codacy - while (!ifs.eof() && idx < length) { char c = ifs.get(); json[idx++] = (uint8_t)c; } + while (!ifs.eof() && idx < static_cast(length)) { char c = ifs.get(); json[idx++] = (uint8_t)c; } const auto key2 = WRAP(TWStoredKey, TWStoredKeyImportJSON(WRAPD(TWDataCreateWithData(&json)).get())); const auto name2 = WRAPS(TWStoredKeyName(key2.get())); @@ -250,11 +250,11 @@ TEST(TWStoredKey, removeAccountForCoin) { ASSERT_NE(WRAP(TWAccount, TWStoredKeyAccountForCoin(key.get(), TWCoinTypeEthereum, wallet.get())).get(), nullptr); ASSERT_NE(WRAP(TWAccount, TWStoredKeyAccountForCoin(key.get(), TWCoinTypeBitcoin, wallet.get())).get(), nullptr); - ASSERT_EQ(TWStoredKeyAccountCount(key.get()), 2); + ASSERT_EQ(TWStoredKeyAccountCount(key.get()), 2ul); TWStoredKeyRemoveAccountForCoin(key.get(), TWCoinTypeBitcoin); - ASSERT_EQ(TWStoredKeyAccountCount(key.get()), 1); + ASSERT_EQ(TWStoredKeyAccountCount(key.get()), 1ul); ASSERT_NE(WRAP(TWAccount, TWStoredKeyAccountForCoin(key.get(), TWCoinTypeEthereum, nullptr)).get(), nullptr); ASSERT_EQ(WRAP(TWAccount, TWStoredKeyAccountForCoin(key.get(), TWCoinTypeBitcoin, nullptr)).get(), nullptr); @@ -281,7 +281,7 @@ TEST(TWStoredKey, encryptionParameters) { // compare some specific parameters EXPECT_EQ(jsonParams["kdfparams"]["n"], 16384); - EXPECT_EQ(std::string(jsonParams["cipherparams"]["iv"]).length(), 32); + EXPECT_EQ(std::string(jsonParams["cipherparams"]["iv"]).length(), 32ul); // compare all keys, except dynamic ones (like cipherparams/iv) jsonParams["cipherparams"] = {}; diff --git a/tests/interface/TWTransactionCompilerTests.cpp b/tests/interface/TWTransactionCompilerTests.cpp index c5cb1b40f57..4cb3bd77a1b 100644 --- a/tests/interface/TWTransactionCompilerTests.cpp +++ b/tests/interface/TWTransactionCompilerTests.cpp @@ -86,7 +86,7 @@ TEST(TWTransactionCompiler, ExternalSignatureSignBinance) { const auto ExpectedTx = "b801f0625dee0a462a2c87fa0a1f0a1440c2979694bbc961023d1d27be6fc4d21a9febe612070a03424e421001121f0a14bffe47abfaede50419c577f1074fee6dd1535cd112070a03424e421001126a0a26eb5ae98721026a35920088d98c3888ca68c53dfc93f4564602606cbb87f0fe5ee533db38e50212401b1181faec30b60a2ddaa2804c253cf264c69180ec31814929b5de62088c0c5a45e8a816d1208fc5366bb8b041781a6771248550d04094c3d7a504f9e8310679"; { - EXPECT_EQ(TWDataSize(outputData.get()), 189); + EXPECT_EQ(TWDataSize(outputData.get()), 189ul); Binance::Proto::SigningOutput output; ASSERT_TRUE(output.ParseFromArray(TWDataBytes(outputData.get()), (int)TWDataSize(outputData.get()))); @@ -172,11 +172,11 @@ TEST(TWTransactionCompiler, ExternalSignatureSignEthereum) { const auto ExpectedTx = "f86c0b8504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a0360a84fb41ad07f07c845fedc34cde728421803ebbaae392fc39c116b29fc07ba053bd9d1376e15a191d844db458893b928f3efbfee90c9febf51ab84c97966779"; { - EXPECT_EQ(TWDataSize(outputData.get()), 183); + EXPECT_EQ(TWDataSize(outputData.get()), 183ul); Ethereum::Proto::SigningOutput output; ASSERT_TRUE(output.ParseFromArray(TWDataBytes(outputData.get()), (int)TWDataSize(outputData.get()))); - EXPECT_EQ(output.encoded().size(), 110); + EXPECT_EQ(output.encoded().size(), 110ul); EXPECT_EQ(hex(output.encoded()), ExpectedTx); } @@ -369,11 +369,11 @@ TEST(TWTransactionCompiler, ExternalSignatureSignBitcoin) { const auto ExpectedTx = "010000000001036021efcf7555f90627364339fc921139dd40a06ccb2cb2a2a4f8f4ea7a2dc74d0000000000ffffffffd6892a5aa54e3b8fe430efd23f49a8950733aaa9d7c915d9989179f48dd1905e0100000000ffffffff07c42b969286be06fae38528c85f0a1ce508d4df837eb5ac4cf5f2a7a9d65fa80000000000ffffffff02804f1200000000001600145360df8231ac5965147c9d90ca930a2aafb05232cb92040000000000160014bd92088bb7e82d611a9b94fbb74a0908152b784f02473044022041294880caa09bb1b653775310fcdd1458da6b8e7d7fae34e37966414fe115820220646397c9d2513edc5974ecc336e9b287de0cdf071c366f3b3dc3ff309213e4e401210217142f69535e4dad0dc7060df645c55a174cc1bfa5b9eb2e59aad2ae96072dfc0247304402201857bc6e6e48b46046a4bd204136fc77e24c240943fb5a1f0e86387aae59b34902200a7f31478784e51c49f46ef072745a4f263d7efdbc9c6784aa2571ff4f6f2a400121024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382024730440220764e3d5b3971c4b3e70b23fb700a7462a6fe519d9830e863a1f8388c402ad0b102207e777f7972c636961f92375a2774af3b7a2a04190251bbcb31d19c70927952dc0121024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb49338200000000"; { - EXPECT_EQ(TWDataSize(outputData.get()), 786); + EXPECT_EQ(TWDataSize(outputData.get()), 786ul); Bitcoin::Proto::SigningOutput output; ASSERT_TRUE(output.ParseFromArray(TWDataBytes(outputData.get()), (int)TWDataSize(outputData.get()))); - EXPECT_EQ(output.encoded().size(), 518); + EXPECT_EQ(output.encoded().size(), 518ul); EXPECT_EQ(hex(output.encoded()), ExpectedTx); } diff --git a/walletconsole/lib/Address.cpp b/walletconsole/lib/Address.cpp index 48f6aa9e65c..7a082f7413c 100644 --- a/walletconsole/lib/Address.cpp +++ b/walletconsole/lib/Address.cpp @@ -53,7 +53,7 @@ bool Address::addrPri(const string& coinid, const string& prikey_in, string& res return true; } -bool Address::addr(const string& coinid, const string& addrStr, string& res) { +bool Address::addr(const string& coinid, const string& addrStr, [[maybe_unused]] string& res) { Coin coin; if (!_coins.findCoin(coinid, coin)) { return false; } auto ctype = (TWCoinType)coin.c; diff --git a/walletconsole/lib/Buffer.cpp b/walletconsole/lib/Buffer.cpp index 3c79030c7b2..27f40a7e596 100644 --- a/walletconsole/lib/Buffer.cpp +++ b/walletconsole/lib/Buffer.cpp @@ -43,7 +43,7 @@ bool Buffer::prepareInput(const string& in, string& in_out) { int n = std::stoi(in2.substr(1)); // of the form #n int idx = n - 1; - if (idx < 0 || idx >= _prev.size()) { + if (idx < 0 || idx >= static_cast(_prev.size())) { _out << "Requested " << in2 << ", but out of range of buffers (n=" << _prev.size() << ")." << endl; return false; } @@ -58,7 +58,7 @@ bool Buffer::prepareInput(const string& in, string& in_out) { void Buffer::buffer() const { _out << "Last value: " << _last.get() << endl; _out << _prev.size() << " previous values:" << endl; - for (int i = 0; i < _prev.size(); ++i) { + for (auto i = 0ul; i < _prev.size(); ++i) { _out << " #" << i + 1 << " " << _prev[i].get() << endl; } } diff --git a/walletconsole/lib/CommandExecutor.cpp b/walletconsole/lib/CommandExecutor.cpp index e20be755518..973c2cf4dd7 100644 --- a/walletconsole/lib/CommandExecutor.cpp +++ b/walletconsole/lib/CommandExecutor.cpp @@ -189,7 +189,7 @@ string CommandExecutor::parseLine(const string& line, vector& params) { return cmd; } -bool CommandExecutor::checkMinParams(const vector& params, int n) const { +bool CommandExecutor::checkMinParams(const vector& params, std::size_t n) const { if (params.size() - 1 >= n) { return true; } diff --git a/walletconsole/lib/CommandExecutor.h b/walletconsole/lib/CommandExecutor.h index 1177d987266..a722e47c1fc 100644 --- a/walletconsole/lib/CommandExecutor.h +++ b/walletconsole/lib/CommandExecutor.h @@ -46,7 +46,7 @@ class CommandExecutor { static string parseLine(const string& line, vector& params); bool prepareInputs(const vector& p_in, vector& p_out); bool setCoin(const string& coin, bool force); - bool checkMinParams(const vector& params, int n) const; + bool checkMinParams(const vector& params, std::size_t n) const; void help() const; }; diff --git a/walletconsole/lib/Keys.cpp b/walletconsole/lib/Keys.cpp index 772f83a8a62..974e3f46e38 100644 --- a/walletconsole/lib/Keys.cpp +++ b/walletconsole/lib/Keys.cpp @@ -65,7 +65,7 @@ bool Keys::pubPri(const string& coinid, const string& p, string& res) { } } -bool Keys::priPub(const string& p, string& res) { +bool Keys::priPub([[maybe_unused]] const string& p, [[maybe_unused]] string& res) { _out << "Not yet implemented! :)" << endl; return false; } @@ -77,7 +77,7 @@ void Keys::setMnemonic(const vector& param) { } // concatenate string mnem = ""; - for (int i = 1; i < param.size(); ++i) { + for (auto i = 1ul; i < param.size(); ++i) { if (i > 1) mnem += " "; mnem += param[i]; } diff --git a/walletconsole/lib/Util.cpp b/walletconsole/lib/Util.cpp index eea581e34e5..86dd938dc84 100644 --- a/walletconsole/lib/Util.cpp +++ b/walletconsole/lib/Util.cpp @@ -48,7 +48,7 @@ bool Util::base64Decode(const string& p, string& res) { } } -bool Util::fileW(const string& fileName, const string& data, string& res) { +bool Util::fileW(const string& fileName, const string& data, [[maybe_unused]] string& res) { if (fileExists(fileName)) { _out << "Warning: File '" << fileName << "' already exists, not overwriting to be safe." << endl; return false; From 031bee34361e537aa51c906754284b5630454578 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Wed, 27 Jul 2022 12:10:30 +0200 Subject: [PATCH 038/497] Cardano: Support Enterprise and Reward address types (#2414) * Cardano: Support Enterprise and Reward address types * Review findings, minor * Remove unused parameter (review) * string::starts_with (review) --- src/Cardano/AddressV3.cpp | 77 ++++++++++++++++++++++++---------- src/Cardano/AddressV3.h | 25 +++++++++-- tests/Cardano/AddressTests.cpp | 73 +++++++++++++++++++++++++++++--- 3 files changed, 144 insertions(+), 31 deletions(-) diff --git a/src/Cardano/AddressV3.cpp b/src/Cardano/AddressV3.cpp index 50ebb4ae7d7..81726329e23 100644 --- a/src/Cardano/AddressV3.cpp +++ b/src/Cardano/AddressV3.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -20,7 +20,40 @@ using namespace TW; using namespace TW::Cardano; using namespace std; -bool AddressV3::parseAndCheckV3(const std::string& addr, NetworkId& networkId, Kind& kind, Data& raw) { +bool AddressV3::checkLength(Kind kind, size_t length) noexcept { + switch (kind) + { + case Kind_Base: + return (length == EncodedSize2); + + case Kind_Enterprise: + case Kind_Reward: + return (length == EncodedSize1); + + default: + // accept other types as well + return true; + } +} + +bool AddressV3::parseAndCheckV3(const Data& raw, NetworkId& networkId, Kind& kind, Data& bytes) noexcept { + if (raw.size() < 1ul) { + // too short, cannot extract kind and networkId + return false; + } + kind = kindFromFirstByte(raw[0]); + networkId = networkIdFromFirstByte(raw[0]); + if (networkId != Network_Production) { + return false; + } + + bytes = Data(); + std::copy(cbegin(raw) + 1, cend(raw), std::back_inserter(bytes)); + + return checkLength(kind, raw.size()); +} + +bool AddressV3::parseAndCheckV3(const std::string& addr, NetworkId& networkId, Kind& kind, Data& bytes) noexcept { try { auto bech = Bech32::decode(addr); if (std::get<1>(bech).size() == 0) { @@ -33,14 +66,16 @@ bool AddressV3::parseAndCheckV3(const std::string& addr, NetworkId& networkId, K if (!success) { return false; } - if (conv.size() != EncodedSize) { + + if (!parseAndCheckV3(conv, networkId, kind, bytes)) { + return false; + } + + // check prefix + if (const auto expectedHrp = getHrp(kind); !addr.starts_with(expectedHrp)) { return false; } - kind = kindFromFirstByte(conv[0]); - networkId = networkIdFromFirstByte(conv[0]); - raw = Data(conv.size() - 1); - std::copy(conv.begin() + 1, conv.end(), raw.begin()); return true; } catch (...) { return false; @@ -100,7 +135,7 @@ AddressV3 AddressV3::createBase(NetworkId networkId, const PublicKey& spendingKe AddressV3::AddressV3(const std::string& addr) { if (parseAndCheckV3(addr, networkId, kind, bytes)) { - // values stored + // values stored return; } // try legacy @@ -113,18 +148,11 @@ AddressV3::AddressV3(const PublicKey& publicKey) { if (publicKey.type != TWPublicKeyTypeED25519Cardano || publicKey.bytes.size() != PublicKey::cardanoKeySize) { throw std::invalid_argument("Invalid public key type"); } - kind = Kind_Base; - *this = createBase(Network_Production, PublicKey(subData(publicKey.bytes, 0, 32), TWPublicKeyTypeED25519), PublicKey(subData(publicKey.bytes, 64, 32), TWPublicKeyTypeED25519)); } AddressV3::AddressV3(const Data& data) { - if (data.size() != EncodedSize) { - throw std::invalid_argument("Address data too short"); - } - networkId = networkIdFromFirstByte(data[0]); - kind = kindFromFirstByte(data[0]); - bytes = subData(data, 1); + parseAndCheckV3(data, networkId, kind, bytes); } AddressV3::AddressV3(const AddressV3& other) = default; @@ -150,14 +178,19 @@ void AddressV3::operator=(const AddressV3& other) legacyAddressV2 = other.legacyAddressV2; } -string AddressV3::string() const { - std::string hrp; +std::string AddressV3::getHrp(Kind kind) noexcept { switch (kind) { - case Kind_Base: - hrp = stringForHRP(TWHRPCardano); break; - default: - hrp = ""; break; + case Kind_Base: + case Kind_Enterprise: + default: + return stringForHRP(TWHRPCardano); + case Kind_Reward: + return "stake"; } +} + +string AddressV3::string() const { + const auto hrp = getHrp(kind); return string(hrp); } diff --git a/src/Cardano/AddressV3.h b/src/Cardano/AddressV3.h index eff53d499b4..b8cbc615933 100644 --- a/src/Cardano/AddressV3.h +++ b/src/Cardano/AddressV3.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -24,13 +24,24 @@ class AddressV3 { }; enum Kind: uint8_t { - Kind_Base = 0, + Kind_Base = 0, // spending + staking key + //Kind_Base_Script_Key = 1, + //Kind_Base_Key_Script_Key = 2, + //Kind_Base_Script_Script_Key = 3, + //Kind_Pointer = 4, + //Kind_Pointer_Script = 5, + Kind_Enterprise = 6, // spending key + //Kind_Enterprise_Script = 7, + //Kind_Bootstrap = 8, // Byron + Kind_Reward = 14, // // staking key + //Kind_Reward_Script = 15, }; static const uint8_t HashSize = 28; // First byte header (kind, netowrkId) and 2 hashes - static const uint8_t EncodedSize = 1 + 2 * HashSize; + static const uint8_t EncodedSize1 = 1 + HashSize; + static const uint8_t EncodedSize2 = 1 + 2 * HashSize; NetworkId networkId = Network_Production; @@ -73,8 +84,14 @@ class AddressV3 { /// Returns the Bech string representation of the address, with given HRP. std::string string(const std::string& hrp) const; + /// Hrp of kind + static std::string getHrp(const Kind kind) noexcept; + /// Check whether data length is correct + static bool checkLength(Kind kind, size_t length) noexcept; + /// Check validity of binary address. + static bool parseAndCheckV3(const TW::Data& raw, NetworkId& networkId, Kind& kind, TW::Data& bytes) noexcept; /// Check validity and parse elements of a string address. Used internally by isValid and ctor. - static bool parseAndCheckV3(const std::string& addr, NetworkId& networkId, Kind& kind, TW::Data& raw); + static bool parseAndCheckV3(const std::string& addr, NetworkId& networkId, Kind& kind, TW::Data& bytes) noexcept; /// Return the binary data representation (keys appended, internal format) Data data() const; diff --git a/tests/Cardano/AddressTests.cpp b/tests/Cardano/AddressTests.cpp index a0d060b5687..0cd6eae62b8 100644 --- a/tests/Cardano/AddressTests.cpp +++ b/tests/Cardano/AddressTests.cpp @@ -36,18 +36,29 @@ TEST(CardanoAddress, V3NetworkIdKind) { TEST(CardanoAddress, Validation) { // valid V3 address ASSERT_TRUE(AddressV3::isValidLegacy("addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23")); - ASSERT_TRUE(AddressV3::isValidLegacy("addr1q92cmkgzv9h4e5q7mnrzsuxtgayvg4qr7y3gyx97ukmz3dfx7r9fu73vqn25377ke6r0xk97zw07dqr9y5myxlgadl2s0dgke5")); + + ASSERT_TRUE(AddressV3::isValid("addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23")); + ASSERT_TRUE(AddressV3::isValid("addr1q92cmkgzv9h4e5q7mnrzsuxtgayvg4qr7y3gyx97ukmz3dfx7r9fu73vqn25377ke6r0xk97zw07dqr9y5myxlgadl2s0dgke5")); + ASSERT_TRUE(AddressV3::isValid("addr1vyuca7esanpgs4ke0um3ft6f4yaeuz3ftpfqx9nxpct2uyqu7dvlp")); // enterprise + ASSERT_TRUE(AddressV3::isValid("stake1uy9ggsc9qls4pu9qvyyacwnmr9tt0gzcdt5s0zj4au8qkqc65geks")); // reward + ASSERT_TRUE(AddressV3::isValid("addr1sxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qmxapsy")); // kind 8 // valid V2 address ASSERT_TRUE(AddressV3::isValidLegacy("Ae2tdPwUPEZ18ZjTLnLVr9CEvUEUX4eW1LBHbxxxJgxdAYHrDeSCSbCxrvx")); ASSERT_TRUE(AddressV3::isValidLegacy("Ae2tdPwUPEZ6RUCnjGHFqi59k5WZLiv3HoCCNGCW8SYc5H9srdTzn1bec4W")); + ASSERT_FALSE(AddressV3::isValid("Ae2tdPwUPEZ18ZjTLnLVr9CEvUEUX4eW1LBHbxxxJgxdAYHrDeSCSbCxrvx")); + // valid V1 address ASSERT_TRUE(AddressV3::isValidLegacy("DdzFFzCqrhssmYoG5Eca1bKZFdGS8d6iag1mU4wbLeYcSPVvBNF2wRG8yhjzQqErbg63N6KJA4DHqha113tjKDpGEwS5x1dT2KfLSbSJ")); ASSERT_TRUE(AddressV3::isValidLegacy("DdzFFzCqrht7HGoJ87gznLktJGywK1LbAJT2sbd4txmgS7FcYLMQFhawb18ojS9Hx55mrbsHPr7PTraKh14TSQbGBPJHbDZ9QVh6Z6Di")); - // invalid V3, length (cardano-crypto.js) + // invalid V3, invalid network ASSERT_FALSE(AddressV3::isValidLegacy("addr1sna05l45z33zpkm8z44q8f0h57wxvm0c86e34wlmua7gtcrdgrdrzy8ny3walyfjanhe33nsyuh088qr5gepqaen6jsa9r94xvvd7fh6jc3e6x")); + // invalid V3, invalid prefix + ASSERT_FALSE(AddressV3::isValidLegacy("prefix1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35q3hm7lv")); + // invalid V3, length + ASSERT_FALSE(AddressV3::isValidLegacy("addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32xsmpqws7")); // invalid checksum V3 ASSERT_FALSE(AddressV3::isValidLegacy("PREFIX1qvqsyqcyq5rqwzqfpg9scrgwpugpzysnzs23v9ccrydpk8qarc0jqxuzx4s")); // invalid checksum V2 @@ -70,9 +81,8 @@ TEST(CardanoAddress, FromStringV2) { } } -TEST(CardanoAddress, FromStringV3) { +TEST(CardanoAddress, FromStringV3_Base) { { - // single addr auto address = AddressV3("addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq"); EXPECT_EQ(address.string(), "addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq"); EXPECT_EQ(address.string("addr"), "addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq"); @@ -82,6 +92,26 @@ TEST(CardanoAddress, FromStringV3) { } } +TEST(CardanoAddress, FromStringV3_Enterprise) { + { + auto address = AddressV3("addr1vyuca7esanpgs4ke0um3ft6f4yaeuz3ftpfqx9nxpct2uyqu7dvlp"); + EXPECT_EQ(address.string(), "addr1vyuca7esanpgs4ke0um3ft6f4yaeuz3ftpfqx9nxpct2uyqu7dvlp"); + EXPECT_EQ(AddressV3::Network_Production, address.networkId); + EXPECT_EQ(AddressV3::Kind_Enterprise, address.kind); + EXPECT_EQ("398efb30ecc28856d97f3714af49a93b9e0a2958520316660e16ae10", hex(address.bytes)); + } +} + +TEST(CardanoAddress, FromStringV3_Reward) { + { + auto address = AddressV3("stake1uy9ggsc9qls4pu9qvyyacwnmr9tt0gzcdt5s0zj4au8qkqc65geks"); + EXPECT_EQ(address.string(), "stake1uy9ggsc9qls4pu9qvyyacwnmr9tt0gzcdt5s0zj4au8qkqc65geks"); + EXPECT_EQ(AddressV3::Network_Production, address.networkId); + EXPECT_EQ(AddressV3::Kind_Reward, address.kind); + EXPECT_EQ("0a84430507e150f0a06109dc3a7b1956b7a0586ae9078a55ef0e0b03", hex(address.bytes)); + } +} + TEST(CardanoAddress, MnemonicToAddressV3) { { // Test from cardano-crypto.js; Test wallet @@ -223,7 +253,7 @@ TEST(CardanoAddress, KeyHashV2) { ASSERT_EQ("a1eda96a9952a56c983d9f49117f935af325e8a6c9d38496e945faa8", hex(hash)); } -TEST(CardanoAddress, FromDataV3) { +TEST(CardanoAddress, FromDataV3_Base) { auto address0 = AddressV3("addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq"); EXPECT_EQ(address0.string(), "addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq"); EXPECT_EQ(hex(address0.data()), "018d98bea0414243dc84070f96265577e7e6cf702d62e871016885034ecc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468"); @@ -242,6 +272,39 @@ TEST(CardanoAddress, FromDataV3) { } } +TEST(CardanoAddress, FromDataV3_Enterprise) { + auto address = AddressV3(parse_hex("61398efb30ecc28856d97f3714af49a93b9e0a2958520316660e16ae10")); + EXPECT_EQ(address.string(), "addr1vyuca7esanpgs4ke0um3ft6f4yaeuz3ftpfqx9nxpct2uyqu7dvlp"); + EXPECT_EQ(address.kind, AddressV3::Kind_Enterprise); + EXPECT_EQ(address.networkId, AddressV3::Network_Production); + EXPECT_EQ(hex(address.bytes), "398efb30ecc28856d97f3714af49a93b9e0a2958520316660e16ae10"); +} + +TEST(CardanoAddress, FromDataV3_Reward) { + auto address = AddressV3(parse_hex("e10a84430507e150f0a06109dc3a7b1956b7a0586ae9078a55ef0e0b03")); + EXPECT_EQ(address.string(), "stake1uy9ggsc9qls4pu9qvyyacwnmr9tt0gzcdt5s0zj4au8qkqc65geks"); + EXPECT_EQ(address.kind, AddressV3::Kind_Reward); + EXPECT_EQ(address.networkId, AddressV3::Network_Production); + EXPECT_EQ(hex(address.bytes), "0a84430507e150f0a06109dc3a7b1956b7a0586ae9078a55ef0e0b03"); +} + +TEST(CardanoAddress, FromDataV3_Invalid) { + { // base, invalid length + auto address = AddressV3(parse_hex("018d98bea0414243dc84070f96265577e7e6cf702d62e871016885034ecc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a34")); + EXPECT_EQ(address.string(), "addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32xsmpqws7"); + EXPECT_EQ(address.kind, AddressV3::Kind_Base); + EXPECT_EQ(address.networkId, AddressV3::Network_Production); + EXPECT_EQ(hex(address.bytes), "8d98bea0414243dc84070f96265577e7e6cf702d62e871016885034ecc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a34"); + } + { // kind = 8 + auto address = AddressV3(parse_hex("818d98bea0414243dc84070f96265577e7e6cf702d62e871016885034ecc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468")); + EXPECT_EQ(address.string(), "addr1sxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qmxapsy"); + EXPECT_EQ(address.kind, static_cast(8)); + EXPECT_EQ(address.networkId, AddressV3::Network_Production); + EXPECT_EQ(hex(address.bytes), "8d98bea0414243dc84070f96265577e7e6cf702d62e871016885034ecc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468"); + } +} + TEST(CardanoAddress, FromPublicKeyV2) { { // caradano-crypto.js test From ba7224cd8893e149926b9773206498c550b64ff7 Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Wed, 27 Jul 2022 18:51:00 +0100 Subject: [PATCH 039/497] Add TWBase64 interface exposing Base64 implementation (#2390) * Add TWBase64 interface exposing Base64 implementation Similarly to https://github.com/trustwallet/wallet-core/blob/master/include/TrustWalletCore/TWBase32.h, expose Base64 implementation from core library to Swift/Kotlin, issue: #2369 * Add Swift/Kotlin tests, minor fixes * Add wasm tests * Rewrite Base64 to fix wasm crash * format code Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- .../trustwallet/core/app/utils/TestBase64.kt | 34 +++++++++++ include/TrustWalletCore/TWBase64.h | 47 ++++++++++++++++ src/Base64.cpp | 11 +--- src/Base64.h | 2 +- src/interface/TWBase64.cpp | 37 ++++++++++++ swift/Tests/Base64Tests.swift | 38 +++++++++++++ tests/interface/TWBase64Tests.cpp | 56 +++++++++++++++++++ wasm/tests/Base32.test.ts | 56 +++++++++++-------- wasm/tests/Base64.test.ts | 42 ++++++++++++++ 9 files changed, 292 insertions(+), 31 deletions(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestBase64.kt create mode 100644 include/TrustWalletCore/TWBase64.h create mode 100644 src/interface/TWBase64.cpp create mode 100644 swift/Tests/Base64Tests.swift create mode 100644 tests/interface/TWBase64Tests.cpp create mode 100644 wasm/tests/Base64.test.ts diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestBase64.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestBase64.kt new file mode 100644 index 00000000000..b69851da1b8 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestBase64.kt @@ -0,0 +1,34 @@ +package com.trustwallet.core.app.utils + +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.Base64 + +class TestBase64 { + init { + System.loadLibrary("TrustWalletCore"); + } + + @Test + fun testEncode() { + assertEquals(Base64.encode("HelloWorld".toByteArray()), "SGVsbG9Xb3JsZA==") + } + + @Test + fun testDecode() { + val decoded = Base64.decode("SGVsbG9Xb3JsZA==") + assertEquals(String(decoded, Charsets.UTF_8), "HelloWorld") + } + + @Test + fun testEncodeUrl() { + assertEquals(Base64.encodeUrl("+\\?ab".toByteArray()), "K1w_YWI=") + } + + @Test + fun testDecodeUrl() { + val decoded = Base64.decodeUrl("K1w_YWI=") + assertEquals(String(decoded, Charsets.UTF_8), "+\\?ab") + } +} + diff --git a/include/TrustWalletCore/TWBase64.h b/include/TrustWalletCore/TWBase64.h new file mode 100644 index 00000000000..5dbaa20fcf7 --- /dev/null +++ b/include/TrustWalletCore/TWBase64.h @@ -0,0 +1,47 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +TW_EXPORT_STRUCT +struct TWBase64; + + +/// Decode a Base64 input with the default alphabet (RFC4648 with '+', '/') +/// +/// \param string Encoded input to be decoded +/// \return The decoded data +TW_EXPORT_STATIC_METHOD +TWData* _Nullable TWBase64Decode(TWString* _Nonnull string); + +/// Decode a Base64 input with the alphabet safe for URL-s and filenames (RFC4648 with '-', '_') +/// +/// \param string Encoded base64 input to be decoded +/// \return The decoded data +TW_EXPORT_STATIC_METHOD +TWData* _Nullable TWBase64DecodeUrl(TWString* _Nonnull string); + +/// Encode an input to Base64 with the default alphabet (RFC4648 with '+', '/') +/// +/// \param data Data to be encoded (raw bytes) +/// \return The encoded data +TW_EXPORT_STATIC_METHOD +TWString *_Nonnull TWBase64Encode(TWData *_Nonnull data); + +/// Encode an input to Base64 with the alphabet safe for URL-s and filenames (RFC4648 with '-', '_') +/// +/// \param data Data to be encoded (raw bytes) +/// \return The encoded data +TW_EXPORT_STATIC_METHOD +TWString *_Nonnull TWBase64EncodeUrl(TWData *_Nonnull data); + +TW_EXTERN_C_END diff --git a/src/Base64.cpp b/src/Base64.cpp index 92b51279c0a..cf4605592ad 100644 --- a/src/Base64.cpp +++ b/src/Base64.cpp @@ -63,14 +63,9 @@ void convertToBase64Url(string& b) { } Data decodeBase64Url(const string& val) { - try { - return decode(val); - } catch (const exception& ex) { - // 2nd try: Base64URL format (replaced by '-' and '_' by '+' and '/' ) - string base64Url = val; - convertFromBase64Url(base64Url); - return decode(base64Url); - } + string base64Url = val; + convertFromBase64Url(base64Url); + return decode(base64Url); } string encodeBase64Url(const Data& val) { diff --git a/src/Base64.h b/src/Base64.h index 089e1c21a93..5bc20e6fc70 100644 --- a/src/Base64.h +++ b/src/Base64.h @@ -20,7 +20,7 @@ std::string encode(const Data& val); // Base64Url format uses '-' and '_' as the two special characters, Base64 uses '+'and '/'. Data decodeBase64Url(const std::string& val); -// Encode bytes into Base64Url string (uses '-' and '_' as pecial characters) +// Encode bytes into Base64Url string (uses '-' and '_' as special characters) std::string encodeBase64Url(const Data& val); } // namespace TW::Base64 diff --git a/src/interface/TWBase64.cpp b/src/interface/TWBase64.cpp new file mode 100644 index 00000000000..c57a713e6e2 --- /dev/null +++ b/src/interface/TWBase64.cpp @@ -0,0 +1,37 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include + +#include "../Base64.h" + +#include + +using namespace TW; + +TWData* _Nullable TWBase64Decode(TWString* _Nonnull string) { + auto cppString = *reinterpret_cast(string); + Data decodedOut = Base64::decode(cppString); + return TWDataCreateWithData(&decodedOut); +} + +TWData* _Nullable TWBase64DecodeUrl(TWString* _Nonnull string) { + auto cppString = *reinterpret_cast(string); + Data decodedOut = Base64::decodeBase64Url(cppString); + return TWDataCreateWithData(&decodedOut); +} + +TWString *_Nonnull TWBase64Encode(TWData *_Nonnull data) { + auto cppData = *reinterpret_cast(data); + auto result = Base64::encode(cppData); + return TWStringCreateWithUTF8Bytes(result.c_str()); +} + +TWString *_Nonnull TWBase64EncodeUrl(TWData *_Nonnull data) { + auto cppData = *reinterpret_cast(data); + auto result = Base64::encodeBase64Url(cppData); + return TWStringCreateWithUTF8Bytes(result.c_str()); +} diff --git a/swift/Tests/Base64Tests.swift b/swift/Tests/Base64Tests.swift new file mode 100644 index 00000000000..b4fdc17c1cf --- /dev/null +++ b/swift/Tests/Base64Tests.swift @@ -0,0 +1,38 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import XCTest +import WalletCore + +class Base64Tests: XCTestCase { + func testEncode() { + let encoded = Base64.encode(data: Data.init(bytes: "HelloWorld", count: 10)); + XCTAssertEqual(encoded, "SGVsbG9Xb3JsZA=="); + } + + func testDecode() { + guard let decoded = Base64.decode(string: "SGVsbG9Xb3JsZA==") else { + return XCTFail(); + } + let toCompare = String(data: decoded, encoding:.utf8); + + XCTAssertEqual(toCompare, "HelloWorld"); + } + + func testUrlEncode() { + let encoded = Base64.encodeUrl(data: Data.init(bytes: "+\\?ab", count: 5)); + XCTAssertEqual(encoded, "K1w_YWI="); + } + + func testUrlDecode() { + guard let decoded = Base64.decodeUrl(string: "K1w_YWI=") else { + return XCTFail(); + } + let toCompare = String(data: decoded, encoding:.utf8); + + XCTAssertEqual(toCompare, "+\\?ab"); + } +} diff --git a/tests/interface/TWBase64Tests.cpp b/tests/interface/TWBase64Tests.cpp new file mode 100644 index 00000000000..15aa7fa7b05 --- /dev/null +++ b/tests/interface/TWBase64Tests.cpp @@ -0,0 +1,56 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "TWTestUtilities.h" + +#include "Data.h" +#include + +#include + +TEST(TWBase64, Decode) { + const auto encodedInput = STRING("Kyc/YWI="); + auto result = WRAPD(TWBase64Decode(encodedInput.get())); + + ASSERT_EQ(TWDataSize(result.get()), 5); + + auto data = *reinterpret_cast(result.get()); + std::string str(data.begin(), data.end()); + + ASSERT_EQ(str, "+\'?ab"); +} + +TEST(TWBase64, Encode) { + TW::Data data{'+', '\'', '?', 'a', 'b'}; + auto encodedStr = TWBase64Encode(&data); + std::string result = TWStringUTF8Bytes(encodedStr); + + ASSERT_EQ(result, "Kyc/YWI="); + + TWStringDelete(encodedStr); +} + +TEST(TWBase64, DecodeUrl) { + const auto encodedInput = STRING("Kyc_YWI="); + auto result = WRAPD(TWBase64DecodeUrl(encodedInput.get())); + + ASSERT_EQ(TWDataSize(result.get()), 5); + + auto data = *reinterpret_cast(result.get()); + std::string str(data.begin(), data.end()); + + ASSERT_EQ(str, "+\'?ab"); +} + +TEST(TWBase64, EncodeUrl) { + TW::Data data{'+', '\'', '?', 'a', 'b'}; + auto encodedStr = TWBase64EncodeUrl(&data); + std::string result = TWStringUTF8Bytes(encodedStr); + + ASSERT_EQ(result, "Kyc_YWI="); + + TWStringDelete(encodedStr); +} diff --git a/wasm/tests/Base32.test.ts b/wasm/tests/Base32.test.ts index 84b8edb1152..ada5219473f 100644 --- a/wasm/tests/Base32.test.ts +++ b/wasm/tests/Base32.test.ts @@ -4,40 +4,52 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -import {assert} from "chai"; -import {Buffer} from "buffer"; +import { assert } from "chai"; +import { Buffer } from "buffer"; import { WalletCore } from "../dist"; describe("Base32", () => { - it("test decrypting", () => { - const {Base32} = WalletCore; + it("test decrypting", () => { + const { Base32 } = WalletCore; - const decoded = Base32.decode("JBSWY3DPK5XXE3DE"); + const decoded = Base32.decode("JBSWY3DPK5XXE3DE"); - assert.equal(Buffer.from(decoded).toString(), "HelloWorld"); - }); + assert.equal(Buffer.from(decoded).toString(), "HelloWorld"); + }); - it("test decrypting with alphabet", () => { - const {Base32} = WalletCore; + it("test decrypting with alphabet", () => { + const { Base32 } = WalletCore; - const decoded = Base32.decodeWithAlphabet("g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i", "abcdefghijklmnopqrstuvwxyz234567"); + const decoded = Base32.decodeWithAlphabet( + "g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i", + "abcdefghijklmnopqrstuvwxyz234567" + ); - assert.equal(Buffer.from(decoded).toString(), "7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"); - }); + assert.equal( + Buffer.from(decoded).toString(), + "7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy" + ); + }); - it("test encrypting", () => { - const {Base32} = WalletCore; + it("test encrypting", () => { + const { Base32 } = WalletCore; - const encoded = Base32.encode(Buffer.from("HelloWorld")); + const encoded = Base32.encode(Buffer.from("HelloWorld")); - assert.equal(encoded, "JBSWY3DPK5XXE3DE"); - }); + assert.equal(encoded, "JBSWY3DPK5XXE3DE"); + }); - it("test encrypting with alphabet", () => { - const {Base32} = WalletCore; + it("test encrypting with alphabet", () => { + const { Base32 } = WalletCore; - const encoded = Base32.encodeWithAlphabet(Buffer.from("7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"), "abcdefghijklmnopqrstuvwxyz234567"); + const encoded = Base32.encodeWithAlphabet( + Buffer.from("7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"), + "abcdefghijklmnopqrstuvwxyz234567" + ); - assert.equal(encoded, "g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i"); - }); + assert.equal( + encoded, + "g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i" + ); + }); }); diff --git a/wasm/tests/Base64.test.ts b/wasm/tests/Base64.test.ts new file mode 100644 index 00000000000..ea5448a89fb --- /dev/null +++ b/wasm/tests/Base64.test.ts @@ -0,0 +1,42 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import { assert } from "chai"; +import { Buffer } from "buffer"; +import { WalletCore } from "../dist"; + +describe("Base64", () => { + it("test decoding", () => { + const { Base64 } = WalletCore; + + const decoded = Base64.decode("SGVsbG9Xb3JsZA=="); + + assert.equal(Buffer.from(decoded).toString(), "HelloWorld"); + }); + + it("test encoding", () => { + const { Base64 } = WalletCore; + + const encoded = Base64.encode(Buffer.from("HelloWorld")); + + assert.equal(encoded, "SGVsbG9Xb3JsZA=="); + }); + + it("test encoding (URL-safe)", () => { + const { Base64 } = WalletCore; + + const encoded = Base64.encodeUrl(Buffer.from("==?=")); + + assert.equal(encoded, "PT0_PQ=="); + }); + + it("test decoding (URL-safe)", () => { + const { Base64 } = WalletCore; + const decoded = Base64.decodeUrl("PT0_PQ=="); + + assert.equal(Buffer.from(decoded).toString(), "==?="); + }); +}); From f0ee735b8953c5a8d56b020b78188e39628b0f16 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 28 Jul 2022 09:23:17 +0800 Subject: [PATCH 040/497] try to use protobuf-lite for android (#2410) --- android/app/build.gradle | 2 +- .../trustwallet/core/app/blockchains/near/TestNEARSigner.kt | 4 ++-- .../core/app/blockchains/stellar/TestStellarSigner.kt | 1 - android/trustwalletcore/build.gradle | 2 +- jni/java/wallet/core/java/AnySigner.java | 6 +++--- tools/generate-files | 4 ++-- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 451d30ecf4d..f38c9acc235 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -42,7 +42,7 @@ dependencies { androidTestImplementation 'androidx.test:runner:1.3.0' androidTestImplementation 'android.arch.core:core-testing:1.1.1' - implementation 'com.google.protobuf:protobuf-java:3.21.2' + implementation 'com.google.protobuf:protobuf-javalite:3.21.2' } repositories { mavenCentral() diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/near/TestNEARSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/near/TestNEARSigner.kt index 3680868be56..8e5021abd4b 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/near/TestNEARSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/near/TestNEARSigner.kt @@ -26,9 +26,9 @@ class TestNEARSigner { signerId = "test.near" nonce = 1 receiverId = "whatever.near" - addActionsBuilder().apply { + addActions(NEAR.Action.newBuilder().apply { transfer = transferAction - } + }) blockHash = ByteString.copyFrom(Base58.decodeNoCheck("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM")) privateKey = ByteString.copyFrom(Base58.decodeNoCheck("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv").sliceArray(0..31)) }.build() diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/stellar/TestStellarSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/stellar/TestStellarSigner.kt index a0a35c869a5..a76ea84550a 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/stellar/TestStellarSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/stellar/TestStellarSigner.kt @@ -31,7 +31,6 @@ class TestStellarTransactionSigner { sequence = 2 passphrase = StellarPassphrase.STELLAR.toString() opPayment = operation.build() - memoVoid = memoVoidBuilder.build() privateKey = ByteString.copyFrom(PrivateKey("59a313f46ef1c23a9e4f71cea10fc0c56a2a6bb8a4b9ea3d5348823e5a478722".toHexByteArray()).data()) } diff --git a/android/trustwalletcore/build.gradle b/android/trustwalletcore/build.gradle index 7235ffb0656..bf97bfd2412 100644 --- a/android/trustwalletcore/build.gradle +++ b/android/trustwalletcore/build.gradle @@ -47,7 +47,7 @@ android { } dependencies { - implementation 'com.google.protobuf:protobuf-java:3.21.2' + implementation 'com.google.protobuf:protobuf-javalite:3.21.2' } apply from: 'maven-push.gradle' diff --git a/jni/java/wallet/core/java/AnySigner.java b/jni/java/wallet/core/java/AnySigner.java index 47f9b4fce9a..49c7770d3d1 100644 --- a/jni/java/wallet/core/java/AnySigner.java +++ b/jni/java/wallet/core/java/AnySigner.java @@ -6,13 +6,13 @@ package wallet.core.java; -import com.google.protobuf.Message; +import com.google.protobuf.MessageLite; import com.google.protobuf.Parser; import wallet.core.jni.CoinType; public class AnySigner { - public static T sign(Message input, CoinType coin, Parser parser) throws Exception { + public static T sign(MessageLite input, CoinType coin, Parser parser) throws Exception { byte[] data = input.toByteArray(); byte[] outputData = nativeSign(data, coin.value()); T output = parser.parseFrom(outputData); @@ -25,7 +25,7 @@ public static T sign(Message input, CoinType coin, Parser public static native boolean supportsJSON(int coin); - public static T plan(Message input, CoinType coin, Parser parser) throws Exception { + public static T plan(MessageLite input, CoinType coin, Parser parser) throws Exception { byte[] data = input.toByteArray(); byte[] outputData = nativePlan(data, coin.value()); T output = parser.parseFrom(outputData); diff --git a/tools/generate-files b/tools/generate-files index 08f968dd5af..75aec1ca64f 100755 --- a/tools/generate-files +++ b/tools/generate-files @@ -51,9 +51,9 @@ codegen/bin/codegen # Generate Java, C++ and Swift Protobuf files if [ -x "$(command -v protoc-gen-swift)" ]; then - "$PROTOC" -I=$PREFIX/include -I=src/proto --cpp_out=src/proto --java_out=jni/java --swift_out=swift/Sources/Generated/Protobuf --swift_opt=Visibility=Public src/proto/*.proto + "$PROTOC" -I=$PREFIX/include -I=src/proto --cpp_out=src/proto --java_out=lite:jni/java --swift_out=swift/Sources/Generated/Protobuf --swift_opt=Visibility=Public src/proto/*.proto else - "$PROTOC" -I=$PREFIX/include -I=src/proto --cpp_out=src/proto --java_out=jni/java src/proto/*.proto + "$PROTOC" -I=$PREFIX/include -I=src/proto --cpp_out=src/proto --java_out=lite:jni/java src/proto/*.proto fi # Generate internal message protocol Protobuf files From a15dea9023953bdaad4213db33740c4d16721dae Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Thu, 28 Jul 2022 16:17:36 +0200 Subject: [PATCH 041/497] Expose PrivateKeyType (#2416) * Expose PrivateKeyType * Add new TW .h file --- include/TrustWalletCore/TWPrivateKeyType.h | 20 ++++++++++++++++ src/HDWallet.cpp | 27 ++++++++-------------- src/HDWallet.h | 4 ---- src/PrivateKey.cpp | 11 ++++++++- src/PrivateKey.h | 11 ++++----- tests/PrivateKeyTests.cpp | 11 ++++++++- 6 files changed, 54 insertions(+), 30 deletions(-) create mode 100644 include/TrustWalletCore/TWPrivateKeyType.h diff --git a/include/TrustWalletCore/TWPrivateKeyType.h b/include/TrustWalletCore/TWPrivateKeyType.h new file mode 100644 index 00000000000..868b5d2dfea --- /dev/null +++ b/include/TrustWalletCore/TWPrivateKeyType.h @@ -0,0 +1,20 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" + +TW_EXTERN_C_BEGIN + +/// Private key types, the vast majority of chains use the default, 32-byte key. +TW_EXPORT_ENUM(uint32_t) +enum TWPrivateKeyType { + TWPrivateKeyTypeDefault = 0, // 32 bytes long + TWPrivateKeyTypeCardano = 1, // 2 extended keys plus chainCode, 96 bytes long, used by Cardano +}; + +TW_EXTERN_C_END diff --git a/src/HDWallet.cpp b/src/HDWallet.cpp index d1025d64457..624d96d5581 100644 --- a/src/HDWallet.cpp +++ b/src/HDWallet.cpp @@ -122,10 +122,10 @@ DerivationPath HDWallet::cardanoStakingDerivationPath(const DerivationPath& path PrivateKey HDWallet::getKey(TWCoinType coin, const DerivationPath& derivationPath) const { const auto curve = TWCoinTypeCurve(coin); - const auto privateKeyType = getPrivateKeyType(curve); + const auto privateKeyType = PrivateKey::getType(curve); auto node = getNode(*this, curve, derivationPath); switch (privateKeyType) { - case PrivateKeyTypeCardano: { + case TWPrivateKeyTypeCardano: { if (derivationPath.indices.size() < 4 || derivationPath.indices[3].value > 1) { // invalid derivation path return PrivateKey(Data(PrivateKey::cardanoKeySize)); @@ -146,7 +146,7 @@ PrivateKey HDWallet::getKey(TWCoinType coin, const DerivationPath& derivationPat return PrivateKey(pkData, extData, chainCode, pkData2, extData2, chainCode2); } - case PrivateKeyTypeDefault32: + case TWPrivateKeyTypeDefault: default: // default path auto data = Data(node.private_key, node.private_key + PrivateKey::size); @@ -249,15 +249,6 @@ std::optional HDWallet::getPrivateKeyFromExtended(const std::string& return PrivateKey(Data(node.private_key, node.private_key + 32)); } -PrivateKeyType HDWallet::getPrivateKeyType(TWCurve curve) { - switch (curve) { - case TWCurve::TWCurveED25519ExtendedCardano: - return PrivateKeyTypeCardano; - default: - return PrivateKeyTypeDefault32; - } -} - namespace { uint32_t fingerprint(HDNode* node, Hash::Hasher hasher) { @@ -317,14 +308,14 @@ bool deserialize(const std::string& extended, TWCurve curve, Hash::Hasher hasher } HDNode getNode(const HDWallet& wallet, TWCurve curve, const DerivationPath& derivationPath) { - const auto privateKeyType = HDWallet::getPrivateKeyType(curve); + const auto privateKeyType = PrivateKey::getType(curve); auto node = getMasterNode(wallet, curve); for (auto& index : derivationPath.indices) { switch (privateKeyType) { - case PrivateKeyTypeCardano: + case TWPrivateKeyTypeCardano: hdnode_private_ckd_cardano(&node, index.derivationIndex()); break; - case PrivateKeyTypeDefault32: + case TWPrivateKeyTypeDefault: default: hdnode_private_ckd(&node, index.derivationIndex()); break; @@ -334,10 +325,10 @@ HDNode getNode(const HDWallet& wallet, TWCurve curve, const DerivationPath& deri } HDNode getMasterNode(const HDWallet& wallet, TWCurve curve) { - const auto privateKeyType = HDWallet::getPrivateKeyType(curve); + const auto privateKeyType = PrivateKey::getType(curve); HDNode node; switch (privateKeyType) { - case PrivateKeyTypeCardano: { + case TWPrivateKeyTypeCardano: { // Derives the root Cardano HDNode from a passphrase and the entropy encoded in // a BIP-0039 mnemonic using the Icarus derivation (V2) scheme const auto entropy = wallet.getEntropy(); @@ -347,7 +338,7 @@ HDNode getMasterNode(const HDWallet& wallet, TWCurve curve) { TW::memzero(secret, CARDANO_SECRET_LENGTH); break; } - case PrivateKeyTypeDefault32: + case TWPrivateKeyTypeDefault: default: hdnode_from_seed(wallet.getSeed().data(), HDWallet::seedSize, curveName(curve), &node); break; diff --git a/src/HDWallet.h b/src/HDWallet.h index 549ee6e9ebd..ecb37e0fc95 100644 --- a/src/HDWallet.h +++ b/src/HDWallet.h @@ -122,10 +122,6 @@ class HDWallet { /// Computes the private key from an extended private key representation. static std::optional getPrivateKeyFromExtended(const std::string& extended, TWCoinType coin, const DerivationPath& path); - public: - // obtain privateKeyType used by the coin/curve - static PrivateKeyType getPrivateKeyType(TWCurve curve); - private: void updateSeedAndEntropy(bool check = true); diff --git a/src/PrivateKey.cpp b/src/PrivateKey.cpp index df34b7e34f9..e5fb5168573 100644 --- a/src/PrivateKey.cpp +++ b/src/PrivateKey.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -75,6 +75,15 @@ bool PrivateKey::isValid(const Data& data, TWCurve curve) { return true; } +TWPrivateKeyType PrivateKey::getType(TWCurve curve) noexcept { + switch (curve) { + case TWCurve::TWCurveED25519ExtendedCardano: + return TWPrivateKeyTypeCardano; + default: + return TWPrivateKeyTypeDefault; + } +} + PrivateKey::PrivateKey(const Data& data) { if (!isValid(data)) { throw std::invalid_argument("Invalid private key data"); diff --git a/src/PrivateKey.h b/src/PrivateKey.h index 79108fec245..a2ac177df5d 100644 --- a/src/PrivateKey.h +++ b/src/PrivateKey.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,15 +9,11 @@ #include "Data.h" #include "PublicKey.h" +#include #include namespace TW { -enum PrivateKeyType { - PrivateKeyTypeDefault32 = 0, // 32 bytes private key. - PrivateKeyTypeCardano = 1, // 96 bytes private key. -}; - class PrivateKey { public: /// The number of bytes in a private key. @@ -44,6 +40,9 @@ class PrivateKey { /// Determines if a collection of bytes and curve make a valid private key. static bool isValid(const Data& data, TWCurve curve); + // obtain private key type used by the curve/coin + static TWPrivateKeyType getType(TWCurve curve) noexcept; + /// Initializes a private key with an array of bytes. Size must be exact (normally 32, or 192 for extended) explicit PrivateKey(const Data& data); diff --git a/tests/PrivateKeyTests.cpp b/tests/PrivateKeyTests.cpp index 1f33ef7f8a8..e52ea08dfba 100644 --- a/tests/PrivateKeyTests.cpp +++ b/tests/PrivateKeyTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -167,6 +167,15 @@ TEST(PrivateKey, Cleanup) { // Note: it would be good to check the memory area after deletion of the object, but this is not possible } +TEST(PrivateKey, GetType) { + EXPECT_EQ(PrivateKey::getType(TWCurveSECP256k1), TWPrivateKeyTypeDefault); + EXPECT_EQ(PrivateKey::getType(TWCurveNIST256p1), TWPrivateKeyTypeDefault); + EXPECT_EQ(PrivateKey::getType(TWCurveED25519), TWPrivateKeyTypeDefault); + EXPECT_EQ(PrivateKey::getType(TWCurveCurve25519), TWPrivateKeyTypeDefault); + + EXPECT_EQ(PrivateKey::getType(TWCurveED25519ExtendedCardano), TWPrivateKeyTypeCardano); +} + TEST(PrivateKey, PrivateKeyExtended) { // Non-extended: both keys are 32 bytes. auto privateKeyNonext = PrivateKey(parse_hex( From a6ff567db3c587a57cb692db3a3a833113554193 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 29 Jul 2022 15:35:34 +0900 Subject: [PATCH 042/497] [Wasm] Revert module type and add README for NPM (#2419) * revert to old export and add readme * change back to commonjs --- wasm/README.md | 7 +++++++ wasm/tsconfig.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 wasm/README.md diff --git a/wasm/README.md b/wasm/README.md new file mode 100644 index 00000000000..63385904724 --- /dev/null +++ b/wasm/README.md @@ -0,0 +1,7 @@ +Trust Wallet Core is an open source, cross platform and cross blockchain library, it adds beta support for WebAssembly recently, You can try it out now: + +```js +npm install @trustwallet/wallet-core +``` + +Documentation will be added to [developer.trustwallet.com](https://developer.trustwallet.com/wallet-core) later, please check out [tests](https://github.com/trustwallet/wallet-core/tree/master/wasm/tests) here for API usages. diff --git a/wasm/tsconfig.json b/wasm/tsconfig.json index e86a48f1020..bcca79e9e1b 100644 --- a/wasm/tsconfig.json +++ b/wasm/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "target": "es5", - "module": "umd", + "module": "commonjs", "moduleResolution": "node", "declaration": true, "outDir": "./dist", From c055ff8178a53eab87794fcaef31a7d50891f4bb Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 29 Jul 2022 10:10:03 +0200 Subject: [PATCH 043/497] [Improvements]: Fix other warnings (#2409) * fix(warnings): enable -Wextra - fix unused parameter - fix sign compare * fix(warning): remove unwanted warning, fix the others - enable -Wshadow - remove unwanted warning already covered by -Wextra * sync(warning): with warning branch * feat(warning): remove -Werror from CompilerWarnings.cmake * refactor(sign_as_der): remove unused curve parameter * refactor(sign_as_der): fix gencode * fix(comments): revert comment changing variable name * fix(review): fix review style --- cmake/CompilerWarnings.cmake | 17 +-- include/TrustWalletCore/TWPrivateKey.h | 34 ++--- src/Binance/Address.cpp | 4 +- src/Binance/Address.h | 8 +- src/Binance/Entry.cpp | 6 +- src/Bitcoin/Amount.h | 4 +- src/Bitcoin/InputSelector.cpp | 16 +-- src/Bitcoin/InputSelector.h | 4 +- src/Bitcoin/SignatureBuilder.cpp | 52 +++---- src/Bitcoin/SignatureBuilder.h | 4 +- src/Bitcoin/Transaction.cpp | 8 +- src/Bitcoin/Transaction.h | 4 +- src/Cbor.cpp | 8 +- src/Cbor.h | 6 +- src/Coin.cpp | 6 +- src/Decred/Signer.cpp | 26 ++-- src/Decred/Signer.h | 4 +- src/EOS/Action.cpp | 1 - src/EOS/PackedTransaction.cpp | 3 +- src/EOS/Transaction.cpp | 1 - src/HDWallet.cpp | 18 +-- src/Keystore/EncryptionParameters.cpp | 12 +- src/Keystore/EncryptionParameters.h | 4 +- src/NEO/TransactionAttribute.h | 20 +-- src/Ontology/Address.cpp | 10 +- src/Ontology/Address.h | 4 +- src/Ontology/Ong.cpp | 8 +- src/Ontology/Ont.cpp | 4 +- src/Ontology/Transaction.cpp | 2 +- src/PrivateKey.cpp | 8 +- src/PrivateKey.h | 2 +- src/Stellar/Signer.cpp | 8 +- src/Stellar/Signer.h | 4 +- src/THORChain/Swap.cpp | 6 +- src/Theta/Transaction.cpp | 4 +- src/Theta/Transaction.h | 4 +- src/Zcash/Transaction.cpp | 6 +- src/Zcash/Transaction.h | 4 +- src/interface/TWPrivateKey.cpp | 6 +- tests/Binance/TWAnySignerTests.cpp | 6 +- tests/Bitcoin/TWBitcoinSigningTests.cpp | 10 +- tests/Bitcoin/TxComparisonHelper.cpp | 2 +- tests/Cosmos/StakingTests.cpp | 32 ++--- tests/Decred/SignerTests.cpp | 8 +- tests/EncryptTests.cpp | 10 +- tests/Ethereum/AbiStructTests.cpp | 8 +- tests/HDWallet/HDWalletTests.cpp | 38 +++--- tests/IoTeX/AddressTests.cpp | 8 +- tests/Keystore/StoredKeyTests.cpp | 128 +++++++++--------- tests/NEO/TransactionAttributeTests.cpp | 24 ++-- tests/NEO/TransactionTests.cpp | 8 +- tests/Ontology/ParamsBuilderTests.cpp | 6 +- tests/Ontology/TransactionTests.cpp | 2 +- tests/Ronin/TWAnyAddressTests.cpp | 6 +- tests/THORChain/TWSwapTests.cpp | 30 ++-- tests/TransactionCompilerTests.cpp | 94 ++++++------- tests/interface/TWHDWalletTests.cpp | 50 +++---- tests/interface/TWPrivateKeyTests.cpp | 2 +- tests/interface/TWPublicKeyTests.cpp | 2 +- .../interface/TWTransactionCompilerTests.cpp | 74 +++++----- 60 files changed, 445 insertions(+), 453 deletions(-) diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake index ca4b3f2ec87..a6e704a52b9 100644 --- a/cmake/CompilerWarnings.cmake +++ b/cmake/CompilerWarnings.cmake @@ -49,22 +49,17 @@ target_compile_options( -Wall -Wextra # reasonable and standard -Wfatal-errors # short error report - #-Wshadow # warn the user if a variable declaration shadows one from a + -Wshadow # warn the user if a variable declaration shadows one from a -Wshorten-64-to-32 # parent context -Wnon-virtual-dtor # warn the user if a class with virtual functions has a - # non-virtual destructor. This helps catch hard to - # track down memory errors - #-Wold-style-cast # warn for c-style casts - #-Wcast-align # warn for potential performance problem casts + # non-virtual destructor. This helps catch hard to track down memory errors + -Wcast-align # warn for potential performance problem casts #-Wunused # warn on anything being unused - #-Woverloaded-virtual # warn if you overload (not override) a virtual + -Woverloaded-virtual # warn if you overload (not override) a virtual # function - #-Wpedantic # warn if non-standard C++ is used - #-Wconversion # warn on type conversions that may lose data - #-Wsign-conversion # warn on sign conversions - #-Wnull-dereference # warn if a null dereference is detected - #-Wdouble-promotion # warn if float is implicit promoted to double + -Wnull-dereference # warn if a null dereference is detected + -Wdouble-promotion # warn if float is implicit promoted to double -Wformat=2 # warn on security issues around functions that format output ) diff --git a/include/TrustWalletCore/TWPrivateKey.h b/include/TrustWalletCore/TWPrivateKey.h index ea77304de57..bf6b4b11016 100644 --- a/include/TrustWalletCore/TWPrivateKey.h +++ b/include/TrustWalletCore/TWPrivateKey.h @@ -19,62 +19,62 @@ struct TWPrivateKey; static const size_t TWPrivateKeySize = 32; TW_EXPORT_STATIC_METHOD -struct TWPrivateKey *_Nonnull TWPrivateKeyCreate(void); +struct TWPrivateKey* _Nonnull TWPrivateKeyCreate(void); TW_EXPORT_STATIC_METHOD -struct TWPrivateKey *_Nullable TWPrivateKeyCreateWithData(TWData *_Nonnull data); +struct TWPrivateKey* _Nullable TWPrivateKeyCreateWithData(TWData* _Nonnull data); TW_EXPORT_STATIC_METHOD -struct TWPrivateKey *_Nullable TWPrivateKeyCreateCopy(struct TWPrivateKey *_Nonnull key); +struct TWPrivateKey* _Nullable TWPrivateKeyCreateCopy(struct TWPrivateKey* _Nonnull key); TW_EXPORT_METHOD -void TWPrivateKeyDelete(struct TWPrivateKey *_Nonnull pk); +void TWPrivateKeyDelete(struct TWPrivateKey* _Nonnull pk); TW_EXPORT_STATIC_METHOD -bool TWPrivateKeyIsValid(TWData *_Nonnull data, enum TWCurve curve); +bool TWPrivateKeyIsValid(TWData* _Nonnull data, enum TWCurve curve); TW_EXPORT_PROPERTY -TWData *_Nonnull TWPrivateKeyData(struct TWPrivateKey *_Nonnull pk); +TWData* _Nonnull TWPrivateKeyData(struct TWPrivateKey* _Nonnull pk); /// Returns the public key associated with this private key. TW_EXPORT_METHOD -struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeySecp256k1(struct TWPrivateKey *_Nonnull pk, bool compressed); +struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeySecp256k1(struct TWPrivateKey* _Nonnull pk, bool compressed); /// Returns the public key associated with this private key. TW_EXPORT_METHOD -struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyNist256p1(struct TWPrivateKey *_Nonnull pk); +struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyNist256p1(struct TWPrivateKey* _Nonnull pk); /// Returns the public key associated with this private key. TW_EXPORT_METHOD -struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519(struct TWPrivateKey *_Nonnull pk); +struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyEd25519(struct TWPrivateKey* _Nonnull pk); /// Returns the public key associated with this private key. TW_EXPORT_METHOD -struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519Blake2b(struct TWPrivateKey *_Nonnull pk); +struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyEd25519Blake2b(struct TWPrivateKey* _Nonnull pk); /// Returns the Cardano style public key associated with this private key. TW_EXPORT_METHOD -struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519Cardano(struct TWPrivateKey *_Nonnull pk); +struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyEd25519Cardano(struct TWPrivateKey* _Nonnull pk); /// Returns the public key associated with this private key. TW_EXPORT_METHOD -struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyCurve25519(struct TWPrivateKey *_Nonnull pk); +struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyCurve25519(struct TWPrivateKey* _Nonnull pk); /// Computes an EC Diffie-Hellman secret in constant time /// Supported curves: secp256k1 TW_EXPORT_METHOD -TWData *_Nullable TWPrivateKeyGetSharedKey(const struct TWPrivateKey *_Nonnull pk, const struct TWPublicKey *_Nonnull publicKey, enum TWCurve curve); +TWData* _Nullable TWPrivateKeyGetSharedKey(const struct TWPrivateKey* _Nonnull pk, const struct TWPublicKey* _Nonnull publicKey, enum TWCurve curve); /// Signs a digest using ECDSA and given curve. TW_EXPORT_METHOD -TWData *_Nullable TWPrivateKeySign(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull digest, enum TWCurve curve); +TWData* _Nullable TWPrivateKeySign(struct TWPrivateKey* _Nonnull pk, TWData* _Nonnull digest, enum TWCurve curve); -/// Signs a digest using ECDSA and given curve. The result is encoded with DER. +/// Signs a digest using ECDSA. The result is encoded with DER. TW_EXPORT_METHOD -TWData *_Nullable TWPrivateKeySignAsDER(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull digest, enum TWCurve curve); +TWData* _Nullable TWPrivateKeySignAsDER(struct TWPrivateKey* _Nonnull pk, TWData* _Nonnull digest); /// Signs a digest using ECDSA and Zilliqa schnorr signature scheme. TW_EXPORT_METHOD -TWData *_Nullable TWPrivateKeySignZilliqaSchnorr(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull message); +TWData* _Nullable TWPrivateKeySignZilliqaSchnorr(struct TWPrivateKey* _Nonnull pk, TWData* _Nonnull message); TW_EXTERN_C_END diff --git a/src/Binance/Address.cpp b/src/Binance/Address.cpp index c0c7b91d0f7..a7313dec8f1 100644 --- a/src/Binance/Address.cpp +++ b/src/Binance/Address.cpp @@ -12,9 +12,9 @@ using namespace TW::Binance; -const std::string Address::hrp = HRP_BINANCE; +const std::string Address::_hrp = HRP_BINANCE; const std::string Address::hrpValidator = "bva"; -const std::vector validHrps = {Address::hrp, Address::hrpValidator, "bnbp", "bvap", "bca", "bcap"}; +const std::vector validHrps = {Address::_hrp, Address::hrpValidator, "bnbp", "bvap", "bca", "bcap"}; bool Address::isValid(const std::string& addr) { Address addrNotUsed; diff --git a/src/Binance/Address.h b/src/Binance/Address.h index f3494c9149f..0735d5db0cf 100644 --- a/src/Binance/Address.h +++ b/src/Binance/Address.h @@ -15,18 +15,18 @@ namespace TW::Binance { /// Binance address is a Bech32Address, with "bnb" prefix and sha256ripemd hash class Address: public Bech32Address { public: - static const std::string hrp; // HRP_BINANCE + static const std::string _hrp; // HRP_BINANCE static const std::string hrpValidator; // HRP_BINANCE static bool isValid(const std::string& addr); - Address() : Bech32Address(hrp) {} + Address() : Bech32Address(_hrp) {} /// Initializes an address with a key hash. - Address(const Data& keyHash) : Bech32Address(hrp, keyHash) {} + Address(const Data& keyHash) : Bech32Address(_hrp, keyHash) {} /// Initializes an address with a public key. - Address(const PublicKey& publicKey) : Bech32Address(hrp, Hash::HasherSha256ripemd, publicKey) {} + Address(const PublicKey& publicKey) : Bech32Address(_hrp, Hash::HasherSha256ripemd, publicKey) {} static bool decode(const std::string& addr, Address& obj_out); }; diff --git a/src/Binance/Entry.cpp b/src/Binance/Entry.cpp index 71c6a6a8d50..7fb78263463 100644 --- a/src/Binance/Entry.cpp +++ b/src/Binance/Entry.cpp @@ -92,9 +92,9 @@ Data Entry::buildTransactionInput([[maybe_unused]] TWCoinType coinType, const st const auto toKeyhash = toAddress.getKeyHash(); { - auto* input = order.add_inputs(); - input->set_address(fromKeyhash.data(), fromKeyhash.size()); - auto* inputCoin = input->add_coins(); + auto* sendOrderInputs = order.add_inputs(); + sendOrderInputs->set_address(fromKeyhash.data(), fromKeyhash.size()); + auto* inputCoin = sendOrderInputs->add_coins(); inputCoin->set_denom(asset); inputCoin->set_amount(static_cast(amount)); } diff --git a/src/Bitcoin/Amount.h b/src/Bitcoin/Amount.h index 77dc499cb07..aa3f9e8dfcb 100644 --- a/src/Bitcoin/Amount.h +++ b/src/Bitcoin/Amount.h @@ -16,9 +16,9 @@ namespace TW::Bitcoin { using Amount = int64_t; /// One bitcoin in satoshis -inline constexpr Amount coin = 100000000; +inline constexpr Amount gCoin = 100000000; /// Maxximum valid amount in satoshis. -inline constexpr Amount maxAmount = 21000000 * coin; +inline constexpr Amount gMaxAmount = 21000000 * gCoin; } // namespace TW::Bitcoin diff --git a/src/Bitcoin/InputSelector.cpp b/src/Bitcoin/InputSelector.cpp index a5025c4136d..ada32d497d2 100644 --- a/src/Bitcoin/InputSelector.cpp +++ b/src/Bitcoin/InputSelector.cpp @@ -74,16 +74,16 @@ InputSelector::select(uint64_t targetValue, uint64_t byteFee, ui } // total values of utxos should be greater than targetValue - if (inputs.empty() || sum(inputs) < targetValue) { + if (_inputs.empty() || sum(_inputs) < targetValue) { return {}; } - assert(inputs.size() >= 1); + assert(_inputs.size() >= 1); // definitions for the following calculation const auto doubleTargetValue = targetValue * 2; // Get all possible utxo selections up to a maximum size, sort by total amount, increasing - std::vector sorted = inputs; + std::vector sorted = _inputs; std::sort(sorted.begin(), sorted.end(), [](const TypeWithAmount& lhs, const TypeWithAmount& rhs) { return lhs.amount < rhs.amount; @@ -168,23 +168,23 @@ std::vector InputSelector::selectSimple(int64_t if (targetValue == 0) { return {}; } - if (inputs.empty()) { + if (_inputs.empty()) { return {}; } - assert(inputs.size() >= 1); + assert(_inputs.size() >= 1); // target value is larger that original, but not by a factor of 2 (optimized for large UTXO // cases) const auto increasedTargetValue = (uint64_t)((double)targetValue * 1.1 + - feeCalculator.calculate(inputs.size(), numOutputs, byteFee) + 1000); + feeCalculator.calculate(_inputs.size(), numOutputs, byteFee) + 1000); const int64_t dustThreshold = feeCalculator.calculateSingleInput(byteFee); // Go through inputs in a single pass, in the order they appear, no optimization uint64_t sum = 0; std::vector selected; - for (auto& input : inputs) { + for (auto& input : _inputs) { if (input.amount <= dustThreshold) { continue; // skip dust } @@ -203,7 +203,7 @@ std::vector InputSelector::selectSimple(int64_t template std::vector InputSelector::selectMaxAmount(int64_t byteFee) noexcept { - return filterOutDust(inputs, byteFee); + return filterOutDust(_inputs, byteFee); } // Explicitly instantiate diff --git a/src/Bitcoin/InputSelector.h b/src/Bitcoin/InputSelector.h index ebd128e85a1..84970297eab 100644 --- a/src/Bitcoin/InputSelector.h +++ b/src/Bitcoin/InputSelector.h @@ -39,7 +39,7 @@ class InputSelector { /// Construct, using provided feeCalculator (see getFeeCalculator()). explicit InputSelector(const std::vector& inputs, const FeeCalculator& feeCalculator) noexcept - : inputs(inputs), feeCalculator(feeCalculator) {} + : _inputs(inputs), feeCalculator(feeCalculator) {} explicit InputSelector(const std::vector& inputs) noexcept : InputSelector(inputs, getFeeCalculator(TWCoinTypeBitcoin)) {} @@ -53,7 +53,7 @@ class InputSelector { uint64_t minimumAmount) noexcept; private: - const std::vector inputs; + const std::vector _inputs; const FeeCalculator& feeCalculator; }; diff --git a/src/Bitcoin/SignatureBuilder.cpp b/src/Bitcoin/SignatureBuilder.cpp index 7f534cba603..46decd9be3a 100644 --- a/src/Bitcoin/SignatureBuilder.cpp +++ b/src/Bitcoin/SignatureBuilder.cpp @@ -28,23 +28,23 @@ Result SignatureBuilder:: // plan with error, fail return Result::failure(plan.error); } - if (transaction.inputs.size() == 0 || plan.utxos.size() == 0) { + if (_transaction.inputs.size() == 0 || plan.utxos.size() == 0) { return Result::failure(Common::Proto::Error_missing_input_utxos); } - transactionToSign = transaction; + transactionToSign = _transaction; transactionToSign.inputs.clear(); - std::copy(std::begin(transaction.inputs), std::end(transaction.inputs), + std::copy(std::begin(_transaction.inputs), std::end(_transaction.inputs), std::back_inserter(transactionToSign.inputs)); const auto hashSingle = hashTypeIsSingle(input.hashType); for (auto i = 0ul; i < plan.utxos.size(); i++) { // Only sign TWBitcoinSigHashTypeSingle if there's a corresponding output - if (hashSingle && i >= transaction.outputs.size()) { + if (hashSingle && i >= _transaction.outputs.size()) { continue; } auto& utxo = plan.utxos[i]; - if (i < transaction.inputs.size()) { + if (i < _transaction.inputs.size()) { auto result = sign(utxo.script, i, utxo); if (!result) { return Result::failure(result.error()); @@ -63,7 +63,7 @@ Result SignatureBuilder:: template Result SignatureBuilder::sign(Script script, size_t index, const UTXO& utxo) { - assert(index < transaction.inputs.size()); + assert(index < _transaction.inputs.size()); Script redeemScript; std::vector results; @@ -80,15 +80,15 @@ Result SignatureBuilder::sign(Sc } results = result.payload(); assert(results.size() >= 1); - auto txin = transaction.inputs[index]; + auto txin = _transaction.inputs[index]; if (script.isPayToScriptHash()) { script = Script(results[0]); - auto result = signStep(script, index, utxo, signatureVersion); - if (!result) { - return Result::failure(result.error()); + auto signStepResult = signStep(script, index, utxo, signatureVersion); + if (!signStepResult) { + return Result::failure(signStepResult.error()); } - results = result.payload(); + results = signStepResult.payload(); results.push_back(script.bytes); redeemScript = script; } @@ -97,19 +97,19 @@ Result SignatureBuilder::sign(Sc Data data; if (script.matchPayToWitnessPublicKeyHash(data)) { auto witnessScript = Script::buildPayToPublicKeyHash(results[0]); - auto result = signStep(witnessScript, index, utxo, WITNESS_V0); - if (!result) { - return Result::failure(result.error()); + auto _result = signStep(witnessScript, index, utxo, WITNESS_V0); + if (!_result) { + return Result::failure(_result.error()); } - witnessStack = result.payload(); + witnessStack = _result.payload(); results.clear(); } else if (script.matchPayToWitnessScriptHash(data)) { auto witnessScript = Script(results[0]); - auto result = signStep(witnessScript, index, utxo, WITNESS_V0); - if (!result) { - return Result::failure(result.error()); + auto _result = signStep(witnessScript, index, utxo, WITNESS_V0); + if (!_result) { + return Result::failure(_result.error()); } - witnessStack = result.payload(); + witnessStack = _result.payload(); witnessStack.push_back(std::move(witnessScript.bytes)); results.clear(); } else if (script.isWitnessProgram()) { @@ -204,12 +204,12 @@ Result, Common::Proto::SigningError> SignatureBuilder, Common::Proto::SigningError>::failure(Common::Proto::Error_signing); } - pubkey = std::get<1>(externalSignatures.value()[index]); + pubkey = std::get<1>(externalSignatures.value()[_index]); } else { // Error: Missing keys return Result, Common::Proto::SigningError>::failure(Common::Proto::Error_missing_private_key); @@ -257,16 +257,16 @@ Data SignatureBuilder::createSignature( if (signingMode == SigningMode_External) { // Use externally-provided signature // Store hash, only for counting - size_t index = hashesForSigning.size(); + size_t _index = hashesForSigning.size(); hashesForSigning.push_back(std::make_pair(sighash, publicKeyHash)); - if (!externalSignatures.has_value() || externalSignatures.value().size() <= index) { + if (!externalSignatures.has_value() || externalSignatures.value().size() <= _index) { // Error: no or not enough signatures provided return Data(); } - Data externalSignature = std::get<0>(externalSignatures.value()[index]); - const Data publicKey = std::get<1>(externalSignatures.value()[index]); + Data externalSignature = std::get<0>(externalSignatures.value()[_index]); + const Data publicKey = std::get<1>(externalSignatures.value()[_index]); // Verify provided signature if (!PublicKey::isValid(publicKey, TWPublicKeyTypeSECP256k1)) { diff --git a/src/Bitcoin/SignatureBuilder.h b/src/Bitcoin/SignatureBuilder.h index c42c5dfb1d1..33ed8925394 100644 --- a/src/Bitcoin/SignatureBuilder.h +++ b/src/Bitcoin/SignatureBuilder.h @@ -42,7 +42,7 @@ class SignatureBuilder { TransactionPlan plan; /// Transaction being signed. - Transaction transaction; + Transaction _transaction; /// Transaction being signed, with list of signed inputs Transaction transactionToSign; @@ -65,7 +65,7 @@ class SignatureBuilder { SigningMode signingMode = SigningMode_Normal, std::optional externalSignatures = {} ) - : input(input), plan(plan), transaction(transaction), signingMode(signingMode), externalSignatures(externalSignatures) {} + : input(input), plan(plan), _transaction(transaction), signingMode(signingMode), externalSignatures(externalSignatures) {} /// Signs the transaction. /// diff --git a/src/Bitcoin/Transaction.cpp b/src/Bitcoin/Transaction.cpp index 6cf74961fd9..b4ee1ccd4b8 100644 --- a/src/Bitcoin/Transaction.cpp +++ b/src/Bitcoin/Transaction.cpp @@ -25,7 +25,7 @@ Data Transaction::getPreImage(const Script& scriptCode, size_t index, Data data; // Version - encode32LE(version, data); + encode32LE(_version, data); // Input prevouts (none/all, depending on flags) if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) == 0) { @@ -117,7 +117,7 @@ void Transaction::encode(Data& data, enum SegwitFormatMode segwitFormat) const { break; } - encode32LE(version, data); + encode32LE(_version, data); if (useWitnessFormat) { // Use extended format in case witnesses are to be serialized. @@ -180,7 +180,7 @@ Data Transaction::getSignatureHashBase(const Script& scriptCode, size_t index, Data data; - encode32LE(version, data); + encode32LE(_version, data); auto serializedInputCount = (hashType & TWBitcoinSigHashTypeAnyoneCanPay) != 0 ? 1 : inputs.size(); @@ -241,7 +241,7 @@ void Transaction::serializeInput(size_t subindex, const Script& scriptCode, size Proto::Transaction Transaction::proto() const { auto protoTx = Proto::Transaction(); - protoTx.set_version(version); + protoTx.set_version(_version); protoTx.set_locktime(lockTime); for (const auto& input : inputs) { diff --git a/src/Bitcoin/Transaction.h b/src/Bitcoin/Transaction.h index b5ecd454e8b..c64957802ec 100644 --- a/src/Bitcoin/Transaction.h +++ b/src/Bitcoin/Transaction.h @@ -33,7 +33,7 @@ class TransactionOutputs: public std::vector {}; struct Transaction { public: /// Transaction data format version (note, this is signed) - int32_t version = 1; + int32_t _version = 1; /// The block number or timestamp at which this transaction is unlocked /// @@ -62,7 +62,7 @@ struct Transaction { Transaction() = default; Transaction(int32_t version, uint32_t lockTime = 0, TW::Hash::Hasher hasher = TW::Hash::HasherSha256d) - : version(version), lockTime(lockTime), inputs(), outputs(), hasher(hasher) {} + : _version(version), lockTime(lockTime), inputs(), outputs(), hasher(hasher) {} /// Whether the transaction is empty. bool empty() const { return inputs.empty() && outputs.empty(); } diff --git a/src/Cbor.cpp b/src/Cbor.cpp index acbf4217c97..788d82e6c24 100644 --- a/src/Cbor.cpp +++ b/src/Cbor.cpp @@ -19,7 +19,7 @@ TW::Data Encode::encoded() const { if (openIndefCount > 0) { throw invalid_argument("CBOR Unclosed indefinite length building"); } - return data; + return _data; } Encode Encode::uint(uint64_t value) { @@ -96,7 +96,7 @@ Encode Encode::closeIndefArray() { throw invalid_argument("CBOR Not inside indefinite-length array"); } // add closing break command - TW::append(data, 0xFF); + TW::append(_data, 0xFF); // close counter --openIndefCount; return *this; @@ -129,7 +129,7 @@ Encode Encode::appendValue(byte majorType, uint64_t value) { minorType = 27; } // add bytes - TW::append(data, (byte)((majorType << 5) | (minorType & 0x1F))); + TW::append(_data, (byte)((majorType << 5) | (minorType & 0x1F))); Data valBytes = Data(byteCount - 1); for (auto i = 0ul; i < valBytes.size(); ++i) { valBytes[valBytes.size() - 1 - i] = (byte)(value & 0xFF); @@ -141,7 +141,7 @@ Encode Encode::appendValue(byte majorType, uint64_t value) { void Encode::appendIndefinite(byte majorType) { byte minorType = 31; - TW::append(data, (byte)((majorType << 5) | (minorType & 0x1F))); + TW::append(_data, (byte)((majorType << 5) | (minorType & 0x1F))); } diff --git a/src/Cbor.h b/src/Cbor.h index 5433b3e2ec2..6b9aa3950c7 100644 --- a/src/Cbor.h +++ b/src/Cbor.h @@ -57,15 +57,15 @@ class Encode { private: Encode() {} - Encode(const TW::Data& rawData) : data(rawData) {} + Encode(const TW::Data& rawData) : _data(rawData) {} /// Append types + value, on variable number of bytes (1..8). Return object to support chain syntax. Encode appendValue(byte majorType, uint64_t value); - inline Encode append(const TW::Data& data) { TW::append(this->data, data); return *this; } + inline Encode append(const TW::Data& data) { TW::append(_data, data); return *this; } void appendIndefinite(byte majorType); private: /// Encoded data is stored here, always well-formed, but my be partial. - TW::Data data; + TW::Data _data; /// number of currently open indefinite buildingds (0, 1, or more for nested) int openIndefCount = 0; }; diff --git a/src/Coin.cpp b/src/Coin.cpp index 8d2b7767ae2..90fc53fe748 100644 --- a/src/Coin.cpp +++ b/src/Coin.cpp @@ -152,12 +152,12 @@ CoinEntry* coinDispatcher(TWCoinType coinType) { return entry; } -const Derivation CoinInfo::derivationByName(TWDerivation name) const { - if (name == TWDerivationDefault && derivation.size() > 0) { +const Derivation CoinInfo::derivationByName(TWDerivation nameIn) const { + if (nameIn == TWDerivationDefault && derivation.size() > 0) { return derivation[0]; } for (auto deriv: derivation) { - if (deriv.name == name) { + if (deriv.name == nameIn) { return deriv; } } diff --git a/src/Decred/Signer.cpp b/src/Decred/Signer.cpp index d03766bb27a..413203c48eb 100644 --- a/src/Decred/Signer.cpp +++ b/src/Decred/Signer.cpp @@ -47,18 +47,18 @@ Proto::SigningOutput Signer::sign(const Bitcoin::Proto::SigningInput& input) noe } Result Signer::sign() { - if (txPlan.utxos.size() == 0 || transaction.inputs.size() == 0) { + if (txPlan.utxos.size() == 0 || _transaction.inputs.size() == 0) { return Result::failure(Common::Proto::Error_missing_input_utxos); } - signedInputs = transaction.inputs; + signedInputs = _transaction.inputs; const auto hashSingle = Bitcoin::hashTypeIsSingle(static_cast(input.hash_type())); for (auto i = 0ul; i < txPlan.utxos.size(); i += 1) { auto& utxo = txPlan.utxos[i]; // Only sign TWBitcoinSigHashTypeSingle if there's a corresponding output - if (hashSingle && i >= transaction.outputs.size()) { + if (hashSingle && i >= _transaction.outputs.size()) { continue; } auto result = sign(utxo.script, i); @@ -68,14 +68,14 @@ Result Signer::sign() { signedInputs[i].script = result.payload(); } - Transaction tx(transaction); + Transaction tx(_transaction); tx.inputs = std::move(signedInputs); - tx.outputs = transaction.outputs; + tx.outputs = _transaction.outputs; return Result::success(std::move(tx)); } Result Signer::sign(Bitcoin::Script script, size_t index) { - assert(index < transaction.inputs.size()); + assert(index < _transaction.inputs.size()); Bitcoin::Script redeemScript; std::vector results; @@ -86,15 +86,15 @@ Result Signer::sign(Bitcoin::Scrip } else { return Result::failure(result.error()); } - auto txin = transaction.inputs[index]; + auto txin = _transaction.inputs[index]; if (script.isPayToScriptHash()) { script = Bitcoin::Script(results.front().begin(), results.front().end()); - auto result = signStep(script, index); - if (!result) { - return Result::failure(result.error()); + auto result_ = signStep(script, index); + if (!result_) { + return Result::failure(result_.error()); } - results = result.payload(); + results = result_.payload(); results.push_back(script.bytes); redeemScript = script; results.push_back(redeemScript.bytes); @@ -104,9 +104,9 @@ Result Signer::sign(Bitcoin::Scrip } Result, Common::Proto::SigningError> Signer::signStep(Bitcoin::Script script, size_t index) { - Transaction transactionToSign(transaction); + Transaction transactionToSign(_transaction); transactionToSign.inputs = signedInputs; - transactionToSign.outputs = transaction.outputs; + transactionToSign.outputs = _transaction.outputs; Data data; std::vector keys; diff --git a/src/Decred/Signer.h b/src/Decred/Signer.h index 6e299fa65d6..170c5e8b818 100644 --- a/src/Decred/Signer.h +++ b/src/Decred/Signer.h @@ -41,7 +41,7 @@ class Signer { Bitcoin::TransactionPlan txPlan; /// Transaction being signed. - Transaction transaction; + Transaction _transaction; private: /// List of signed inputs. @@ -59,7 +59,7 @@ class Signer { } else { txPlan = TransactionBuilder::plan(input); } - transaction = TransactionBuilder::build(txPlan, input.to_address(), input.change_address()); + _transaction = TransactionBuilder::build(txPlan, input.to_address(), input.change_address()); } /// Signs the transaction. diff --git a/src/EOS/Action.cpp b/src/EOS/Action.cpp index dae38bbabf7..37bb5dea766 100644 --- a/src/EOS/Action.cpp +++ b/src/EOS/Action.cpp @@ -10,7 +10,6 @@ using namespace TW; using namespace TW::EOS; -using json = nlohmann::json; void PermissionLevel::serialize(Data& o) const { actor.serialize(o); diff --git a/src/EOS/PackedTransaction.cpp b/src/EOS/PackedTransaction.cpp index 56708474227..c0f0955b996 100644 --- a/src/EOS/PackedTransaction.cpp +++ b/src/EOS/PackedTransaction.cpp @@ -10,7 +10,6 @@ using namespace TW; using namespace TW::EOS; -using json = nlohmann::json; PackedTransaction::PackedTransaction(const Transaction& transaction, CompressionType type) noexcept : compression(type) { transaction.serialize(packedTrx); @@ -49,4 +48,4 @@ json PackedTransaction::serialize() const noexcept { obj["packed_trx"] = hex(packedTrx); return obj; -} \ No newline at end of file +} diff --git a/src/EOS/Transaction.cpp b/src/EOS/Transaction.cpp index d30d6b670ae..8189f8ef042 100644 --- a/src/EOS/Transaction.cpp +++ b/src/EOS/Transaction.cpp @@ -17,7 +17,6 @@ using namespace TW; using namespace TW::EOS; -using json = nlohmann::json; Signature::Signature(const Data& sig, Type type) : data(sig), type(type) { if (sig.size() != DataSize) { diff --git a/src/HDWallet.cpp b/src/HDWallet.cpp index 624d96d5581..56ef7730d14 100644 --- a/src/HDWallet.cpp +++ b/src/HDWallet.cpp @@ -98,13 +98,13 @@ void HDWallet::updateSeedAndEntropy(bool check) { PrivateKey HDWallet::getMasterKey(TWCurve curve) const { auto node = getMasterNode(*this, curve); - auto data = Data(node.private_key, node.private_key + PrivateKey::size); + auto data = Data(node.private_key, node.private_key + PrivateKey::_size); return PrivateKey(data); } PrivateKey HDWallet::getMasterKeyExtension(TWCurve curve) const { auto node = getMasterNode(*this, curve); - auto data = Data(node.private_key_extension, node.private_key_extension + PrivateKey::size); + auto data = Data(node.private_key_extension, node.private_key_extension + PrivateKey::_size); return PrivateKey(data); } @@ -132,15 +132,15 @@ PrivateKey HDWallet::getKey(TWCoinType coin, const DerivationPath& derivationPat } const DerivationPath stakingPath = cardanoStakingDerivationPath(derivationPath); - auto pkData = Data(node.private_key, node.private_key + PrivateKey::size); - auto extData = Data(node.private_key_extension, node.private_key_extension + PrivateKey::size); - auto chainCode = Data(node.chain_code, node.chain_code + PrivateKey::size); + auto pkData = Data(node.private_key, node.private_key + PrivateKey::_size); + auto extData = Data(node.private_key_extension, node.private_key_extension + PrivateKey::_size); + auto chainCode = Data(node.chain_code, node.chain_code + PrivateKey::_size); // repeat with staking path const auto node2 = getNode(*this, curve, stakingPath); - auto pkData2 = Data(node2.private_key, node2.private_key + PrivateKey::size); - auto extData2 = Data(node2.private_key_extension, node2.private_key_extension + PrivateKey::size); - auto chainCode2 = Data(node2.chain_code, node2.chain_code + PrivateKey::size); + auto pkData2 = Data(node2.private_key, node2.private_key + PrivateKey::_size); + auto extData2 = Data(node2.private_key_extension, node2.private_key_extension + PrivateKey::_size); + auto chainCode2 = Data(node2.chain_code, node2.chain_code + PrivateKey::_size); TW::memzero(&node); return PrivateKey(pkData, extData, chainCode, pkData2, extData2, chainCode2); @@ -149,7 +149,7 @@ PrivateKey HDWallet::getKey(TWCoinType coin, const DerivationPath& derivationPat case TWPrivateKeyTypeDefault: default: // default path - auto data = Data(node.private_key, node.private_key + PrivateKey::size); + auto data = Data(node.private_key, node.private_key + PrivateKey::_size); TW::memzero(&node); return PrivateKey(data); } diff --git a/src/Keystore/EncryptionParameters.cpp b/src/Keystore/EncryptionParameters.cpp index d5642ae28ee..27adea5f10c 100644 --- a/src/Keystore/EncryptionParameters.cpp +++ b/src/Keystore/EncryptionParameters.cpp @@ -72,7 +72,7 @@ nlohmann::json EncryptionParameters::json() const { } EncryptedPayload::EncryptedPayload(const Data& password, const Data& data, const EncryptionParameters& params) : - params(std::move(params)), mac() { + params(std::move(params)), _mac() { auto scryptParams = boost::get(params.kdfParams); auto derivedKey = Data(scryptParams.desiredKeyLength); scrypt(reinterpret_cast(password.data()), password.size(), scryptParams.salt.data(), @@ -87,13 +87,13 @@ EncryptedPayload::EncryptedPayload(const Data& password, const Data& data, const encrypted = Data(data.size()); aes_ctr_encrypt(data.data(), encrypted.data(), static_cast(data.size()), iv.data(), aes_ctr_cbuf_inc, &ctx); - mac = computeMAC(derivedKey.end() - 16, derivedKey.end(), encrypted); + _mac = computeMAC(derivedKey.end() - 16, derivedKey.end(), encrypted); } } EncryptedPayload::~EncryptedPayload() { std::fill(encrypted.begin(), encrypted.end(), 0); - std::fill(mac.begin(), mac.end(), 0); + std::fill(_mac.begin(), _mac.end(), 0); } Data EncryptedPayload::decrypt(const Data& password) const { @@ -118,7 +118,7 @@ Data EncryptedPayload::decrypt(const Data& password) const { throw DecryptionError::unsupportedKDF; } - if (mac != this->mac) { + if (mac != _mac) { throw DecryptionError::invalidPassword; } @@ -149,12 +149,12 @@ Data EncryptedPayload::decrypt(const Data& password) const { EncryptedPayload::EncryptedPayload(const nlohmann::json& json) { params = EncryptionParameters(json); encrypted = parse_hex(json[CodingKeys::encrypted].get()); - mac = parse_hex(json[CodingKeys::mac].get()); + _mac = parse_hex(json[CodingKeys::mac].get()); } nlohmann::json EncryptedPayload::json() const { nlohmann::json j = params.json(); j[CodingKeys::encrypted] = hex(encrypted); - j[CodingKeys::mac] = hex(mac); + j[CodingKeys::mac] = hex(_mac); return j; } diff --git a/src/Keystore/EncryptionParameters.h b/src/Keystore/EncryptionParameters.h index 2f7463ff598..744ebe47277 100644 --- a/src/Keystore/EncryptionParameters.h +++ b/src/Keystore/EncryptionParameters.h @@ -82,7 +82,7 @@ struct EncryptedPayload { Data encrypted; /// Message authentication code. - Data mac; + Data _mac; EncryptedPayload() = default; @@ -90,7 +90,7 @@ struct EncryptedPayload { EncryptedPayload(const EncryptionParameters& params, const Data& encrypted, const Data& mac) : params(std::move(params)) , encrypted(std::move(encrypted)) - , mac(std::move(mac)) {} + , _mac(std::move(mac)) {} /// Initializes by encrypting data with a password /// using standard values. diff --git a/src/NEO/TransactionAttribute.h b/src/NEO/TransactionAttribute.h index 87a4c62d764..bdad6b80a12 100644 --- a/src/NEO/TransactionAttribute.h +++ b/src/NEO/TransactionAttribute.h @@ -16,12 +16,12 @@ namespace TW::NEO { class TransactionAttribute : public Serializable { public: TransactionAttributeUsage usage = TAU_ContractHash; - Data data; + Data _data; virtual ~TransactionAttribute() {} int64_t size() const override { - return 1 + data.size(); + return 1 + _data.size(); } void deserialize(const Data& data, int initial_pos = 0) override { @@ -31,30 +31,30 @@ class TransactionAttribute : public Serializable { usage = (TransactionAttributeUsage) data[initial_pos]; if (usage == TransactionAttributeUsage::TAU_ContractHash || usage == TransactionAttributeUsage::TAU_Vote || (usage >= TransactionAttributeUsage::TAU_Hash1 && usage <= TransactionAttributeUsage::TAU_Hash15)) { - this->data = readBytes(data, 32, initial_pos + 1); + _data = readBytes(data, 32, initial_pos + 1); } else if (usage == TransactionAttributeUsage::TAU_ECDH02 || usage == TransactionAttributeUsage::TAU_ECDH03) { - this->data = readBytes(data, 32, initial_pos + 1); + _data = readBytes(data, 32, initial_pos + 1); } else if (usage == TransactionAttributeUsage::TAU_Script) { - this->data = readBytes(data, 20, initial_pos + 1); + _data = readBytes(data, 20, initial_pos + 1); } else if (usage == TransactionAttributeUsage::TAU_DescriptionUrl) { - this->data = readBytes(data, 1, initial_pos + 1); + _data = readBytes(data, 1, initial_pos + 1); } else if (usage == TransactionAttributeUsage::TAU_Description || usage >= TransactionAttributeUsage::TAU_Remark) { - this->data = readBytes(data, int(data.size()) - 1 - initial_pos, initial_pos + 1); + _data = readBytes(data, int(data.size()) - 1 - initial_pos, initial_pos + 1); } else { throw std::invalid_argument("TransactionAttribute Deserialize FormatException"); } } Data serialize() const override { - return concat(Data({static_cast(usage)}), data); + return concat(Data({static_cast(usage)}), _data); } bool operator==(const TransactionAttribute &other) const { return this->usage == other.usage - && this->data.size() == other.data.size() - && this->data == other.data; + && _data.size() == other._data.size() + && _data == other._data; } }; diff --git a/src/Ontology/Address.cpp b/src/Ontology/Address.cpp index 979d204dc05..76bd96365ef 100644 --- a/src/Ontology/Address.cpp +++ b/src/Ontology/Address.cpp @@ -23,7 +23,7 @@ Address::Address(const PublicKey& publicKey) { builder.insert(builder.begin(), PUSH_BYTE_33); builder.push_back(CHECK_SIG); auto builderData = toScriptHash(builder); - std::copy(builderData.begin(), builderData.end(), data.begin()); + std::copy(builderData.begin(), builderData.end(), _data.begin()); } Address::Address(const std::string& b58Address) { @@ -32,19 +32,19 @@ Address::Address(const std::string& b58Address) { } Data addressWithVersion(size + 1); base58_decode_check(b58Address.c_str(), HASHER_SHA2D, addressWithVersion.data(), size + 1); - std::copy(addressWithVersion.begin() + 1, addressWithVersion.end(), data.begin()); + std::copy(addressWithVersion.begin() + 1, addressWithVersion.end(), _data.begin()); } Address::Address(const std::vector& bytes) { if (bytes.size() != size) { throw std::runtime_error("Invalid bytes data."); } - std::copy(bytes.begin(), bytes.end(), data.begin()); + std::copy(bytes.begin(), bytes.end(), _data.begin()); } Address::Address(uint8_t m, const std::vector& publicKeys) { auto builderData = toScriptHash(ParamsBuilder::fromMultiPubkey(m, publicKeys)); - std::copy(builderData.begin(), builderData.end(), data.begin()); + std::copy(builderData.begin(), builderData.end(), _data.begin()); } Data Address::toScriptHash(const Data& data) { @@ -64,7 +64,7 @@ bool Address::isValid(const std::string& b58Address) noexcept { std::string Address::string() const { std::vector encodeData(size + 1); encodeData[0] = version; - std::copy(data.begin(), data.end(), encodeData.begin() + 1); + std::copy(_data.begin(), _data.end(), encodeData.begin() + 1); size_t b58StrSize = 34; std::string b58Str(b58StrSize, ' '); base58_encode_check(encodeData.data(), (int)encodeData.size(), HASHER_SHA2D, &b58Str[0], diff --git a/src/Ontology/Address.h b/src/Ontology/Address.h index 7d5b2377b31..5b9e640ea56 100644 --- a/src/Ontology/Address.h +++ b/src/Ontology/Address.h @@ -22,7 +22,7 @@ class Address { static const size_t size = 20; static const uint8_t version = 0x17; - std::array data; + std::array _data; /// Initializes an address with a public key. explicit Address(const PublicKey& publicKey); @@ -44,7 +44,7 @@ class Address { }; inline bool operator==(const Address& lhs, const Address& rhs) { - return lhs.data == rhs.data; + return lhs._data == rhs._data; } } // namespace TW::Ontology diff --git a/src/Ontology/Ong.cpp b/src/Ontology/Ong.cpp index 383a411e549..209e4b21e0a 100644 --- a/src/Ontology/Ong.cpp +++ b/src/Ontology/Ong.cpp @@ -25,7 +25,7 @@ Transaction Ong::decimals(uint32_t nonce) { Transaction Ong::balanceOf(const Address &address, uint32_t nonce) { auto builder = ParamsBuilder(); auto invokeCode = - ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "balanceOf", address.data); + ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "balanceOf", address._data); auto tx = Transaction(version, txType, nonce, (uint64_t)0, (uint64_t)0, (std::string) "", invokeCode); return tx; @@ -34,7 +34,7 @@ Transaction Ong::balanceOf(const Address &address, uint32_t nonce) { Transaction Ong::transfer(const Signer &from, const Address &to, uint64_t amount, const Signer &payer, uint64_t gasPrice, uint64_t gasLimit, uint32_t nonce) { - std::list transferParam{from.getAddress().data, to.data, amount}; + std::list transferParam{from.getAddress()._data, to._data, amount}; std::vector args{transferParam}; auto invokeCode = ParamsBuilder::buildNativeInvokeCode(contractAddress(), 0x00, "transfer", args); @@ -49,7 +49,7 @@ Transaction Ong::withdraw(const Signer &claimer, const Address &receiver, uint64 const Signer &payer, uint64_t gasPrice, uint64_t gasLimit, uint32_t nonce) { auto ontContract = Address("AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV"); - std::list args{claimer.getAddress().data, ontContract.data, receiver.data, amount}; + std::list args{claimer.getAddress()._data, ontContract._data, receiver._data, amount}; auto invokeCode = ParamsBuilder::buildNativeInvokeCode(contractAddress(), 0x00, "transferFrom", args); auto tx = Transaction(version, txType, nonce, gasPrice, gasLimit, payer.getAddress().string(), @@ -57,4 +57,4 @@ Transaction Ong::withdraw(const Signer &claimer, const Address &receiver, uint64 claimer.sign(tx); payer.addSign(tx); return tx; -} \ No newline at end of file +} diff --git a/src/Ontology/Ont.cpp b/src/Ontology/Ont.cpp index 08ce5847328..6f279c9f38c 100644 --- a/src/Ontology/Ont.cpp +++ b/src/Ontology/Ont.cpp @@ -25,7 +25,7 @@ Transaction Ont::decimals(uint32_t nonce) { Transaction Ont::balanceOf(const Address &address, uint32_t nonce) { auto builder = ParamsBuilder(); auto invokeCode = - ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "balanceOf", address.data); + ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "balanceOf", address._data); auto tx = Transaction((uint8_t)0, txType, nonce, (uint64_t)0, (uint64_t)0, (std::string) "", invokeCode); return tx; @@ -34,7 +34,7 @@ Transaction Ont::balanceOf(const Address &address, uint32_t nonce) { Transaction Ont::transfer(const Signer &from, const Address &to, uint64_t amount, const Signer &payer, uint64_t gasPrice, uint64_t gasLimit, uint32_t nonce) { - std::list transferParam{from.getAddress().data, to.data, amount}; + std::list transferParam{from.getAddress()._data, to._data, amount}; std::vector args{transferParam}; auto invokeCode = ParamsBuilder::buildNativeInvokeCode(contractAddress(), 0x00, "transfer", args); diff --git a/src/Ontology/Transaction.cpp b/src/Ontology/Transaction.cpp index a3306871b75..8a78e478735 100644 --- a/src/Ontology/Transaction.cpp +++ b/src/Ontology/Transaction.cpp @@ -25,7 +25,7 @@ std::vector Transaction::serializeUnsigned() { builder.pushBack(nonce); builder.pushBack(gasPrice); builder.pushBack(gasLimit); - builder.pushBack(Address(payer).data); + builder.pushBack(Address(payer)._data); if (!payload.empty()) { builder.pushVar(payload); } diff --git a/src/PrivateKey.cpp b/src/PrivateKey.cpp index e5fb5168573..898953100ed 100644 --- a/src/PrivateKey.cpp +++ b/src/PrivateKey.cpp @@ -25,12 +25,12 @@ using namespace TW; bool PrivateKey::isValid(const Data& data) { // Check length - if (data.size() != size && data.size() != cardanoKeySize) { + if (data.size() != _size && data.size() != cardanoKeySize) { return false; } // Check for zero address - for (size_t i = 0; i < size; ++i) { + for (size_t i = 0; i < _size; ++i) { if (data[i] != 0) { return true; } @@ -94,8 +94,8 @@ PrivateKey::PrivateKey(const Data& data) { PrivateKey::PrivateKey( const Data& key1, const Data& extension1, const Data& chainCode1, const Data& key2, const Data& extension2, const Data& chainCode2) { - if (key1.size() != size || extension1.size() != size || chainCode1.size() != size || - key2.size() != size || extension2.size() != size || chainCode2.size() != size) { + if (key1.size() != _size || extension1.size() != _size || chainCode1.size() != _size || + key2.size() != _size || extension2.size() != _size || chainCode2.size() != _size) { throw std::invalid_argument("Invalid private key or extended key data"); } bytes = key1; diff --git a/src/PrivateKey.h b/src/PrivateKey.h index a2ac177df5d..32b2877a0ff 100644 --- a/src/PrivateKey.h +++ b/src/PrivateKey.h @@ -17,7 +17,7 @@ namespace TW { class PrivateKey { public: /// The number of bytes in a private key. - static const size_t size = 32; + static const size_t _size = 32; /// The number of bytes in a Cardano key (two extended ed25519 keys + chain code) static const size_t cardanoKeySize = 2 * 3 * 32; diff --git a/src/Stellar/Signer.cpp b/src/Stellar/Signer.cpp index fe3e4475ec4..a2e78a25e7f 100644 --- a/src/Stellar/Signer.cpp +++ b/src/Stellar/Signer.cpp @@ -25,12 +25,12 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { std::string Signer::sign() const noexcept { - auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); - auto account = Address(input.account()); - auto encoded = encode(input); + auto key = PrivateKey(Data(_input.private_key().begin(), _input.private_key().end())); + auto account = Address(_input.account()); + auto encoded = encode(_input); auto encodedWithHeaders = Data(); - auto publicNetwork = input.passphrase(); // Header + auto publicNetwork = _input.passphrase(); // Header auto passphrase = Hash::sha256(publicNetwork); encodedWithHeaders.insert(encodedWithHeaders.end(), passphrase.begin(), passphrase.end()); auto transactionType = Data{0, 0, 0, 2}; // Header diff --git a/src/Stellar/Signer.h b/src/Stellar/Signer.h index c38896000b2..a37c3f0338c 100644 --- a/src/Stellar/Signer.h +++ b/src/Stellar/Signer.h @@ -20,9 +20,9 @@ class Signer { /// Signs a Proto::SigningInput transaction static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept; public: - const Proto::SigningInput& input; + const Proto::SigningInput& _input; - Signer(const Proto::SigningInput& input) : input(input) {} + Signer(const Proto::SigningInput& input) : _input(input) {} /// Signs the given transaction. std::string sign() const noexcept; diff --git a/src/THORChain/Swap.cpp b/src/THORChain/Swap.cpp index fccacfb4f96..17d47ebf51e 100644 --- a/src/THORChain/Swap.cpp +++ b/src/THORChain/Swap.cpp @@ -213,9 +213,9 @@ std::pair Swap::buildBinance([[maybe_unused]] Chain toChain, [ { Binance::Address fromAddressBin; Binance::Address::decode(fromAddress, fromAddressBin); - auto input = order.add_inputs(); - input->set_address(fromAddressBin.getKeyHash().data(), fromAddressBin.getKeyHash().size()); - *input->add_coins() = token; + auto input_ = order.add_inputs(); + input_->set_address(fromAddressBin.getKeyHash().data(), fromAddressBin.getKeyHash().size()); + *input_->add_coins() = token; } { Binance::Address vaultAddressBin; diff --git a/src/Theta/Transaction.cpp b/src/Theta/Transaction.cpp index 7cfa42e3ad2..f430d422238 100644 --- a/src/Theta/Transaction.cpp +++ b/src/Theta/Transaction.cpp @@ -60,7 +60,7 @@ Transaction::Transaction(Ethereum::Address from, Ethereum::Address to, auto input = TxInput(std::move(from), coinsInput, sequence); auto output = TxOutput(std::move(to), coinsOutput); - this->fee = fee; + this->_fee = fee; this->inputs.push_back(input); this->outputs.push_back(output); } @@ -70,7 +70,7 @@ Data Transaction::encode() const noexcept { uint16_t txType = 2; // TxSend append(encoded, RLP::encode(txType)); auto encodedData = Data(); - append(encodedData, ::encode(fee)); + append(encodedData, ::encode(_fee)); append(encodedData, ::encode(inputs)); append(encodedData, ::encode(outputs)); append(encoded, RLP::encodeList(encodedData)); diff --git a/src/Theta/Transaction.h b/src/Theta/Transaction.h index 735c21ab1a8..cdc9d079d4d 100644 --- a/src/Theta/Transaction.h +++ b/src/Theta/Transaction.h @@ -39,13 +39,13 @@ class TxOutput { class Transaction { public: - Coins fee; + Coins _fee; std::vector inputs; std::vector outputs; Transaction() = default; Transaction(Coins fee, std::vector inputs, std::vector outputs) - : fee(std::move(fee)), inputs(std::move(inputs)), outputs(std::move(outputs)) {} + : _fee(std::move(fee)), inputs(std::move(inputs)), outputs(std::move(outputs)) {} Transaction(Ethereum::Address from, Ethereum::Address to, uint256_t thetaAmount, uint256_t tfuelAmount, uint64_t sequence, diff --git a/src/Zcash/Transaction.cpp b/src/Zcash/Transaction.cpp index 7a61a33b2cb..c12bab72c0c 100644 --- a/src/Zcash/Transaction.cpp +++ b/src/Zcash/Transaction.cpp @@ -36,7 +36,7 @@ Data Transaction::getPreImage(const Bitcoin::Script& scriptCode, size_t index, e auto data = Data{}; // header - encode32LE(version, data); + encode32LE(_version, data); // nVersionGroupId encode32LE(versionGroupId, data); @@ -152,7 +152,7 @@ Data Transaction::getShieldedOutputsHash() const { } void Transaction::encode(Data& data) const { - encode32LE(version, data); + encode32LE(_version, data); encode32LE(versionGroupId, data); // vin @@ -194,7 +194,7 @@ Data Transaction::getSignatureHash(const Bitcoin::Script& scriptCode, size_t ind Bitcoin::Proto::Transaction Transaction::proto() const { auto protoTx = Bitcoin::Proto::Transaction(); - protoTx.set_version(version); + protoTx.set_version(_version); protoTx.set_locktime(lockTime); for (const auto& input : inputs) { diff --git a/src/Zcash/Transaction.h b/src/Zcash/Transaction.h index e42b77ef106..4086f3ddbea 100644 --- a/src/Zcash/Transaction.h +++ b/src/Zcash/Transaction.h @@ -23,7 +23,7 @@ extern const std::array BlossomBranchID; /// Only supports transparent transaction right now /// See also https://github.com/zcash/zips/blob/master/zip-0243.rst struct Transaction { - uint32_t version = 0x80000004; + uint32_t _version = 0x80000004; uint32_t versionGroupId = 0x892F2085; uint32_t lockTime = 0; uint32_t expiryHeight = 0; @@ -40,7 +40,7 @@ struct Transaction { Transaction(uint32_t version, uint32_t versionGroupId, uint32_t lockTime, uint32_t expiryHeight, uint64_t valueBalance, std::array branchId) - : version(version) + : _version(version) , versionGroupId(versionGroupId) , lockTime(lockTime) , expiryHeight(expiryHeight) diff --git a/src/interface/TWPrivateKey.cpp b/src/interface/TWPrivateKey.cpp index 2de3aaf3032..ab91378d9ca 100644 --- a/src/interface/TWPrivateKey.cpp +++ b/src/interface/TWPrivateKey.cpp @@ -17,8 +17,8 @@ using namespace TW; struct TWPrivateKey *TWPrivateKeyCreate() { - Data bytes(PrivateKey::size); - random_buffer(bytes.data(), PrivateKey::size); + Data bytes(PrivateKey::_size); + random_buffer(bytes.data(), PrivateKey::_size); if (!PrivateKey::isValid(bytes)) { // Under no circumstance return an invalid private key. We'd rather // crash. This also captures cases where the random generator fails @@ -108,7 +108,7 @@ TWData *TWPrivateKeySign(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull dige } } -TWData *TWPrivateKeySignAsDER(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull digest, [[maybe_unused]] enum TWCurve curve) { +TWData* TWPrivateKeySignAsDER(struct TWPrivateKey* pk, TWData* digest) { auto& d = *reinterpret_cast(digest); auto result = pk->impl.signAsDER(d); if (result.empty()) { diff --git a/tests/Binance/TWAnySignerTests.cpp b/tests/Binance/TWAnySignerTests.cpp index 514b0435992..22ab4b17de7 100644 --- a/tests/Binance/TWAnySignerTests.cpp +++ b/tests/Binance/TWAnySignerTests.cpp @@ -39,9 +39,9 @@ Proto::SigningOutput SignTest() { auto toKeyhash = toAddress.getKeyHash(); { - auto input = order.add_inputs(); - input->set_address(fromKeyhash.data(), fromKeyhash.size()); - auto inputCoin = input->add_coins(); + auto inputOrder = order.add_inputs(); + inputOrder->set_address(fromKeyhash.data(), fromKeyhash.size()); + auto inputCoin = inputOrder->add_coins(); inputCoin->set_denom("BNB"); inputCoin->set_amount(1); } diff --git a/tests/Bitcoin/TWBitcoinSigningTests.cpp b/tests/Bitcoin/TWBitcoinSigningTests.cpp index e3f02115039..3942c7c9baa 100644 --- a/tests/Bitcoin/TWBitcoinSigningTests.cpp +++ b/tests/Bitcoin/TWBitcoinSigningTests.cpp @@ -332,11 +332,11 @@ TEST(BitcoinSigning, SignP2WPKH) { { // Non-segwit encoded, for comparison - Data serialized; - signedTx.encode(serialized, Transaction::SegwitFormatMode::NonSegwit); + Data serialized_; + signedTx.encode(serialized_, Transaction::SegwitFormatMode::NonSegwit); EXPECT_EQ(getEncodedTxSize(signedTx), (EncodedTxSize{195, 192, 193})); - EXPECT_EQ(serialized.size(), 192ul); - ASSERT_EQ(hex(serialized), // printed using prettyPrintTransaction + EXPECT_EQ(serialized_.size(), 192ul); + ASSERT_EQ(hex(serialized_), // printed using prettyPrintTransaction "01000000" // version "01" // inputs "fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f" "00000000" "49" "483045022100c327babdd370f0fc5b24cf920736446bf7d9c5660e4a5f7df432386fd652fe280220269c4fc3690c1c248e50c8bf2435c20b4ef00f308b403575f4437f862a91c53a01" "ffffffff" @@ -1466,7 +1466,7 @@ TEST(BitcoinSigning, EncodeThreeOutput) { auto hashType = TWBitcoinSigHashType::TWBitcoinSigHashTypeAll; Data sighash = unsignedTx.getSignatureHash(redeemScript0, unsignedTx.inputs[0].previousOutput.index, - hashType, utxo0Amount, static_cast(unsignedTx.version)); + hashType, utxo0Amount, static_cast(unsignedTx._version)); auto sig = privkey.signAsDER(sighash); ASSERT_FALSE(sig.empty()); sig.push_back(hashType); diff --git a/tests/Bitcoin/TxComparisonHelper.cpp b/tests/Bitcoin/TxComparisonHelper.cpp index 3d617ee510b..cc2fb43ecec 100644 --- a/tests/Bitcoin/TxComparisonHelper.cpp +++ b/tests/Bitcoin/TxComparisonHelper.cpp @@ -196,7 +196,7 @@ void prettyPrintScript(const Script& script) { void prettyPrintTransaction(const Transaction& tx, bool useWitnessFormat) { Data data; - encode32LE(tx.version, data); + encode32LE(tx._version, data); std::cout << " \"" << hex(data) << "\" // version\n"; if (useWitnessFormat) { diff --git a/tests/Cosmos/StakingTests.cpp b/tests/Cosmos/StakingTests.cpp index e80358816b9..bde53cb1322 100644 --- a/tests/Cosmos/StakingTests.cpp +++ b/tests/Cosmos/StakingTests.cpp @@ -50,10 +50,10 @@ TEST(CosmosStaking, Staking) { { // Json-serialization, for coverage (to be removed later) input.set_signing_mode(Proto::JSON); - auto output = Signer::sign(input, TWCoinTypeCosmos); - ASSERT_EQ(hex(output.signature()), "c08bdf6c2b0b4428f37975e85d329f1cb19745b000994a743b5df81d57d573aa5f755349befcc848c1d1507818723b1288594bc91df685e89aff22e0303b4861"); - EXPECT_EQ(output.error(), ""); - EXPECT_EQ(hex(output.serialized()), ""); + auto signingOutput = Signer::sign(input, TWCoinTypeCosmos); + ASSERT_EQ(hex(signingOutput.signature()), "c08bdf6c2b0b4428f37975e85d329f1cb19745b000994a743b5df81d57d573aa5f755349befcc848c1d1507818723b1288594bc91df685e89aff22e0303b4861"); + EXPECT_EQ(signingOutput.error(), ""); + EXPECT_EQ(hex(signingOutput.serialized()), ""); } } @@ -90,10 +90,10 @@ TEST(CosmosStaking, Unstaking) { { // Json-serialization, for coverage (to be removed later) input.set_signing_mode(Proto::JSON); - auto output = Signer::sign(input, TWCoinTypeCosmos); - ASSERT_EQ(hex(output.signature()), "8f85a9515a211881daebfb346c2beeca3ab5c2d406a9b3ad402cfddaa3d08e2b13378e13cfef8ecf1d6500fe85d0ce3e793034dd77aba90f216427807cbff79f"); - EXPECT_EQ(output.error(), ""); - EXPECT_EQ(hex(output.serialized()), ""); + auto signingOutput = Signer::sign(input, TWCoinTypeCosmos); + ASSERT_EQ(hex(signingOutput.signature()), "8f85a9515a211881daebfb346c2beeca3ab5c2d406a9b3ad402cfddaa3d08e2b13378e13cfef8ecf1d6500fe85d0ce3e793034dd77aba90f216427807cbff79f"); + EXPECT_EQ(signingOutput.error(), ""); + EXPECT_EQ(hex(signingOutput.serialized()), ""); } } @@ -132,10 +132,10 @@ TEST(CosmosStaking, Restaking) { { // Json-serialization, for coverage (to be removed later) input.set_signing_mode(Proto::JSON); - auto output = Signer::sign(input, TWCoinTypeCosmos); - ASSERT_EQ(hex(output.signature()), "e64d3761bd25a28befcda80c0a0e208d024fdb0a2b89955170e65a5c5d454aba2ce81d57e01f0c126de5a59c2b58124c109560c9803d65a17a14b548dd6c50db"); - EXPECT_EQ(output.error(), ""); - EXPECT_EQ(hex(output.serialized()), ""); + auto signingOutput = Signer::sign(input, TWCoinTypeCosmos); + ASSERT_EQ(hex(signingOutput.signature()), "e64d3761bd25a28befcda80c0a0e208d024fdb0a2b89955170e65a5c5d454aba2ce81d57e01f0c126de5a59c2b58124c109560c9803d65a17a14b548dd6c50db"); + EXPECT_EQ(signingOutput.error(), ""); + EXPECT_EQ(hex(signingOutput.serialized()), ""); } } @@ -169,9 +169,9 @@ TEST(CosmosStaking, Withdraw) { { // Json-serialization, for coverage (to be removed later) input.set_signing_mode(Proto::JSON); - auto output = Signer::sign(input, TWCoinTypeCosmos); - ASSERT_EQ(hex(output.signature()), "546f0d67356f6af94cfb5ab22b974e499c33123f2c2c292f4f0e64878e0e728f4643105fd771550beb3f2371f08880aaa38fa8f2334c103a779f1d82d2db98d6"); - EXPECT_EQ(output.error(), ""); - EXPECT_EQ(hex(output.serialized()), ""); + auto signingOutput = Signer::sign(input, TWCoinTypeCosmos); + ASSERT_EQ(hex(signingOutput.signature()), "546f0d67356f6af94cfb5ab22b974e499c33123f2c2c292f4f0e64878e0e728f4643105fd771550beb3f2371f08880aaa38fa8f2334c103a779f1d82d2db98d6"); + EXPECT_EQ(signingOutput.error(), ""); + EXPECT_EQ(hex(signingOutput.serialized()), ""); } } diff --git a/tests/Decred/SignerTests.cpp b/tests/Decred/SignerTests.cpp index 8ad2081c970..e2282b76fba 100644 --- a/tests/Decred/SignerTests.cpp +++ b/tests/Decred/SignerTests.cpp @@ -86,7 +86,7 @@ TEST(DecredSigner, SignP2PKH) { // Sign auto signer = Signer(std::move(input)); - signer.transaction = redeemTx; + signer._transaction = redeemTx; signer.txPlan.amount = 100'000'000; const auto result = signer.sign(); @@ -193,7 +193,7 @@ TEST(DecredSigner, SignP2SH) { // Sign auto signer = Signer(std::move(input)); - signer.transaction = redeemTx; + signer._transaction = redeemTx; signer.txPlan.amount = 100'000'000; const auto result = signer.sign(); @@ -273,7 +273,7 @@ TEST(DecredSigner, SignNegativeNoUtxo) { // Sign auto signer = Signer(std::move(input)); - signer.transaction = redeemTx; + signer._transaction = redeemTx; signer.txPlan.amount = 100'000'000; const auto result = signer.sign(); @@ -342,7 +342,7 @@ TEST(DecredSigner, SignP2PKH_NoPlan) { // Sign auto signer = Signer(std::move(input)); - signer.transaction = redeemTx; + signer._transaction = redeemTx; //signer.txPlan.utxos.push_back(*utxo0); //signer.txPlan.amount = 100'000'000; const auto result = signer.sign(); diff --git a/tests/EncryptTests.cpp b/tests/EncryptTests.cpp index 2bf4979fd2c..85f20b1160f 100644 --- a/tests/EncryptTests.cpp +++ b/tests/EncryptTests.cpp @@ -15,7 +15,7 @@ using namespace TW::Encrypt; using namespace TW; -const Data key = parse_hex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); +const Data gKey = parse_hex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); inline void assertHexEqual(const Data& data, const char* expected) { EXPECT_EQ(hex(data), expected); @@ -46,7 +46,7 @@ TEST(Encrypt, AESCBCEncrypt) { auto iv = parse_hex("000102030405060708090A0B0C0D0E0F"); auto data = parse_hex("6bc1bee22e409f96e93d7e117393172a"); - auto encryptResult = AESCBCEncrypt(key, data, iv); + auto encryptResult = AESCBCEncrypt(gKey, data, iv); assertHexEqual(encryptResult, "f58c4c04d6e5f1ba779eabfb5f7bfbd6"); } @@ -70,7 +70,7 @@ TEST(Encrypt, AESCBCDecrypt) { auto iv = parse_hex("000102030405060708090A0B0C0D0E0F"); auto cipher = parse_hex("f58c4c04d6e5f1ba779eabfb5f7bfbd6"); - auto decryptResult = AESCBCDecrypt(key, cipher, iv); + auto decryptResult = AESCBCDecrypt(gKey, cipher, iv); assertHexEqual(decryptResult, "6bc1bee22e409f96e93d7e117393172a"); } @@ -98,7 +98,7 @@ TEST(Encrypt, AESCTREncrypt) { auto iv = parse_hex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); auto data = parse_hex("6bc1bee22e409f96e93d7e117393172a"); - auto encryptResult = AESCTREncrypt(key, data, iv); + auto encryptResult = AESCTREncrypt(gKey, data, iv); assertHexEqual(encryptResult, "601ec313775789a5b7a7f504bbf3d228"); } @@ -106,7 +106,7 @@ TEST(Encrypt, AESCTRDecrypt) { auto iv = parse_hex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); auto cipher = parse_hex("601ec313775789a5b7a7f504bbf3d228"); - auto decryptResult = AESCTRDecrypt(key, cipher, iv); + auto decryptResult = AESCTRDecrypt(gKey, cipher, iv); assertHexEqual(decryptResult, "6bc1bee22e409f96e93d7e117393172a"); } diff --git a/tests/Ethereum/AbiStructTests.cpp b/tests/Ethereum/AbiStructTests.cpp index cd7f66cb3d2..2a20569d1ec 100644 --- a/tests/Ethereum/AbiStructTests.cpp +++ b/tests/Ethereum/AbiStructTests.cpp @@ -65,7 +65,7 @@ ParamStruct msgMailCow2Bob3("Mail", std::vector>{ std::make_shared("to", std::make_shared(std::make_shared(msgPersonBob3))), std::make_shared("contents", std::make_shared("Hello, Bob!")) }); -ParamStruct msgEIP712Domain("EIP712Domain", std::vector>{ +ParamStruct gMsgEIP712Domain("EIP712Domain", std::vector>{ std::make_shared("name", std::make_shared("Ether Mail")), std::make_shared("version", std::make_shared("1")), std::make_shared("chainId", std::make_shared(1)), @@ -86,7 +86,7 @@ TEST(EthereumAbiStruct, encodeTypes) { EXPECT_EQ(hex(msgMailCow1Bob1.hashStruct()), "c52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e"); - EXPECT_EQ(hex(msgEIP712Domain.hashStruct()), "f2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f"); + EXPECT_EQ(hex(gMsgEIP712Domain.hashStruct()), "f2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f"); Address address = Address(privateKeyCow.getPublicKey(TWPublicKeyTypeSECP256k1Extended)); EXPECT_EQ(address.string(), "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"); @@ -150,7 +150,7 @@ TEST(EthereumAbiStruct, encodeTypes_v3) { EXPECT_EQ(hex(msgMailCow1Bob1.hashStruct()), "c52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e"); - EXPECT_EQ(hex(msgEIP712Domain.hashStruct()), "f2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f"); + EXPECT_EQ(hex(gMsgEIP712Domain.hashStruct()), "f2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f"); Address address = Address(privateKeyCow.getPublicKey(TWPublicKeyTypeSECP256k1Extended)); EXPECT_EQ(address.string(), "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"); @@ -238,7 +238,7 @@ TEST(EthereumAbiStruct, encodeTypes_v4) { EXPECT_EQ(hex(msgMailCow2Bob3.hashStruct()), "eb4221181ff3f1a83ea7313993ca9218496e424604ba9492bb4052c03d5c3df8"); - EXPECT_EQ(hex(msgEIP712Domain.hashStruct()), "f2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f"); + EXPECT_EQ(hex(gMsgEIP712Domain.hashStruct()), "f2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f"); Address address = Address(privateKeyCow.getPublicKey(TWPublicKeyTypeSECP256k1Extended)); EXPECT_EQ(address.string(), "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"); diff --git a/tests/HDWallet/HDWalletTests.cpp b/tests/HDWallet/HDWalletTests.cpp index 701f3ed5dd8..2e1fc4a53a9 100644 --- a/tests/HDWallet/HDWalletTests.cpp +++ b/tests/HDWallet/HDWalletTests.cpp @@ -24,34 +24,34 @@ extern std::string TESTS_ROOT; namespace TW { const auto mnemonic1 = "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal"; -const auto passphrase = "passphrase"; +const auto gPassphrase = "passphrase"; TEST(HDWallet, generate) { { - HDWallet wallet = HDWallet(128, passphrase); + HDWallet wallet = HDWallet(128, gPassphrase); EXPECT_TRUE(Mnemonic::isValid(wallet.getMnemonic())); - EXPECT_EQ(wallet.getPassphrase(), passphrase); + EXPECT_EQ(wallet.getPassphrase(), gPassphrase); EXPECT_EQ(wallet.getEntropy().size(), 16ul); } { - HDWallet wallet = HDWallet(256, passphrase); + HDWallet wallet = HDWallet(256, gPassphrase); EXPECT_TRUE(Mnemonic::isValid(wallet.getMnemonic())); - EXPECT_EQ(wallet.getPassphrase(), passphrase); + EXPECT_EQ(wallet.getPassphrase(), gPassphrase); EXPECT_EQ(wallet.getEntropy().size(), 32ul); } } TEST(HDWallet, generateInvalid) { - EXPECT_EXCEPTION(HDWallet(64, passphrase), "Invalid strength"); - EXPECT_EXCEPTION(HDWallet(129, passphrase), "Invalid strength"); - EXPECT_EXCEPTION(HDWallet(512, passphrase), "Invalid strength"); + EXPECT_EXCEPTION(HDWallet(64, gPassphrase), "Invalid strength"); + EXPECT_EXCEPTION(HDWallet(129, gPassphrase), "Invalid strength"); + EXPECT_EXCEPTION(HDWallet(512, gPassphrase), "Invalid strength"); } TEST(HDWallet, createFromMnemonic) { { - HDWallet wallet = HDWallet(mnemonic1, passphrase); + HDWallet wallet = HDWallet(mnemonic1, gPassphrase); EXPECT_EQ(wallet.getMnemonic(), mnemonic1); - EXPECT_EQ(wallet.getPassphrase(), passphrase); + EXPECT_EQ(wallet.getPassphrase(), gPassphrase); EXPECT_EQ(hex(wallet.getEntropy()), "ba5821e8c356c05ba5f025d9532fe0f21f65d594"); EXPECT_EQ(hex(wallet.getSeed()), "143cd5fc27ae46eb423efebc41610473f5e24a80f2ca2e2fa7bf167e537f58f4c68310ae487fce82e25bad29bab2530cf77fd724a5ebfc05a45872773d7ee2d6"); } @@ -116,31 +116,31 @@ TEST(HDWallet, createFromSpanishMnemonic) { } TEST(HDWallet, createFromMnemonicInvalid) { - EXPECT_EXCEPTION(HDWallet("THIS IS AN INVALID MNEMONIC", passphrase), "Invalid mnemonic"); - EXPECT_EXCEPTION(HDWallet("", passphrase), "Invalid mnemonic"); + EXPECT_EXCEPTION(HDWallet("THIS IS AN INVALID MNEMONIC", gPassphrase), "Invalid mnemonic"); + EXPECT_EXCEPTION(HDWallet("", gPassphrase), "Invalid mnemonic"); - EXPECT_EXCEPTION(HDWallet("", passphrase, false), "Invalid mnemonic"); - HDWallet walletUnchecked = HDWallet("THIS IS AN INVALID MNEMONIC", passphrase, false); + EXPECT_EXCEPTION(HDWallet("", gPassphrase, false), "Invalid mnemonic"); + HDWallet walletUnchecked = HDWallet("THIS IS AN INVALID MNEMONIC", gPassphrase, false); } TEST(HDWallet, createFromEntropy) { { - HDWallet wallet = HDWallet(parse_hex("ba5821e8c356c05ba5f025d9532fe0f21f65d594"), passphrase); + HDWallet wallet = HDWallet(parse_hex("ba5821e8c356c05ba5f025d9532fe0f21f65d594"), gPassphrase); EXPECT_EQ(wallet.getMnemonic(), mnemonic1); } } TEST(HDWallet, createFromEntropyInvalid) { - EXPECT_EXCEPTION(HDWallet(parse_hex(""), passphrase), "Invalid mnemonic data"); - EXPECT_EXCEPTION(HDWallet(parse_hex("123456"), passphrase), "Invalid mnemonic data"); + EXPECT_EXCEPTION(HDWallet(parse_hex(""), gPassphrase), "Invalid mnemonic data"); + EXPECT_EXCEPTION(HDWallet(parse_hex("123456"), gPassphrase), "Invalid mnemonic data"); } TEST(HDWallet, recreateFromEntropy) { { - HDWallet wallet1 = HDWallet(mnemonic1, passphrase); + HDWallet wallet1 = HDWallet(mnemonic1, gPassphrase); EXPECT_EQ(wallet1.getMnemonic(), mnemonic1); EXPECT_EQ(hex(wallet1.getEntropy()), "ba5821e8c356c05ba5f025d9532fe0f21f65d594"); - HDWallet wallet2 = HDWallet(wallet1.getEntropy(), passphrase); + HDWallet wallet2 = HDWallet(wallet1.getEntropy(), gPassphrase); EXPECT_EQ(wallet2.getMnemonic(), wallet1.getMnemonic()); EXPECT_EQ(wallet2.getEntropy(), wallet1.getEntropy()); EXPECT_EQ(wallet2.getSeed(), wallet1.getSeed()); diff --git a/tests/IoTeX/AddressTests.cpp b/tests/IoTeX/AddressTests.cpp index 60616bf1002..36fd80b38d9 100644 --- a/tests/IoTeX/AddressTests.cpp +++ b/tests/IoTeX/AddressTests.cpp @@ -45,8 +45,8 @@ TEST(IoTeXAddress, FromPrivateKey) { EXPECT_THROW({ try { - const auto publicKey = PublicKey(privateKey.getPublicKey(TWPublicKeyTypeSECP256k1)); - const auto address = Address(publicKey); + const auto _publicKey = PublicKey(privateKey.getPublicKey(TWPublicKeyTypeSECP256k1)); + const auto _address = Address(_publicKey); } catch( const std::invalid_argument& e ) { @@ -64,8 +64,8 @@ TEST(IoTeXAddress, FromKeyHash) { EXPECT_THROW({ try { - const auto keyHash = parse_hex("3f9c20bcec9de520d88d98cbe07ee7b5ded0da"); - const auto address = Address(keyHash); + const auto _keyHash = parse_hex("3f9c20bcec9de520d88d98cbe07ee7b5ded0da"); + const auto _address = Address(_keyHash); } catch( const std::invalid_argument& e ) { diff --git a/tests/Keystore/StoredKeyTests.cpp b/tests/Keystore/StoredKeyTests.cpp index e504b2e1bba..f68af94833d 100644 --- a/tests/Keystore/StoredKeyTests.cpp +++ b/tests/Keystore/StoredKeyTests.cpp @@ -23,8 +23,8 @@ namespace TW::Keystore { using namespace std; const auto passwordString = "password"; -const auto password = TW::data(string(passwordString)); -const auto mnemonic = "team engine square letter hero song dizzy scrub tornado fabric divert saddle"; +const auto gPassword = TW::data(string(passwordString)); +const auto gMnemonic = "team engine square letter hero song dizzy scrub tornado fabric divert saddle"; const TWCoinType coinTypeBc = TWCoinTypeBitcoin; const TWCoinType coinTypeBnb = TWCoinTypeBinance; const TWCoinType coinTypeBsc = TWCoinTypeSmartChain; @@ -32,12 +32,12 @@ const TWCoinType coinTypeEth = TWCoinTypeEthereum; const TWCoinType coinTypeBscLegacy = TWCoinTypeSmartChainLegacy; TEST(StoredKey, CreateWithMnemonic) { - auto key = StoredKey::createWithMnemonic("name", password, mnemonic, TWStoredKeyEncryptionLevelDefault); + auto key = StoredKey::createWithMnemonic("name", gPassword, gMnemonic, TWStoredKeyEncryptionLevelDefault); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); - const Data& mnemo2Data = key.payload.decrypt(password); - EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(mnemonic)); + const Data& mnemo2Data = key.payload.decrypt(gPassword); + EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(gMnemonic)); EXPECT_EQ(key.accounts.size(), 0ul); - EXPECT_EQ(key.wallet(password).getMnemonic(), string(mnemonic)); + EXPECT_EQ(key.wallet(gPassword).getMnemonic(), string(gMnemonic)); const auto json = key.json(); EXPECT_EQ(json["name"], "name"); @@ -47,7 +47,7 @@ TEST(StoredKey, CreateWithMnemonic) { TEST(StoredKey, CreateWithMnemonicInvalid) { try { - auto key = StoredKey::createWithMnemonic("name", password, "_THIS_IS_NOT_A_VALID_MNEMONIC_", TWStoredKeyEncryptionLevelDefault); + auto key = StoredKey::createWithMnemonic("name", gPassword, "_THIS_IS_NOT_A_VALID_MNEMONIC_", TWStoredKeyEncryptionLevelDefault); } catch (std::invalid_argument&) { // expedcted exception OK return; @@ -56,38 +56,38 @@ TEST(StoredKey, CreateWithMnemonicInvalid) { } TEST(StoredKey, CreateWithMnemonicRandom) { - const auto key = StoredKey::createWithMnemonicRandom("name", password, TWStoredKeyEncryptionLevelDefault); + const auto key = StoredKey::createWithMnemonicRandom("name", gPassword, TWStoredKeyEncryptionLevelDefault); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); // random mnemonic: check only length and validity - const Data& mnemo2Data = key.payload.decrypt(password); + const Data& mnemo2Data = key.payload.decrypt(gPassword); EXPECT_TRUE(mnemo2Data.size() >= 36); EXPECT_TRUE(Mnemonic::isValid(string(mnemo2Data.begin(), mnemo2Data.end()))); EXPECT_EQ(key.accounts.size(), 0ul); } TEST(StoredKey, CreateWithMnemonicAddDefaultAddress) { - auto key = StoredKey::createWithMnemonicAddDefaultAddress("name", password, mnemonic, coinTypeBc); + auto key = StoredKey::createWithMnemonicAddDefaultAddress("name", gPassword, gMnemonic, coinTypeBc); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); - const Data& mnemo2Data = key.payload.decrypt(password); + const Data& mnemo2Data = key.payload.decrypt(gPassword); - EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(mnemonic)); + EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(gMnemonic)); EXPECT_EQ(key.accounts.size(), 1ul); EXPECT_EQ(key.accounts[0].coin, coinTypeBc); EXPECT_EQ(key.accounts[0].address, "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"); EXPECT_EQ(key.accounts[0].publicKey, "02df6fc590ab3101bbe0bb5765cbaeab9b5dcfe09ac9315d707047cbd13bc7e006"); EXPECT_EQ(key.accounts[0].extendedPublicKey, "zpub6qbsWdbcKW9sC6shTKK4VEhfWvDCoWpfLnnVfYKHLHt31wKYUwH3aFDz4WLjZvjHZ5W4qVEyk37cRwzTbfrrT1Gnu8SgXawASnkdQ994atn"); - EXPECT_EQ(hex(key.privateKey(coinTypeBc, password).bytes), "d2568511baea8dc347f14c4e0479eb8ebe29eb5f664ed796e755896250ffd11f"); + EXPECT_EQ(hex(key.privateKey(coinTypeBc, gPassword).bytes), "d2568511baea8dc347f14c4e0479eb8ebe29eb5f664ed796e755896250ffd11f"); } TEST(StoredKey, CreateWithPrivateKeyAddDefaultAddress) { const auto privateKey = parse_hex("3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"); - auto key = StoredKey::createWithPrivateKeyAddDefaultAddress("name", password, coinTypeBc, privateKey); + auto key = StoredKey::createWithPrivateKeyAddDefaultAddress("name", gPassword, coinTypeBc, privateKey); EXPECT_EQ(key.type, StoredKeyType::privateKey); EXPECT_EQ(key.accounts.size(), 1ul); EXPECT_EQ(key.accounts[0].coin, coinTypeBc); EXPECT_EQ(key.accounts[0].address, "bc1q375sq4kl2nv0mlmup3vm8znn4eqwu7mt6hkwhr"); - EXPECT_EQ(hex(key.privateKey(coinTypeBc, password).bytes), hex(privateKey)); + EXPECT_EQ(hex(key.privateKey(coinTypeBc, gPassword).bytes), hex(privateKey)); const auto json = key.json(); EXPECT_EQ(json["name"], "name"); @@ -98,7 +98,7 @@ TEST(StoredKey, CreateWithPrivateKeyAddDefaultAddress) { TEST(StoredKey, CreateWithPrivateKeyAddDefaultAddressInvalid) { try { const auto privateKeyInvalid = parse_hex("0001020304"); - auto key = StoredKey::createWithPrivateKeyAddDefaultAddress("name", password, coinTypeBc, privateKeyInvalid); + auto key = StoredKey::createWithPrivateKeyAddDefaultAddress("name", gPassword, coinTypeBc, privateKeyInvalid); } catch (std::invalid_argument&) { // expected exception ok return; @@ -107,14 +107,14 @@ TEST(StoredKey, CreateWithPrivateKeyAddDefaultAddressInvalid) { } TEST(StoredKey, AccountGetCreate) { - auto key = StoredKey::createWithMnemonic("name", password, mnemonic, TWStoredKeyEncryptionLevelDefault); + auto key = StoredKey::createWithMnemonic("name", gPassword, gMnemonic, TWStoredKeyEncryptionLevelDefault); EXPECT_EQ(key.accounts.size(), 0ul); // not exists EXPECT_FALSE(key.account(coinTypeBc).has_value()); EXPECT_EQ(key.accounts.size(), 0ul); - auto wallet = key.wallet(password); + auto wallet = key.wallet(gPassword); // not exists, wallet null, not create EXPECT_FALSE(key.account(coinTypeBc, nullptr).has_value()); EXPECT_EQ(key.accounts.size(), 0ul); @@ -145,8 +145,8 @@ TEST(StoredKey, AccountGetCreate) { } TEST(StoredKey, AccountGetDoesntChange) { - auto key = StoredKey::createWithMnemonic("name", password, mnemonic, TWStoredKeyEncryptionLevelDefault); - auto wallet = key.wallet(password); + auto key = StoredKey::createWithMnemonic("name", gPassword, gMnemonic, TWStoredKeyEncryptionLevelDefault); + auto wallet = key.wallet(gPassword); EXPECT_EQ(key.accounts.size(), 0ul); vector coins = {coinTypeBc, coinTypeEth, coinTypeBnb}; @@ -169,7 +169,7 @@ TEST(StoredKey, AccountGetDoesntChange) { } TEST(StoredKey, AddRemoveAccount) { - auto key = StoredKey::createWithMnemonic("name", password, mnemonic, TWStoredKeyEncryptionLevelDefault); + auto key = StoredKey::createWithMnemonic("name", gPassword, gMnemonic, TWStoredKeyEncryptionLevelDefault); EXPECT_EQ(key.accounts.size(), 0ul); { @@ -199,7 +199,7 @@ TEST(StoredKey, AddRemoveAccount) { } TEST(StoredKey, AddRemoveAccountDerivation) { - auto key = StoredKey::createWithMnemonic("name", Data(), mnemonic, TWStoredKeyEncryptionLevelDefault); + auto key = StoredKey::createWithMnemonic("name", Data(), gMnemonic, TWStoredKeyEncryptionLevelDefault); EXPECT_EQ(key.accounts.size(), 0ul); const auto derivationPath = DerivationPath("m/84'/0'/0'/0/0"); @@ -223,7 +223,7 @@ TEST(StoredKey, AddRemoveAccountDerivation) { } TEST(StoredKey, AddRemoveAccountDerivationPath) { - auto key = StoredKey::createWithMnemonic("name", Data(), mnemonic, TWStoredKeyEncryptionLevelDefault); + auto key = StoredKey::createWithMnemonic("name", Data(), gMnemonic, TWStoredKeyEncryptionLevelDefault); EXPECT_EQ(key.accounts.size(), 0ul); const auto derivationPath0 = DerivationPath("m/84'/0'/0'/0/0"); @@ -249,21 +249,21 @@ TEST(StoredKey, AddRemoveAccountDerivationPath) { TEST(StoredKey, FixAddress) { { - auto key = StoredKey::createWithMnemonic("name", password, mnemonic, TWStoredKeyEncryptionLevelDefault); - key.fixAddresses(password); + auto key = StoredKey::createWithMnemonic("name", gPassword, gMnemonic, TWStoredKeyEncryptionLevelDefault); + key.fixAddresses(gPassword); } { const auto privateKey = parse_hex("3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"); - auto key = StoredKey::createWithPrivateKeyAddDefaultAddress("name", password, coinTypeBc, privateKey); - key.fixAddresses(password); + auto key = StoredKey::createWithPrivateKeyAddDefaultAddress("name", gPassword, coinTypeBc, privateKey); + key.fixAddresses(gPassword); } } TEST(StoredKey, WalletInvalid) { const auto privateKey = parse_hex("3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"); - auto key = StoredKey::createWithPrivateKeyAddDefaultAddress("name", password, coinTypeBc, privateKey); + auto key = StoredKey::createWithPrivateKeyAddDefaultAddress("name", gPassword, coinTypeBc, privateKey); try { - auto wallet = key.wallet(password); + auto wallet = key.wallet(gPassword); } catch (std::invalid_argument&) { // expected exception ok return; @@ -310,7 +310,7 @@ TEST(StoredKey, LoadLegacyMnemonic) { EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); EXPECT_EQ(key.id, "629aad29-0b22-488e-a0e7-b4219d4f311c"); - const auto data = key.payload.decrypt(password); + const auto data = key.payload.decrypt(gPassword); const auto mnemonic = string(reinterpret_cast(data.data())); EXPECT_EQ(mnemonic, "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn back"); @@ -343,7 +343,7 @@ TEST(StoredKey, ReadWallet) { EXPECT_EQ(header.params.cipher, "aes-128-ctr"); EXPECT_EQ(hex(header.encrypted), "d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c"); - EXPECT_EQ(hex(header.mac), "2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097"); + EXPECT_EQ(hex(header._mac), "2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097"); EXPECT_EQ(hex(header.params.cipherParams.iv), "83dbcc02d8ccb40e466191a123791e0e"); ASSERT_TRUE(header.params.kdfParams.which() == 0); @@ -361,7 +361,7 @@ TEST(StoredKey, ReadMyEtherWallet) { TEST(StoredKey, InvalidPassword) { const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/key.json"); - ASSERT_THROW(key.payload.decrypt(password), DecryptionError); + ASSERT_THROW(key.payload.decrypt(gPassword), DecryptionError); } TEST(StoredKey, EmptyAccounts) { @@ -379,16 +379,16 @@ TEST(StoredKey, Decrypt) { TEST(StoredKey, CreateWallet) { const auto privateKey = parse_hex("3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"); - const auto key = StoredKey::createWithPrivateKey("name", password, privateKey); - const auto decrypted = key.payload.decrypt(password); + const auto key = StoredKey::createWithPrivateKey("name", gPassword, privateKey); + const auto decrypted = key.payload.decrypt(gPassword); EXPECT_EQ(hex(decrypted), hex(privateKey)); } TEST(StoredKey, CreateAccounts) { string mnemonicPhrase = "team engine square letter hero song dizzy scrub tornado fabric divert saddle"; - auto key = StoredKey::createWithMnemonic("name", password, mnemonicPhrase, TWStoredKeyEncryptionLevelDefault); - const auto wallet = key.wallet(password); + auto key = StoredKey::createWithMnemonic("name", gPassword, mnemonicPhrase, TWStoredKeyEncryptionLevelDefault); + const auto wallet = key.wallet(gPassword); EXPECT_EQ(key.account(TWCoinTypeEthereum, &wallet)->address, "0x494f60cb6Ac2c8F5E1393aD9FdBdF4Ad589507F7"); EXPECT_EQ(key.account(TWCoinTypeEthereum, &wallet)->publicKey, "04cc32a479080d83fdcf69966713f0aad1bc1dc3ecf873b034894e84259841bc1c9b122717803e68905220ff54952d3f5ea2ab2698ca31f843addf94ae73fae9fd"); @@ -423,14 +423,14 @@ TEST(StoredKey, MissingAddressFix) { auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/missing-address.json"); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); - const auto wallet = key.wallet(password); + const auto wallet = key.wallet(gPassword); EXPECT_EQ(wallet.getMnemonic(), "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal"); EXPECT_TRUE(Mnemonic::isValid(wallet.getMnemonic())); EXPECT_EQ(key.account(TWCoinTypeBitcoin)->address, ""); EXPECT_EQ(key.account(TWCoinTypeEthereum)->address, ""); - key.fixAddresses(password); + key.fixAddresses(gPassword); EXPECT_EQ(key.account(TWCoinTypeEthereum, nullptr)->address, "0xA3Dcd899C0f3832DFDFed9479a9d828c6A4EB2A7"); EXPECT_EQ(key.account(TWCoinTypeEthereum, nullptr)->publicKey, "0448a9ffac8022f1c7eb5253746e24d11d9b6b2737c0aecd48335feabb95a179916b1f3a97bed6740a85a2d11c663d38566acfb08af48a47ce0c835c65c9b23d0d"); @@ -442,7 +442,7 @@ TEST(StoredKey, MissingAddressReadd) { auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/missing-address.json"); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); - const auto wallet = key.wallet(password); + const auto wallet = key.wallet(gPassword); EXPECT_EQ(wallet.getMnemonic(), "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal"); EXPECT_TRUE(Mnemonic::isValid(wallet.getMnemonic())); @@ -468,12 +468,12 @@ TEST(StoredKey, EtherWalletAddressNo0x) { } TEST(StoredKey, CreateMinimalEncryptionParameters) { - const auto key = StoredKey::createWithMnemonic("name", password, mnemonic, TWStoredKeyEncryptionLevelMinimal); + const auto key = StoredKey::createWithMnemonic("name", gPassword, gMnemonic, TWStoredKeyEncryptionLevelMinimal); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); - const Data& mnemo2Data = key.payload.decrypt(password); - EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(mnemonic)); + const Data& mnemo2Data = key.payload.decrypt(gPassword); + EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(gMnemonic)); EXPECT_EQ(key.accounts.size(), 0ul); - EXPECT_EQ(key.wallet(password).getMnemonic(), string(mnemonic)); + EXPECT_EQ(key.wallet(gPassword).getMnemonic(), string(gMnemonic)); const auto json = key.json(); @@ -482,16 +482,16 @@ TEST(StoredKey, CreateMinimalEncryptionParameters) { // load it back const auto key2 = StoredKey::createWithJson(json); - EXPECT_EQ(key2.wallet(password).getMnemonic(), string(mnemonic)); + EXPECT_EQ(key2.wallet(gPassword).getMnemonic(), string(gMnemonic)); } TEST(StoredKey, CreateWeakEncryptionParameters) { - const auto key = StoredKey::createWithMnemonic("name", password, mnemonic, TWStoredKeyEncryptionLevelWeak); + const auto key = StoredKey::createWithMnemonic("name", gPassword, gMnemonic, TWStoredKeyEncryptionLevelWeak); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); - const Data& mnemo2Data = key.payload.decrypt(password); - EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(mnemonic)); + const Data& mnemo2Data = key.payload.decrypt(gPassword); + EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(gMnemonic)); EXPECT_EQ(key.accounts.size(), 0ul); - EXPECT_EQ(key.wallet(password).getMnemonic(), string(mnemonic)); + EXPECT_EQ(key.wallet(gPassword).getMnemonic(), string(gMnemonic)); const auto json = key.json(); @@ -500,16 +500,16 @@ TEST(StoredKey, CreateWeakEncryptionParameters) { // load it back const auto key2 = StoredKey::createWithJson(json); - EXPECT_EQ(key2.wallet(password).getMnemonic(), string(mnemonic)); + EXPECT_EQ(key2.wallet(gPassword).getMnemonic(), string(gMnemonic)); } TEST(StoredKey, CreateStandardEncryptionParameters) { - const auto key = StoredKey::createWithMnemonic("name", password, mnemonic, TWStoredKeyEncryptionLevelStandard); + const auto key = StoredKey::createWithMnemonic("name", gPassword, gMnemonic, TWStoredKeyEncryptionLevelStandard); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); - const Data& mnemo2Data = key.payload.decrypt(password); - EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(mnemonic)); + const Data& mnemo2Data = key.payload.decrypt(gPassword); + EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(gMnemonic)); EXPECT_EQ(key.accounts.size(), 0ul); - EXPECT_EQ(key.wallet(password).getMnemonic(), string(mnemonic)); + EXPECT_EQ(key.wallet(gPassword).getMnemonic(), string(gMnemonic)); const auto json = key.json(); @@ -518,21 +518,21 @@ TEST(StoredKey, CreateStandardEncryptionParameters) { // load it back const auto key2 = StoredKey::createWithJson(json); - EXPECT_EQ(key2.wallet(password).getMnemonic(), string(mnemonic)); + EXPECT_EQ(key2.wallet(gPassword).getMnemonic(), string(gMnemonic)); } TEST(StoredKey, CreateMultiAccounts) { // Multiple accounts for the same coin - auto key = StoredKey::createWithMnemonic("name", password, mnemonic, TWStoredKeyEncryptionLevelDefault); + auto key = StoredKey::createWithMnemonic("name", gPassword, gMnemonic, TWStoredKeyEncryptionLevelDefault); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); - const Data& mnemo2Data = key.payload.decrypt(password); - EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(mnemonic)); - EXPECT_EQ(key.wallet(password).getMnemonic(), string(mnemonic)); + const Data& mnemo2Data = key.payload.decrypt(gPassword); + EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(gMnemonic)); + EXPECT_EQ(key.wallet(gPassword).getMnemonic(), string(gMnemonic)); EXPECT_EQ(key.accounts.size(), 0ul); const auto expectedBtc1 = "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"; const auto expectedBtc2 = "1NyRyFewhZcWMa9XCj3bBxSXPXyoSg8dKz"; const auto expectedSol1 = "HiipoCKL8hX2RVmJTz3vaLy34hS2zLhWWMkUWtw85TmZ"; - const auto wallet = key.wallet(password); + const auto wallet = key.wallet(gPassword); auto expectedAccounts = 0ul; { // Create default Bitcoin account @@ -625,25 +625,25 @@ TEST(StoredKey, CreateMultiAccounts) { // Multiple accounts for the same coin TEST(StoredKey, CreateWithMnemonicAlternativeDerivation) { const auto coin = TWCoinTypeSolana; - auto key = StoredKey::createWithMnemonicAddDefaultAddress("name", password, mnemonic, coin); + auto key = StoredKey::createWithMnemonicAddDefaultAddress("name", gPassword, gMnemonic, coin); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); ASSERT_EQ(key.accounts.size(), 1ul); EXPECT_EQ(key.accounts[0].coin, coin); EXPECT_EQ(key.accounts[0].address, "HiipoCKL8hX2RVmJTz3vaLy34hS2zLhWWMkUWtw85TmZ"); EXPECT_EQ(key.accounts[0].publicKey, "f86b18399096c8134dd185f1e72dd7e26528772a2a998abfd81c5f8c547223d0"); - EXPECT_EQ(hex(key.privateKey(coin, password).bytes), "d81b5c525979e487736b69cb84ed8331559de17294f38491b304555c26687e83"); - EXPECT_EQ(hex(key.privateKey(coin, TWDerivationDefault, password).bytes), "d81b5c525979e487736b69cb84ed8331559de17294f38491b304555c26687e83"); + EXPECT_EQ(hex(key.privateKey(coin, gPassword).bytes), "d81b5c525979e487736b69cb84ed8331559de17294f38491b304555c26687e83"); + EXPECT_EQ(hex(key.privateKey(coin, TWDerivationDefault, gPassword).bytes), "d81b5c525979e487736b69cb84ed8331559de17294f38491b304555c26687e83"); ASSERT_EQ(key.accounts.size(), 1ul); // alternative derivation, different keys - EXPECT_EQ(hex(key.privateKey(coin, TWDerivationSolanaSolana, password).bytes), "d49a5fa7f77593534c7afd2ba8dc8e9d8b007bc6ec65fe8df25ffe6fafc57151"); + EXPECT_EQ(hex(key.privateKey(coin, TWDerivationSolanaSolana, gPassword).bytes), "d49a5fa7f77593534c7afd2ba8dc8e9d8b007bc6ec65fe8df25ffe6fafc57151"); ASSERT_EQ(key.accounts.size(), 2ul); EXPECT_EQ(key.accounts[1].coin, coin); EXPECT_EQ(key.accounts[1].address, "CgWJeEWkiYqosy1ba7a3wn9HAQuHyK48xs3LM4SSDc1C"); EXPECT_EQ(key.accounts[1].publicKey, "ad8f57924dce62f9040f93b4f6ce3c3d39afde7e29bcb4013dad59db7913c4c7"); - EXPECT_EQ(hex(key.privateKey(coin, TWDerivationSolanaSolana, password).bytes), "d49a5fa7f77593534c7afd2ba8dc8e9d8b007bc6ec65fe8df25ffe6fafc57151"); + EXPECT_EQ(hex(key.privateKey(coin, TWDerivationSolanaSolana, gPassword).bytes), "d49a5fa7f77593534c7afd2ba8dc8e9d8b007bc6ec65fe8df25ffe6fafc57151"); } } // namespace TW::Keystore diff --git a/tests/NEO/TransactionAttributeTests.cpp b/tests/NEO/TransactionAttributeTests.cpp index b99ca38141b..1ebfd2f9992 100644 --- a/tests/NEO/TransactionAttributeTests.cpp +++ b/tests/NEO/TransactionAttributeTests.cpp @@ -21,31 +21,31 @@ TEST(NEOTransactionAttribute, Serialize) { auto transactionAttribute = TransactionAttribute(); string data = "bdecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4a"; transactionAttribute.usage = TransactionAttributeUsage::TAU_ContractHash; - transactionAttribute.data = parse_hex(data); + transactionAttribute._data = parse_hex(data); EXPECT_EQ("00" + data, hex(transactionAttribute.serialize())); data = "bdecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4b"; transactionAttribute.usage = TransactionAttributeUsage::TAU_Vote; - transactionAttribute.data = parse_hex(data); + transactionAttribute._data = parse_hex(data); EXPECT_EQ("30" + data, hex(transactionAttribute.serialize())); transactionAttribute.usage = TransactionAttributeUsage::TAU_ECDH02; - transactionAttribute.data = parse_hex(data); + transactionAttribute._data = parse_hex(data); EXPECT_EQ("02" + data, hex(transactionAttribute.serialize())); data = "bdecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af"; transactionAttribute.usage = TransactionAttributeUsage::TAU_Script; - transactionAttribute.data = parse_hex(data); + transactionAttribute._data = parse_hex(data); EXPECT_EQ("20" + data, hex(transactionAttribute.serialize())); data = "bd"; transactionAttribute.usage = TransactionAttributeUsage::TAU_DescriptionUrl; - transactionAttribute.data = parse_hex(data); + transactionAttribute._data = parse_hex(data); EXPECT_EQ("81" + data, hex(transactionAttribute.serialize())); data = "bdecbb623eee6f9ade28d5a8ff5fb3ea"; transactionAttribute.usage = TransactionAttributeUsage::TAU_Remark; - transactionAttribute.data = parse_hex(data); + transactionAttribute._data = parse_hex(data); EXPECT_EQ("f0" + data, hex(transactionAttribute.serialize())); } @@ -54,31 +54,31 @@ TEST(NEOTransactionAttribute, Deserialize) { string data = "bdecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4a"; transactionAttribute.deserialize(parse_hex("00" + data)); EXPECT_EQ(TransactionAttributeUsage::TAU_ContractHash, transactionAttribute.usage); - EXPECT_EQ(data, hex(transactionAttribute.data)); + EXPECT_EQ(data, hex(transactionAttribute._data)); data = "bdecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4b"; transactionAttribute.deserialize(parse_hex("30" + data)); EXPECT_EQ(TransactionAttributeUsage::TAU_Vote, transactionAttribute.usage); - EXPECT_EQ(data, hex(transactionAttribute.data)); + EXPECT_EQ(data, hex(transactionAttribute._data)); transactionAttribute.deserialize(parse_hex("02" + data)); EXPECT_EQ(TransactionAttributeUsage::TAU_ECDH02, transactionAttribute.usage); - EXPECT_EQ(data, hex(transactionAttribute.data)); + EXPECT_EQ(data, hex(transactionAttribute._data)); data = "bdecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af"; transactionAttribute.deserialize(parse_hex("20" + data)); EXPECT_EQ(TransactionAttributeUsage::TAU_Script, transactionAttribute.usage); - EXPECT_EQ(data, hex(transactionAttribute.data)); + EXPECT_EQ(data, hex(transactionAttribute._data)); data = "bd"; transactionAttribute.deserialize(parse_hex("81" + data)); EXPECT_EQ(TransactionAttributeUsage::TAU_DescriptionUrl, transactionAttribute.usage); - EXPECT_EQ(data, hex(transactionAttribute.data)); + EXPECT_EQ(data, hex(transactionAttribute._data)); data = "bdecbb623eee6f9ade28d5a8ff5fb3ea"; transactionAttribute.deserialize(parse_hex("f0" + data)); EXPECT_EQ(TransactionAttributeUsage::TAU_Remark, transactionAttribute.usage); - EXPECT_EQ(data, hex(transactionAttribute.data)); + EXPECT_EQ(data, hex(transactionAttribute._data)); EXPECT_THROW(transactionAttribute.deserialize(parse_hex("b1" + data)), std::invalid_argument); } diff --git a/tests/NEO/TransactionTests.cpp b/tests/NEO/TransactionTests.cpp index 8224ac771b2..7ea44361a46 100644 --- a/tests/NEO/TransactionTests.cpp +++ b/tests/NEO/TransactionTests.cpp @@ -54,7 +54,7 @@ TEST(NEOTransaction, SerializeDeserializeAttribute) { const string oneVarLong = "01"; transaction.attributes.push_back(TransactionAttribute()); transaction.attributes[0].usage = TransactionAttributeUsage::TAU_ContractHash; - transaction.attributes[0].data = parse_hex("bdecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4a"); + transaction.attributes[0]._data = parse_hex("bdecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4a"); auto serialized = transaction.serialize(); EXPECT_EQ("8007" + oneVarLong + hex(transaction.attributes[0].serialize()) + zeroVarLong + zeroVarLong, hex(serialized)); @@ -64,7 +64,7 @@ TEST(NEOTransaction, SerializeDeserializeAttribute) { transaction.attributes.push_back(TransactionAttribute()); transaction.attributes[1].usage = TransactionAttributeUsage::TAU_ECDH02; - transaction.attributes[1].data = parse_hex("b7ecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4a"); + transaction.attributes[1]._data = parse_hex("b7ecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4a"); serialized = transaction.serialize(); const string twoVarLong = "02"; string expectedSerialized = "8007" + twoVarLong; @@ -150,7 +150,7 @@ TEST(NEOTransaction, SerializeDeserialize) { transaction.attributes.push_back(TransactionAttribute()); transaction.attributes[0].usage = TransactionAttributeUsage::TAU_ContractHash; - transaction.attributes[0].data = parse_hex("bdecbb623eee6f9ade28d5a8ff5fbdea9c9d73af039e0286201b3b0291fb4d4a"); + transaction.attributes[0]._data = parse_hex("bdecbb623eee6f9ade28d5a8ff5fbdea9c9d73af039e0286201b3b0291fb4d4a"); transaction.inInputs.push_back(CoinReference()); transaction.inInputs[0].prevHash = load(parse_hex("bdecbb623eee679ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4a")); @@ -220,7 +220,7 @@ TEST(NEOTransaction, SerializeDeserializeMiner) { string notMiner = "1000d11f7a2800000000"; EXPECT_THROW( - std::unique_ptr deserializedTransaction(Transaction::deserializeFrom(parse_hex(notMiner))), + std::unique_ptr _deserializedTransaction(Transaction::deserializeFrom(parse_hex(notMiner))), std::invalid_argument ); } diff --git a/tests/Ontology/ParamsBuilderTests.cpp b/tests/Ontology/ParamsBuilderTests.cpp index f39da1249b0..eed7e998aca 100644 --- a/tests/Ontology/ParamsBuilderTests.cpp +++ b/tests/Ontology/ParamsBuilderTests.cpp @@ -59,7 +59,7 @@ TEST(ParamsBuilder, pushInt) { } TEST(ParamsBuilder, balanceInvokeCode) { - auto balanceParam = Address("ANDfjwrUroaVtvBguDtrWKRMyxFwvVwnZD").data; + auto balanceParam = Address("ANDfjwrUroaVtvBguDtrWKRMyxFwvVwnZD")._data; auto invokeCode = ParamsBuilder::buildNativeInvokeCode(Ont().contractAddress(), 0x00, "balanceOf", balanceParam); auto hexInvokeCode = @@ -69,8 +69,8 @@ TEST(ParamsBuilder, balanceInvokeCode) { } TEST(ParamsBuilder, transferInvokeCode) { - auto fromAddress = Address("ANDfjwrUroaVtvBguDtrWKRMyxFwvVwnZD").data; - auto toAddress = Address("Af1n2cZHhMZumNqKgw9sfCNoTWu9de4NDn").data; + auto fromAddress = Address("ANDfjwrUroaVtvBguDtrWKRMyxFwvVwnZD")._data; + auto toAddress = Address("Af1n2cZHhMZumNqKgw9sfCNoTWu9de4NDn")._data; uint64_t amount = 1; std::list transferParam{fromAddress, toAddress, amount}; std::vector args{transferParam}; diff --git a/tests/Ontology/TransactionTests.cpp b/tests/Ontology/TransactionTests.cpp index 63db8af8e0f..c3ed787c304 100644 --- a/tests/Ontology/TransactionTests.cpp +++ b/tests/Ontology/TransactionTests.cpp @@ -25,7 +25,7 @@ TEST(OntologyTransaction, validity) { auto fromAddress = Address("AeicEjZyiXKgUeSBbYQHxsU1X3V5Buori5"); auto toAddress = Address("APniYDGozkhUh8Tk7pe35aah2HGJ4fJfVd"); uint64_t amount = 1; - std::list transferParam{fromAddress.data, toAddress.data, amount}; + std::list transferParam{fromAddress._data, toAddress._data, amount}; std::vector args{transferParam}; auto invokeCode = ParamsBuilder::buildNativeInvokeCode(ontContract, 0x00, "transfer", args); uint8_t version = 0; diff --git a/tests/Ronin/TWAnyAddressTests.cpp b/tests/Ronin/TWAnyAddressTests.cpp index 20c88c5eeac..d2e0bde63c7 100644 --- a/tests/Ronin/TWAnyAddressTests.cpp +++ b/tests/Ronin/TWAnyAddressTests.cpp @@ -16,7 +16,7 @@ const auto roninPrefixChecksummed = "ronin:EC49280228b0D05Aa8e8b756503254e1eE7835ab"; -const auto tests = { +const auto gTests = { roninPrefixChecksummed, "ronin:ec49280228b0d05aa8e8b756503254e1ee7835ab", "0xEC49280228b0D05Aa8e8b756503254e1eE7835ab", @@ -24,13 +24,13 @@ const auto tests = { }; TEST(RoninAnyAddress, Validate) { - for (const auto& t: tests) { + for (const auto& t: gTests) { EXPECT_TRUE(TWAnyAddressIsValid(STRING(t).get(), TWCoinTypeRonin)); } } TEST(RoninAnyAddress, Normalize) { - for (const auto& t: tests) { + for (const auto& t: gTests) { auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithString(STRING(t).get(), TWCoinTypeRonin)); auto string2 = WRAPS(TWAnyAddressDescription(addr.get())); EXPECT_TRUE(TWStringEqual(string2.get(), STRING(roninPrefixChecksummed).get())); diff --git a/tests/THORChain/TWSwapTests.cpp b/tests/THORChain/TWSwapTests.cpp index 7a589d9cf0e..807a936e95c 100644 --- a/tests/THORChain/TWSwapTests.cpp +++ b/tests/THORChain/TWSwapTests.cpp @@ -51,13 +51,13 @@ TEST(TWTHORChainSwap, SwapBtcToEth) { input.set_to_amount_limit("140000000000000000"); // serialize input - const auto inputData = input.SerializeAsString(); - EXPECT_EQ(hex(inputData), "0801122a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070381a0708021203455448222a3078623966353737316332373636346266323238326439386530396437663530636563376362303161372a2a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a373a07313030303030304212313430303030303030303030303030303030"); - const auto inputTWData = WRAPD(TWDataCreateWithBytes((const uint8_t *)inputData.data(), inputData.size())); + const auto inputData_ = input.SerializeAsString(); + EXPECT_EQ(hex(inputData_), "0801122a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070381a0708021203455448222a3078623966353737316332373636346266323238326439386530396437663530636563376362303161372a2a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a373a07313030303030304212313430303030303030303030303030303030"); + const auto inputTWData_ = WRAPD(TWDataCreateWithBytes((const uint8_t *)inputData_.data(), inputData_.size())); // invoke swap - const auto outputTWData = WRAPD(TWTHORChainSwapBuildSwap(inputTWData.get())); - const auto outputData = data(TWDataBytes(outputTWData.get()), TWDataSize(outputTWData.get())); + const auto outputTWData_ = WRAPD(TWTHORChainSwapBuildSwap(inputTWData_.get())); + const auto outputData = data(TWDataBytes(outputTWData_.get()), TWDataSize(outputTWData_.get())); EXPECT_EQ(outputData.size(), 178ul); // parse result in proto Proto::SwapOutput outputProto; @@ -131,13 +131,13 @@ TEST(TWTHORChainSwap, SwapEthBnb) { input.set_to_amount_limit("600003"); // serialize input - const auto inputData = input.SerializeAsString(); - EXPECT_EQ(hex(inputData), "0802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a1135303030303030303030303030303030304206363030303033"); - const auto inputTWData = WRAPD(TWDataCreateWithBytes((const uint8_t *)inputData.data(), inputData.size())); + const auto inputData_ = input.SerializeAsString(); + EXPECT_EQ(hex(inputData_), "0802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a1135303030303030303030303030303030304206363030303033"); + const auto inputTWData_ = WRAPD(TWDataCreateWithBytes((const uint8_t *)inputData_.data(), inputData_.size())); // invoke swap - const auto outputTWData = WRAPD(TWTHORChainSwapBuildSwap(inputTWData.get())); - const auto outputData = data(TWDataBytes(outputTWData.get()), TWDataSize(outputTWData.get())); + const auto outputTWData_ = WRAPD(TWTHORChainSwapBuildSwap(inputTWData_.get())); + const auto outputData = data(TWDataBytes(outputTWData_.get()), TWDataSize(outputTWData_.get())); EXPECT_EQ(outputData.size(), 311ul); // parse result in proto Proto::SwapOutput outputProto; @@ -185,13 +185,13 @@ TEST(TWTHORChainSwap, SwapBnbBtc) { input.set_to_amount_limit("10000000"); // serialize input - const auto inputData = input.SerializeAsString(); - EXPECT_EQ(hex(inputData), "0803122a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372781a0708011203425443222a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070382a2a626e62316e396573787577386361377473386c367736366b64683830307330396d7376756c36766c73653a08313030303030303042083130303030303030"); - const auto inputTWData = WRAPD(TWDataCreateWithBytes((const uint8_t *)inputData.data(), inputData.size())); + const auto inputData_ = input.SerializeAsString(); + EXPECT_EQ(hex(inputData_), "0803122a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372781a0708011203425443222a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070382a2a626e62316e396573787577386361377473386c367736366b64683830307330396d7376756c36766c73653a08313030303030303042083130303030303030"); + const auto inputTWData_ = WRAPD(TWDataCreateWithBytes((const uint8_t *)inputData_.data(), inputData_.size())); // invoke swap - const auto outputTWData = WRAPD(TWTHORChainSwapBuildSwap(inputTWData.get())); - const auto outputData = data(TWDataBytes(outputTWData.get()), TWDataSize(outputTWData.get())); + const auto outputTWData_ = WRAPD(TWTHORChainSwapBuildSwap(inputTWData_.get())); + const auto outputData = data(TWDataBytes(outputTWData_.get()), TWDataSize(outputTWData_.get())); EXPECT_EQ(outputData.size(), 149ul); // parse result in proto Proto::SwapOutput outputProto; diff --git a/tests/TransactionCompilerTests.cpp b/tests/TransactionCompilerTests.cpp index 62b1a9d75c0..0d9c8e4eab8 100644 --- a/tests/TransactionCompilerTests.cpp +++ b/tests/TransactionCompilerTests.cpp @@ -56,11 +56,11 @@ TEST(TransactionCompiler, BinanceCompileWithSignatures) { const auto preImageHashes = TransactionCompiler::preImageHashes(coin, txInputData); ASSERT_GT(preImageHashes.size(), 0ul); - TxCompiler::Proto::PreSigningOutput output; - ASSERT_TRUE(output.ParseFromArray(preImageHashes.data(), int(preImageHashes.size()))); - ASSERT_EQ(output.error(), 0); + TxCompiler::Proto::PreSigningOutput preSigningOutput; + ASSERT_TRUE(preSigningOutput.ParseFromArray(preImageHashes.data(), int(preImageHashes.size()))); + ASSERT_EQ(preSigningOutput.error(), 0); - auto preImageHash = data(output.data_hash()); + auto preImageHash = data(preSigningOutput.data_hash()); EXPECT_EQ(hex(preImageHash), "3f3fece9059e714d303a9a1496ddade8f2c38fa78fc4cc2e505c5dbb0ea678d1"); // Simulate signature, normally obtained from signature server @@ -159,14 +159,14 @@ TEST(TransactionCompiler, BitcoinCompileWithSignatures) { const auto ownAddress = "bc1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z00ppggv"; // Setup input for Plan - Bitcoin::Proto::SigningInput input; - input.set_coin_type(coin); - input.set_hash_type(TWBitcoinSigHashTypeAll); - input.set_amount(1'200'000); - input.set_use_max_amount(false); - input.set_byte_fee(1); - input.set_to_address("bc1q2dsdlq3343vk29runkgv4yc292hmq53jedfjmp"); - input.set_change_address(ownAddress); + Bitcoin::Proto::SigningInput signingInput; + signingInput.set_coin_type(coin); + signingInput.set_hash_type(TWBitcoinSigHashTypeAll); + signingInput.set_amount(1'200'000); + signingInput.set_use_max_amount(false); + signingInput.set_byte_fee(1); + signingInput.set_to_address("bc1q2dsdlq3343vk29runkgv4yc292hmq53jedfjmp"); + signingInput.set_change_address(ownAddress); // process UTXOs int count = 0; @@ -192,9 +192,9 @@ TEST(TransactionCompiler, BitcoinCompileWithSignatures) { if (count == 0) EXPECT_EQ(hex(redeemScript.bytes), "76a914bd92088bb7e82d611a9b94fbb74a0908152b784f88ac"); if (count == 1) EXPECT_EQ(hex(redeemScript.bytes), "76a914bd92088bb7e82d611a9b94fbb74a0908152b784f88ac"); if (count == 2) EXPECT_EQ(hex(redeemScript.bytes), "76a9146641abedacf9483b793afe1718689cc9420bbb1c88ac"); - (*input.mutable_scripts())[hex(keyHash)] = std::string(redeemScript.bytes.begin(), redeemScript.bytes.end()); + (*signingInput.mutable_scripts())[hex(keyHash)] = std::string(redeemScript.bytes.begin(), redeemScript.bytes.end()); - auto utxo = input.add_utxo(); + auto utxo = signingInput.add_utxo(); utxo->set_script(utxoScript.bytes.data(), utxoScript.bytes.size()); utxo->set_amount(u.amount); utxo->mutable_out_point()->set_hash(std::string(u.revUtxoHash.begin(), u.revUtxoHash.end())); @@ -204,11 +204,11 @@ TEST(TransactionCompiler, BitcoinCompileWithSignatures) { ++count; } EXPECT_EQ(count, 3); - EXPECT_EQ(input.utxo_size(), 3); + EXPECT_EQ(signingInput.utxo_size(), 3); // Plan Bitcoin::Proto::TransactionPlan plan; - ANY_PLAN(input, plan, coin); + ANY_PLAN(signingInput, plan, coin); // Plan is checked, assume it is accepted EXPECT_EQ(plan.amount(), 1'200'000); @@ -221,29 +221,29 @@ TEST(TransactionCompiler, BitcoinCompileWithSignatures) { EXPECT_EQ(hex(plan.utxos(2).out_point().hash()), hex(revUtxoHash0)); // Extend input with accepted plan - *input.mutable_plan() = plan; + *signingInput.mutable_plan() = plan; // Serialize input - const auto txInputData = data(input.SerializeAsString()); + const auto txInputData = data(signingInput.SerializeAsString()); EXPECT_EQ((int)txInputData.size(), 692); /// Step 2: Obtain preimage hashes const auto preImageHashes = TransactionCompiler::preImageHashes(coin, txInputData); - TW::Bitcoin::Proto::PreSigningOutput output; - ASSERT_TRUE(output.ParseFromArray(preImageHashes.data(), (int)preImageHashes.size())); + TW::Bitcoin::Proto::PreSigningOutput preSigningOutput; + ASSERT_TRUE(preSigningOutput.ParseFromArray(preImageHashes.data(), (int)preImageHashes.size())); - ASSERT_EQ(output.error(), 0); - EXPECT_EQ(hex(output.hash_public_keys()[0].data_hash()), "505f527f00e15fcc5a2d2416c9970beb57dfdfaca99e572a01f143b24dd8fab6"); - EXPECT_EQ(hex(output.hash_public_keys()[1].data_hash()), "a296bead4172007be69b21971a790e076388666c162a9505698415f1b003ebd7"); - EXPECT_EQ(hex(output.hash_public_keys()[2].data_hash()), "60ed6e9371e5ddc72fd88e46a12cb2f68516ebd307c0fd31b1b55cf767272101"); - EXPECT_EQ(hex(output.hash_public_keys()[0].public_key_hash()), hex(inPubKeyHash1)); - EXPECT_EQ(hex(output.hash_public_keys()[1].public_key_hash()), hex(inPubKeyHash0)); - EXPECT_EQ(hex(output.hash_public_keys()[2].public_key_hash()), hex(inPubKeyHash0)); + ASSERT_EQ(preSigningOutput.error(), 0); + EXPECT_EQ(hex(preSigningOutput.hash_public_keys()[0].data_hash()), "505f527f00e15fcc5a2d2416c9970beb57dfdfaca99e572a01f143b24dd8fab6"); + EXPECT_EQ(hex(preSigningOutput.hash_public_keys()[1].data_hash()), "a296bead4172007be69b21971a790e076388666c162a9505698415f1b003ebd7"); + EXPECT_EQ(hex(preSigningOutput.hash_public_keys()[2].data_hash()), "60ed6e9371e5ddc72fd88e46a12cb2f68516ebd307c0fd31b1b55cf767272101"); + EXPECT_EQ(hex(preSigningOutput.hash_public_keys()[0].public_key_hash()), hex(inPubKeyHash1)); + EXPECT_EQ(hex(preSigningOutput.hash_public_keys()[1].public_key_hash()), hex(inPubKeyHash0)); + EXPECT_EQ(hex(preSigningOutput.hash_public_keys()[2].public_key_hash()), hex(inPubKeyHash0)); // Simulate signatures, normally obtained from signature server. std::vector signatureVec; std::vector pubkeyVec; - for (const auto& h: output.hash_public_keys()) { + for (const auto& h: preSigningOutput.hash_public_keys()) { const auto& preImageHash = h.data_hash(); const auto& pubkeyhash = h.public_key_hash(); @@ -263,13 +263,13 @@ TEST(TransactionCompiler, BitcoinCompileWithSignatures) { } /// Step 3: Compile transaction info - const Data outputData = TransactionCompiler::compileWithSignatures(coin, txInputData, signatureVec, pubkeyVec); + const Data compileWithSignatures = TransactionCompiler::compileWithSignatures(coin, txInputData, signatureVec, pubkeyVec); const auto ExpectedTx = "010000000001036021efcf7555f90627364339fc921139dd40a06ccb2cb2a2a4f8f4ea7a2dc74d0000000000ffffffffd6892a5aa54e3b8fe430efd23f49a8950733aaa9d7c915d9989179f48dd1905e0100000000ffffffff07c42b969286be06fae38528c85f0a1ce508d4df837eb5ac4cf5f2a7a9d65fa80000000000ffffffff02804f1200000000001600145360df8231ac5965147c9d90ca930a2aafb05232cb92040000000000160014bd92088bb7e82d611a9b94fbb74a0908152b784f02473044022041294880caa09bb1b653775310fcdd1458da6b8e7d7fae34e37966414fe115820220646397c9d2513edc5974ecc336e9b287de0cdf071c366f3b3dc3ff309213e4e401210217142f69535e4dad0dc7060df645c55a174cc1bfa5b9eb2e59aad2ae96072dfc0247304402201857bc6e6e48b46046a4bd204136fc77e24c240943fb5a1f0e86387aae59b34902200a7f31478784e51c49f46ef072745a4f263d7efdbc9c6784aa2571ff4f6f2a400121024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382024730440220764e3d5b3971c4b3e70b23fb700a7462a6fe519d9830e863a1f8388c402ad0b102207e777f7972c636961f92375a2774af3b7a2a04190251bbcb31d19c70927952dc0121024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb49338200000000"; { - EXPECT_EQ(outputData.size(), 786ul); + EXPECT_EQ(compileWithSignatures.size(), 786ul); Bitcoin::Proto::SigningOutput output; - ASSERT_TRUE(output.ParseFromArray(outputData.data(), (int)outputData.size())); + ASSERT_TRUE(output.ParseFromArray(compileWithSignatures.data(), (int)compileWithSignatures.size())); EXPECT_EQ(output.encoded().size(), 518ul); EXPECT_EQ(hex(output.encoded()), ExpectedTx); @@ -334,35 +334,35 @@ TEST(TransactionCompiler, EthereumCompileWithSignatures) { // Check, by parsing EXPECT_EQ((int)txInputData0.size(), 61); - Ethereum::Proto::SigningInput input; - ASSERT_TRUE(input.ParseFromArray(txInputData0.data(), (int)txInputData0.size())); - EXPECT_EQ(hex(input.chain_id()), "01"); - EXPECT_EQ(input.to_address(), "0x3535353535353535353535353535353535353535"); - ASSERT_TRUE(input.transaction().has_transfer()); - EXPECT_EQ(hex(input.transaction().transfer().amount()), "0de0b6b3a7640000"); + Ethereum::Proto::SigningInput signingInput; + ASSERT_TRUE(signingInput.ParseFromArray(txInputData0.data(), (int)txInputData0.size())); + EXPECT_EQ(hex(signingInput.chain_id()), "01"); + EXPECT_EQ(signingInput.to_address(), "0x3535353535353535353535353535353535353535"); + ASSERT_TRUE(signingInput.transaction().has_transfer()); + EXPECT_EQ(hex(signingInput.transaction().transfer().amount()), "0de0b6b3a7640000"); // Set a few other values const auto nonce = store(uint256_t(11)); const auto gasPrice = store(uint256_t(20000000000)); const auto gasLimit = store(uint256_t(21000)); - input.set_nonce(nonce.data(), nonce.size()); - input.set_gas_price(gasPrice.data(), gasPrice.size()); - input.set_gas_limit(gasLimit.data(), gasLimit.size()); - input.set_tx_mode(Ethereum::Proto::Legacy); + signingInput.set_nonce(nonce.data(), nonce.size()); + signingInput.set_gas_price(gasPrice.data(), gasPrice.size()); + signingInput.set_gas_limit(gasLimit.data(), gasLimit.size()); + signingInput.set_tx_mode(Ethereum::Proto::Legacy); - // Serialize back, this shows how to serialize SigningInput protobuf to byte array - const auto txInputData = data(input.SerializeAsString()); + // Serialize back, this shows how to serialize input protobuf to byte array + const auto txInputData = data(signingInput.SerializeAsString()); EXPECT_EQ((int)txInputData.size(), 75); /// Step 2: Obtain preimage hash const auto preImageHashes = TransactionCompiler::preImageHashes(coin, txInputData); ASSERT_GT(preImageHashes.size(), 0ul); - TxCompiler::Proto::PreSigningOutput output; - ASSERT_TRUE(output.ParseFromArray(preImageHashes.data(), int(preImageHashes.size()))); - ASSERT_EQ(output.error(), 0); + TxCompiler::Proto::PreSigningOutput preSigningOutput; + ASSERT_TRUE(preSigningOutput.ParseFromArray(preImageHashes.data(), int(preImageHashes.size()))); + ASSERT_EQ(preSigningOutput.error(), 0); - auto preImageHash = data(output.data_hash()); + auto preImageHash = data(preSigningOutput.data_hash()); EXPECT_EQ(hex(preImageHash), "15e180a6274b2f6a572b9b51823fce25ef39576d10188ecdcd7de44526c47217"); // Simulate signature, normally obtained from signature server diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp index dddffb8b517..5ace16a9351 100644 --- a/tests/interface/TWHDWalletTests.cpp +++ b/tests/interface/TWHDWalletTests.cpp @@ -27,8 +27,8 @@ using namespace TW; const auto wordsStr = "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal"; -const auto words = STRING(wordsStr); -const auto passphrase = STRING("TREZOR"); +const auto gWords = STRING(wordsStr); +const auto gPassphrase = STRING("TREZOR"); const auto seedHex = "7ae6f661157bda6492f6162701e570097fc726b6235011ea5ad09bf04986731ed4d92bc43cbdee047b60ea0dd1b1fa4274377c9bf5bd14ab1982c272d8076f29"; const auto entropyHex = "ba5821e8c356c05ba5f025d9532fe0f21f65d594"; @@ -49,31 +49,31 @@ inline void assertEntropyEq(const std::shared_ptr& wallet, const cha } TEST(HDWallet, CreateFromMnemonic) { - const auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + const auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); assertMnemonicEq(wallet, wordsStr); assertEntropyEq(wallet, entropyHex); assertSeedEq(wallet, seedHex); } TEST(HDWallet, CreateFromEntropy) { - const auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithEntropy(DATA(entropyHex).get(), passphrase.get())); + const auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithEntropy(DATA(entropyHex).get(), gPassphrase.get())); assertMnemonicEq(wallet, wordsStr); assertSeedEq(wallet, seedHex); assertEntropyEq(wallet, entropyHex); } TEST(HDWallet, Generate) { - const auto wallet = WRAP(TWHDWallet, TWHDWalletCreate(128, passphrase.get())); + const auto wallet = WRAP(TWHDWallet, TWHDWalletCreate(128, gPassphrase.get())); EXPECT_TRUE(TWMnemonicIsValid(WRAPS(TWHDWalletMnemonic(wallet.get())).get())); } TEST(HDWallet, SeedWithExtraSpaces) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); assertSeedEq(wallet, "7ae6f661157bda6492f6162701e570097fc726b6235011ea5ad09bf04986731ed4d92bc43cbdee047b60ea0dd1b1fa4274377c9bf5bd14ab1982c272d8076f29"); } TEST(HDWallet, CreateFromMnemonicNoPassword) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), STRING("").get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), STRING("").get())); assertSeedEq(wallet, "354c22aedb9a37407adc61f657a6f00d10ed125efa360215f36c6919abd94d6dbc193a5f9c495e21ee74118661e327e84a5f5f11fa373ec33b80897d4697557d"); } @@ -88,7 +88,7 @@ TEST(HDWallet, CreateFromMnemonicInvalid) { } TEST(HDWallet, MasterPrivateKey) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), STRING("").get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), STRING("").get())); auto key1 = WRAP(TWPrivateKey, TWHDWalletGetMasterKey(wallet.get(), TWCurveSECP256k1)); auto hexKey1 = WRAPD(TWPrivateKeyData(key1.get())); @@ -102,7 +102,7 @@ TEST(HDWallet, MasterPrivateKey) { TEST(HDWallet, Derive) { const auto derivationPath = TW::derivationPath(TWCoinTypeEthereum); - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto key0 = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeEthereum)); auto publicKey0 = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(key0.get(), false)); @@ -112,7 +112,7 @@ TEST(HDWallet, Derive) { } TEST(HDWallet, DeriveBitcoinNonextended) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto key = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeBitcoin)); auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(key.get(), false)); auto publicKeyData = WRAPD(TWPublicKeyData(publicKey.get())); @@ -122,7 +122,7 @@ TEST(HDWallet, DeriveBitcoinNonextended) { } TEST(HDWallet, DeriveBitcoinExtended) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto key = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeBitcoin)); auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(key.get(), true)); auto publicKeyData = WRAPD(TWPublicKeyData(publicKey.get())); @@ -134,13 +134,13 @@ TEST(HDWallet, DeriveBitcoinExtended) { } TEST(HDWallet, DeriveAddressBitcoin) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto address = WRAP(TWString, TWHDWalletGetAddressForCoin(wallet.get(), TWCoinTypeBitcoin)); assertStringsEqual(address, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85"); } TEST(HDWallet, DeriveEthereum) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto key = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeEthereum)); auto key2 = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeSmartChain)); @@ -157,7 +157,7 @@ TEST(HDWallet, DeriveEthereum) { } TEST(HDWallet, DeriveAddressEthereum) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto address = WRAP(TWString, TWHDWalletGetAddressForCoin(wallet.get(), TWCoinTypeEthereum)); assertStringsEqual(address, "0x27Ef5cDBe01777D62438AfFeb695e33fC2335979"); } @@ -179,7 +179,7 @@ TEST(HDWallet, DeriveCosmos) { } TEST(HDWallet, DeriveNimiq) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto key = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeNimiq)); auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyEd25519(key.get())); auto publicKeyData = WRAPD(TWPublicKeyData(publicKey.get())); @@ -188,7 +188,7 @@ TEST(HDWallet, DeriveNimiq) { } TEST(HDWallet, DeriveTezos) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto key = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeTezos)); auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyEd25519(key.get())); auto publicKeyData = WRAPD(TWPublicKeyData(publicKey.get())); @@ -197,7 +197,7 @@ TEST(HDWallet, DeriveTezos) { } TEST(HDWallet, DeriveDoge) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto key = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeDogecoin)); auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(key.get(), true)); auto publicKeyData = WRAPD(TWPublicKeyData(publicKey.get())); @@ -212,7 +212,7 @@ TEST(HDWallet, DeriveDoge) { } TEST(HDWallet, DeriveZilliqa) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto key = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeZilliqa)); auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(key.get(), true)); auto publicKeyData = WRAPD(TWPublicKeyData(publicKey.get())); @@ -244,7 +244,7 @@ TEST(HDWallet, DeriveFIO) { } TEST(HDWallet, DeriveAlgorand) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeAlgorand)); auto privateKeyData = WRAPD(TWPrivateKeyData(privateKey.get())); auto address = WRAPS(TWCoinTypeDeriveAddress(TWCoinTypeAlgorand, privateKey.get())); @@ -253,7 +253,7 @@ TEST(HDWallet, DeriveAlgorand) { } TEST(HDWallet, DeriveElrond) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeElrond)); auto privateKeyData = WRAPD(TWPrivateKeyData(privateKey.get())); auto address = WRAPS(TWCoinTypeDeriveAddress(TWCoinTypeElrond, privateKey.get())); @@ -263,7 +263,7 @@ TEST(HDWallet, DeriveElrond) { } TEST(HDWallet, DeriveBinance) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto key = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeBinance)); auto key2 = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeSmartChain)); auto keyData = WRAPD(TWPrivateKeyData(key.get())); @@ -277,7 +277,7 @@ TEST(HDWallet, DeriveBinance) { } TEST(HDWallet, DeriveAvalancheCChain) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto key = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeAvalancheCChain)); auto keyData = WRAPD(TWPrivateKeyData(key.get())); @@ -287,7 +287,7 @@ TEST(HDWallet, DeriveAvalancheCChain) { } TEST(HDWallet, DeriveCardano) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeCardano)); auto privateKeyData = WRAPD(TWPrivateKeyData(privateKey.get())); EXPECT_EQ(TWDataSize(privateKeyData.get()), 192ul); @@ -449,7 +449,7 @@ TEST(HDWallet, MultipleThreads) { } TEST(HDWallet, GetDerivedKey) { - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); const auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetDerivedKey(wallet.get(), TWCoinTypeBitcoin, 0, 0, 0)); const auto privateKeyData = WRAPD(TWPrivateKeyData(privateKey.get())); assertHexEqual(privateKeyData, "1901b5994f075af71397f65bd68a9fff8d3025d65f5a2c731cf90f5e259d6aac"); @@ -460,7 +460,7 @@ TEST(TWHDWallet, Derive_XpubPub_vs_PrivPub) { // - Direct: mnemonic -> seed -> privateKey -> publicKey -> address // - Extended Public: mnemonic -> seed -> zpub -> publicKey -> address - auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), STRING("").get())); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), STRING("").get())); const auto coin = TWCoinTypeBitcoin; const auto derivPath1 = STRING("m/84'/0'/0'/0/0"); const auto derivPath2 = STRING("m/84'/0'/0'/0/2"); diff --git a/tests/interface/TWPrivateKeyTests.cpp b/tests/interface/TWPrivateKeyTests.cpp index d6fe4ea8f36..96df973cf57 100644 --- a/tests/interface/TWPrivateKeyTests.cpp +++ b/tests/interface/TWPrivateKeyTests.cpp @@ -167,7 +167,7 @@ TEST(TWPrivateKeyTests, SignAsDER) { const auto data = WRAPD(TWDataCreateWithBytes((uint8_t *)message, strlen(message))); const auto hash = WRAPD(TWHashKeccak256(data.get())); - auto actual = WRAPD(TWPrivateKeySignAsDER(privateKey.get(), hash.get(), TWCurveSECP256k1)); + auto actual = WRAPD(TWPrivateKeySignAsDER(privateKey.get(), hash.get())); ASSERT_EQ(TW::hex(*((TW::Data*)actual.get())), "30450221008720a46b5b3963790d94bcc61ad57ca02fd153584315bfa161ed3455e336ba6202204d68df010ed934b8792c5b6a57ba86c3da31d039f9612b44d1bf054132254de9"); diff --git a/tests/interface/TWPublicKeyTests.cpp b/tests/interface/TWPublicKeyTests.cpp index 39d06485ff9..5fd8fbd7af8 100644 --- a/tests/interface/TWPublicKeyTests.cpp +++ b/tests/interface/TWPublicKeyTests.cpp @@ -89,7 +89,7 @@ TEST(TWPublicKeyTests, VerifyAsDER) { auto messageData = WRAPD(TWDataCreateWithBytes((const uint8_t*)message, strlen(message))); auto digest = WRAPD(TWHashKeccak256(messageData.get())); - auto signature = WRAPD(TWPrivateKeySignAsDER(privateKey.get(), digest.get(), TWCurveSECP256k1)); + auto signature = WRAPD(TWPrivateKeySignAsDER(privateKey.get(), digest.get())); auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(privateKey.get(), false)); diff --git a/tests/interface/TWTransactionCompilerTests.cpp b/tests/interface/TWTransactionCompilerTests.cpp index 4cb3bd77a1b..5793a97340a 100644 --- a/tests/interface/TWTransactionCompilerTests.cpp +++ b/tests/interface/TWTransactionCompilerTests.cpp @@ -59,10 +59,10 @@ TEST(TWTransactionCompiler, ExternalSignatureSignBinance) { const auto preImageHashes = WRAPD(TWTransactionCompilerPreImageHashes(coin, txInputData.get())); auto preImageHash = data(TWDataBytes(preImageHashes.get()), TWDataSize(preImageHashes.get())); - TxCompiler::Proto::PreSigningOutput output; - ASSERT_TRUE(output.ParseFromArray(preImageHash.data(), int(preImageHash.size()))); - ASSERT_EQ(output.error(), 0); - const auto preImageHashData = data(output.data_hash()); + TxCompiler::Proto::PreSigningOutput preSigningOutput; + ASSERT_TRUE(preSigningOutput.ParseFromArray(preImageHash.data(), int(preImageHash.size()))); + ASSERT_EQ(preSigningOutput.error(), 0); + const auto preImageHashData = data(preSigningOutput.data_hash()); EXPECT_EQ(hex(preImageHashData), "3f3fece9059e714d303a9a1496ddade8f2c38fa78fc4cc2e505c5dbb0ea678d1"); @@ -121,24 +121,24 @@ TEST(TWTransactionCompiler, ExternalSignatureSignEthereum) { // Check, by parsing EXPECT_EQ((int)TWDataSize(txInputData0.get()), 61); - Ethereum::Proto::SigningInput input; - ASSERT_TRUE(input.ParseFromArray(TWDataBytes(txInputData0.get()), (int)TWDataSize(txInputData0.get()))); - EXPECT_EQ(hex(input.chain_id()), "01"); - EXPECT_EQ(input.to_address(), "0x3535353535353535353535353535353535353535"); - ASSERT_TRUE(input.transaction().has_transfer()); - EXPECT_EQ(hex(input.transaction().transfer().amount()), "0de0b6b3a7640000"); + Ethereum::Proto::SigningInput signingInput; + ASSERT_TRUE(signingInput.ParseFromArray(TWDataBytes(txInputData0.get()), (int)TWDataSize(txInputData0.get()))); + EXPECT_EQ(hex(signingInput.chain_id()), "01"); + EXPECT_EQ(signingInput.to_address(), "0x3535353535353535353535353535353535353535"); + ASSERT_TRUE(signingInput.transaction().has_transfer()); + EXPECT_EQ(hex(signingInput.transaction().transfer().amount()), "0de0b6b3a7640000"); // Set a few other values const auto nonce = store(uint256_t(11)); const auto gasPrice = store(uint256_t(20000000000)); const auto gasLimit = store(uint256_t(21000)); - input.set_nonce(nonce.data(), nonce.size()); - input.set_gas_price(gasPrice.data(), gasPrice.size()); - input.set_gas_limit(gasLimit.data(), gasLimit.size()); - input.set_tx_mode(Ethereum::Proto::Legacy); + signingInput.set_nonce(nonce.data(), nonce.size()); + signingInput.set_gas_price(gasPrice.data(), gasPrice.size()); + signingInput.set_gas_limit(gasLimit.data(), gasLimit.size()); + signingInput.set_tx_mode(Ethereum::Proto::Legacy); // Serialize back, this shows how to serialize SigningInput protobuf to byte array - const auto txInputDataData = data(input.SerializeAsString()); + const auto txInputDataData = data(signingInput.SerializeAsString()); const auto txInputData = WRAPD(TWDataCreateWithBytes(txInputDataData.data(), txInputDataData.size())); EXPECT_EQ((int)TWDataSize(txInputData.get()), 75); @@ -146,10 +146,10 @@ TEST(TWTransactionCompiler, ExternalSignatureSignEthereum) { const auto preImageHashes = WRAPD(TWTransactionCompilerPreImageHashes(coin, txInputData.get())); auto preImageHash = data(TWDataBytes(preImageHashes.get()), TWDataSize(preImageHashes.get())); - TxCompiler::Proto::PreSigningOutput output; - ASSERT_TRUE(output.ParseFromArray(preImageHash.data(), int(preImageHash.size()))); - ASSERT_EQ(output.error(), 0); - const auto preImageHashData = data(output.data_hash()); + TxCompiler::Proto::PreSigningOutput preSigningOutput; + ASSERT_TRUE(preSigningOutput.ParseFromArray(preImageHash.data(), int(preImageHash.size()))); + ASSERT_EQ(preSigningOutput.error(), 0); + const auto preImageHashData = data(preSigningOutput.data_hash()); EXPECT_EQ(hex(preImageHashData), "15e180a6274b2f6a572b9b51823fce25ef39576d10188ecdcd7de44526c47217"); // Simulate signature, normally obtained from signature server @@ -259,14 +259,14 @@ TEST(TWTransactionCompiler, ExternalSignatureSignBitcoin) { const auto ownAddress = "bc1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z00ppggv"; // Setup input for Plan - Bitcoin::Proto::SigningInput input; - input.set_coin_type(coin); - input.set_hash_type(TWBitcoinSigHashTypeAll); - input.set_amount(1'200'000); - input.set_use_max_amount(false); - input.set_byte_fee(1); - input.set_to_address("bc1q2dsdlq3343vk29runkgv4yc292hmq53jedfjmp"); - input.set_change_address(ownAddress); + Bitcoin::Proto::SigningInput signingInput; + signingInput.set_coin_type(coin); + signingInput.set_hash_type(TWBitcoinSigHashTypeAll); + signingInput.set_amount(1'200'000); + signingInput.set_use_max_amount(false); + signingInput.set_byte_fee(1); + signingInput.set_to_address("bc1q2dsdlq3343vk29runkgv4yc292hmq53jedfjmp"); + signingInput.set_change_address(ownAddress); // process UTXOs int count = 0; @@ -292,9 +292,9 @@ TEST(TWTransactionCompiler, ExternalSignatureSignBitcoin) { if (count == 0) EXPECT_EQ(hex(redeemScript.bytes), "76a914bd92088bb7e82d611a9b94fbb74a0908152b784f88ac"); if (count == 1) EXPECT_EQ(hex(redeemScript.bytes), "76a914bd92088bb7e82d611a9b94fbb74a0908152b784f88ac"); if (count == 2) EXPECT_EQ(hex(redeemScript.bytes), "76a9146641abedacf9483b793afe1718689cc9420bbb1c88ac"); - (*input.mutable_scripts())[hex(keyHash)] = std::string(redeemScript.bytes.begin(), redeemScript.bytes.end()); + (*signingInput.mutable_scripts())[hex(keyHash)] = std::string(redeemScript.bytes.begin(), redeemScript.bytes.end()); - auto utxo = input.add_utxo(); + auto utxo = signingInput.add_utxo(); utxo->set_script(utxoScript.bytes.data(), utxoScript.bytes.size()); utxo->set_amount(u.amount); utxo->mutable_out_point()->set_hash(std::string(u.revUtxoHash.begin(), u.revUtxoHash.end())); @@ -304,11 +304,11 @@ TEST(TWTransactionCompiler, ExternalSignatureSignBitcoin) { ++count; } EXPECT_EQ(count, 3); - EXPECT_EQ(input.utxo_size(), 3); + EXPECT_EQ(signingInput.utxo_size(), 3); // Plan Bitcoin::Proto::TransactionPlan plan; - ANY_PLAN(input, plan, coin); + ANY_PLAN(signingInput, plan, coin); // Plan is checked, assume it is accepted EXPECT_EQ(plan.amount(), 1'200'000); @@ -321,10 +321,10 @@ TEST(TWTransactionCompiler, ExternalSignatureSignBitcoin) { EXPECT_EQ(hex(plan.utxos(2).out_point().hash()), hex(revUtxoHash0)); // Extend input with accepted plan - *input.mutable_plan() = plan; + *signingInput.mutable_plan() = plan; - // Serialize input - const auto txInputDataData = data(input.SerializeAsString()); + // Serialize signingInput + const auto txInputDataData = data(signingInput.SerializeAsString()); const auto txInputData = WRAPD(TWDataCreateWithBytes(txInputDataData.data(), txInputDataData.size())); EXPECT_EQ((int)TWDataSize(txInputData.get()), 692); @@ -346,10 +346,10 @@ TEST(TWTransactionCompiler, ExternalSignatureSignBitcoin) { auto signatureVec = WRAP(TWDataVector, TWDataVectorCreate()); auto pubkeyVec = WRAP(TWDataVector, TWDataVectorCreate()); for (const auto& h: hashes) { - const auto& preImageHash = TW::data(h.data_hash()); + const auto& preImageHash_ = TW::data(h.data_hash()); const auto& pubkeyhash = h.public_key_hash(); - const std::string key = hex(pubkeyhash) + "+" + hex(preImageHash); + const std::string key = hex(pubkeyhash) + "+" + hex(preImageHash_); const auto sigInfoFind = signatureInfos.find(key); ASSERT_TRUE(sigInfoFind != signatureInfos.end()); const auto& sigInfo = std::get<1>(*sigInfoFind); @@ -360,7 +360,7 @@ TEST(TWTransactionCompiler, ExternalSignatureSignBitcoin) { TWDataVectorAdd(signatureVec.get(), WRAPD(TWDataCreateWithBytes(signature.data(), signature.size())).get()); TWDataVectorAdd(pubkeyVec.get(), WRAPD(TWDataCreateWithBytes(publicKeyData.data(), publicKeyData.size())).get()); // Verify signature (pubkey & hash & signature) - EXPECT_TRUE(publicKey.verifyAsDER(signature, preImageHash)); + EXPECT_TRUE(publicKey.verifyAsDER(signature, preImageHash_)); } /// Step 3: Compile transaction info const auto outputData = WRAPD(TWTransactionCompilerCompileWithSignatures( From 81650fbfe2c68e7fe6c31ce6d7031b5cfc10e275 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 29 Jul 2022 23:58:04 +0200 Subject: [PATCH 044/497] fix: add missing header guards (#2424) --- src/Aeternity/Address.h | 2 ++ src/Aeternity/Signer.h | 2 ++ src/Algorand/AssetTransfer.h | 2 ++ src/Algorand/OptInAssetTransaction.h | 2 ++ src/Bech32.h | 2 ++ src/Defer.h | 2 ++ src/Tezos/Forging.h | 2 ++ 7 files changed, 14 insertions(+) diff --git a/src/Aeternity/Address.h b/src/Aeternity/Address.h index 07e9b732939..3733a44e93d 100644 --- a/src/Aeternity/Address.h +++ b/src/Aeternity/Address.h @@ -4,6 +4,8 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#pragma once + #include #include diff --git a/src/Aeternity/Signer.h b/src/Aeternity/Signer.h index dd289e5487d..b1cb5aaa7bf 100644 --- a/src/Aeternity/Signer.h +++ b/src/Aeternity/Signer.h @@ -4,6 +4,8 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#pragma once + #include "Transaction.h" #include "../proto/Aeternity.pb.h" #include diff --git a/src/Algorand/AssetTransfer.h b/src/Algorand/AssetTransfer.h index cdc5bab9c2b..030a90dcc2d 100644 --- a/src/Algorand/AssetTransfer.h +++ b/src/Algorand/AssetTransfer.h @@ -4,6 +4,8 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#pragma once + #include "Address.h" #include "BaseTransaction.h" #include "../Data.h" diff --git a/src/Algorand/OptInAssetTransaction.h b/src/Algorand/OptInAssetTransaction.h index 2f9b7c55394..8412c3e4e46 100644 --- a/src/Algorand/OptInAssetTransaction.h +++ b/src/Algorand/OptInAssetTransaction.h @@ -4,6 +4,8 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#pragma once + #include "Address.h" #include "BaseTransaction.h" #include "../Data.h" diff --git a/src/Bech32.h b/src/Bech32.h index 60037fc5794..f9f8311a786 100644 --- a/src/Bech32.h +++ b/src/Bech32.h @@ -5,6 +5,8 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#pragma once + #include "Data.h" #include diff --git a/src/Defer.h b/src/Defer.h index e8c70316733..744eba85655 100644 --- a/src/Defer.h +++ b/src/Defer.h @@ -4,6 +4,8 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#pragma once + #ifndef defer // https://stackoverflow.com/a/42060129/411431 struct defer_dummy {}; diff --git a/src/Tezos/Forging.h b/src/Tezos/Forging.h index 45f4624e282..9e7b1125c4a 100644 --- a/src/Tezos/Forging.h +++ b/src/Tezos/Forging.h @@ -4,6 +4,8 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#pragma once + #include "../PublicKey.h" #include "../proto/Tezos.pb.h" From 200bd11232c4d6b848a90efbac1ccd8c8abf84e0 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 29 Jul 2022 23:58:26 +0200 Subject: [PATCH 045/497] fix: warning base64 tests (integer comparison) (#2425) --- tests/interface/TWBase64Tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/interface/TWBase64Tests.cpp b/tests/interface/TWBase64Tests.cpp index 15aa7fa7b05..d3da4e2f747 100644 --- a/tests/interface/TWBase64Tests.cpp +++ b/tests/interface/TWBase64Tests.cpp @@ -15,7 +15,7 @@ TEST(TWBase64, Decode) { const auto encodedInput = STRING("Kyc/YWI="); auto result = WRAPD(TWBase64Decode(encodedInput.get())); - ASSERT_EQ(TWDataSize(result.get()), 5); + ASSERT_EQ(TWDataSize(result.get()), 5ul); auto data = *reinterpret_cast(result.get()); std::string str(data.begin(), data.end()); @@ -37,7 +37,7 @@ TEST(TWBase64, DecodeUrl) { const auto encodedInput = STRING("Kyc_YWI="); auto result = WRAPD(TWBase64DecodeUrl(encodedInput.get())); - ASSERT_EQ(TWDataSize(result.get()), 5); + ASSERT_EQ(TWDataSize(result.get()), 5ul); auto data = *reinterpret_cast(result.get()); std::string str(data.begin(), data.end()); From c1b7a27bdecd3c3125f37199dd8fc4c907436867 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Wed, 3 Aug 2022 15:21:30 +0200 Subject: [PATCH 046/497] Add getKeyByCurve method (#2473) * Add getCurveKey method * Add name and test case * Refactor getKeyByCurve so that getKey reuses it * Add C++ tests as well Co-authored-by: lmcmz --- include/TrustWalletCore/TWHDWallet.h | 4 ++++ src/HDWallet.cpp | 4 ++++ src/HDWallet.h | 3 +++ src/interface/TWHDWallet.cpp | 6 ++++++ tests/HDWallet/HDWalletTests.cpp | 26 ++++++++++++++++++++++++++ tests/interface/TWHDWalletTests.cpp | 13 +++++++++++++ 6 files changed, 56 insertions(+) diff --git a/include/TrustWalletCore/TWHDWallet.h b/include/TrustWalletCore/TWHDWallet.h index 1e52859422d..9ab93773c3a 100644 --- a/include/TrustWalletCore/TWHDWallet.h +++ b/include/TrustWalletCore/TWHDWallet.h @@ -76,6 +76,10 @@ TWString *_Nonnull TWHDWalletGetAddressForCoin(struct TWHDWallet *_Nonnull walle TW_EXPORT_METHOD struct TWPrivateKey *_Nonnull TWHDWalletGetKey(struct TWHDWallet *_Nonnull wallet, enum TWCoinType coin, TWString *_Nonnull derivationPath); +/// Generates the private key for the specified derivation path and curve. Returned object needs to be deleted. +TW_EXPORT_METHOD +struct TWPrivateKey *_Nonnull TWHDWalletGetKeyByCurve(struct TWHDWallet *_Nonnull wallet, enum TWCurve curve, TWString *_Nonnull derivationPath); + /// Shortcut method to generate private key with the specified account/change/address (bip44 standard). Returned object needs to be deleted. /// /// @see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki diff --git a/src/HDWallet.cpp b/src/HDWallet.cpp index 56ef7730d14..47e84bdec75 100644 --- a/src/HDWallet.cpp +++ b/src/HDWallet.cpp @@ -122,6 +122,10 @@ DerivationPath HDWallet::cardanoStakingDerivationPath(const DerivationPath& path PrivateKey HDWallet::getKey(TWCoinType coin, const DerivationPath& derivationPath) const { const auto curve = TWCoinTypeCurve(coin); + return getKeyByCurve(curve, derivationPath); +} + +PrivateKey HDWallet::getKeyByCurve(TWCurve curve, const DerivationPath& derivationPath) const { const auto privateKeyType = PrivateKey::getType(curve); auto node = getNode(*this, curve, derivationPath); switch (privateKeyType) { diff --git a/src/HDWallet.h b/src/HDWallet.h index ecb37e0fc95..0579591c82e 100644 --- a/src/HDWallet.h +++ b/src/HDWallet.h @@ -81,6 +81,9 @@ class HDWallet { /// Returns the private key at the given derivation path. PrivateKey getKey(const TWCoinType coin, const DerivationPath& derivationPath) const; + /// Returns the private key at the given derivation path and curve. + PrivateKey getKeyByCurve(TWCurve curve, const DerivationPath& derivationPath) const; + /// Derives the address for a coin (default derivation). std::string deriveAddress(TWCoinType coin) const; diff --git a/src/interface/TWHDWallet.cpp b/src/interface/TWHDWallet.cpp index 8b8a38b79b5..18447aa54bd 100644 --- a/src/interface/TWHDWallet.cpp +++ b/src/interface/TWHDWallet.cpp @@ -89,6 +89,12 @@ struct TWPrivateKey *_Nonnull TWHDWalletGetDerivedKey(struct TWHDWallet *_Nonnul return new TWPrivateKey{ wallet->impl.getKey(coin, derivationPath) }; } +struct TWPrivateKey *_Nonnull TWHDWalletGetKeyByCurve(struct TWHDWallet *_Nonnull wallet, enum TWCurve curve, TWString *_Nonnull derivationPath) { + auto& s = *reinterpret_cast(derivationPath); + const auto path = DerivationPath(s); + return new TWPrivateKey{ wallet->impl.getKeyByCurve(curve, path)}; +} + TWString *_Nonnull TWHDWalletGetExtendedPrivateKey(struct TWHDWallet *wallet, TWPurpose purpose, TWCoinType coin, TWHDVersion version) { return new std::string(wallet->impl.getExtendedPrivateKey(purpose, coin, version)); } diff --git a/tests/HDWallet/HDWalletTests.cpp b/tests/HDWallet/HDWalletTests.cpp index 2e1fc4a53a9..c646d801e91 100644 --- a/tests/HDWallet/HDWalletTests.cpp +++ b/tests/HDWallet/HDWalletTests.cpp @@ -397,4 +397,30 @@ TEST(HDWallet, Derive_XpubPub_vs_PrivPub) { } } +TEST(HDWallet, getKeyByCurve) { + const auto derivPath = "m/44'/539'/0'/0/0"; + HDWallet wallet = HDWallet(mnemonic1, ""); + { + const auto privateKey = wallet.getKeyByCurve(TWCurveSECP256k1, DerivationPath(derivPath)); + EXPECT_EQ(hex(privateKey.bytes), "4fb8657d6464adcaa086d6758d7f0b6b6fc026c98dc1671fcc6460b5a74abc62"); + } + { + const auto privateKey = wallet.getKeyByCurve(TWCurveNIST256p1, DerivationPath(derivPath)); + EXPECT_EQ(hex(privateKey.bytes), "a13df52d5a5b438bbf921bbf86276e4347fe8e2f2ed74feaaee12b77d6d26f86"); + } +} + +TEST(HDWallet, getKey) { + const auto derivPath = "m/44'/539'/0'/0/0"; + HDWallet wallet = HDWallet(mnemonic1, ""); + { + const auto privateKey = wallet.getKey(TWCoinTypeBitcoin, DerivationPath(derivPath)); + EXPECT_EQ(hex(privateKey.bytes), "4fb8657d6464adcaa086d6758d7f0b6b6fc026c98dc1671fcc6460b5a74abc62"); + } + { + const auto privateKey = wallet.getKey(TWCoinTypeNEO, DerivationPath(derivPath)); + EXPECT_EQ(hex(privateKey.bytes), "a13df52d5a5b438bbf921bbf86276e4347fe8e2f2ed74feaaee12b77d6d26f86"); + } +} + } // namespace diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp index 5ace16a9351..c826186dbfd 100644 --- a/tests/interface/TWHDWalletTests.cpp +++ b/tests/interface/TWHDWalletTests.cpp @@ -455,6 +455,19 @@ TEST(HDWallet, GetDerivedKey) { assertHexEqual(privateKeyData, "1901b5994f075af71397f65bd68a9fff8d3025d65f5a2c731cf90f5e259d6aac"); } +TEST(HDWallet, GetKeyByCurve) { + const auto derivPath = STRING("m/44'/539'/0'/0/0"); + + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), STRING("").get())); + const auto privateKey1 = WRAP(TWPrivateKey, TWHDWalletGetKeyByCurve(wallet.get(), TWCurveSECP256k1, derivPath.get())); + const auto privateKeyData1 = WRAPD(TWPrivateKeyData(privateKey1.get())); + assertHexEqual(privateKeyData1, "4fb8657d6464adcaa086d6758d7f0b6b6fc026c98dc1671fcc6460b5a74abc62"); + + const auto privateKey2 = WRAP(TWPrivateKey, TWHDWalletGetKeyByCurve(wallet.get(), TWCurveNIST256p1, derivPath.get())); + const auto privateKeyData2 = WRAPD(TWPrivateKeyData(privateKey2.get())); + assertHexEqual(privateKeyData2, "a13df52d5a5b438bbf921bbf86276e4347fe8e2f2ed74feaaee12b77d6d26f86"); +} + TEST(TWHDWallet, Derive_XpubPub_vs_PrivPub) { // Test different routes for deriving address from mnemonic, result should be the same: // - Direct: mnemonic -> seed -> privateKey -> publicKey -> address From 269399ca34ecfcd1e0ef62e8828532c2f77cc0e4 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 4 Aug 2022 14:43:30 +0900 Subject: [PATCH 047/497] [Wasm] Enable strict build mode and disable `eval` (#2472) * Enable strict build node and disable eval * enable MODULARIZE and change to O2 * adjust tests * generate WalletCore interface * update samples --- .github/workflows/wasm-ci.yml | 3 +-- codegen/lib/ts_helper.rb | 28 +++++++++++++++++++++++++- samples/node/index.js | 16 ++++++--------- samples/wasm/README.md | 2 +- wasm/.gitignore | 2 +- wasm/CMakeLists.txt | 4 ++-- wasm/index.ts | 10 +++++++-- wasm/package.json | 3 ++- wasm/tests/AES.test.ts | 13 +++++++++--- wasm/tests/AnyAddress.test.ts | 6 +++--- wasm/tests/Base32.test.ts | 17 +++++++++++----- wasm/tests/Base64.test.ts | 16 ++++++++++----- wasm/tests/Blockchain/Bitcoin.test.ts | 2 +- wasm/tests/Blockchain/Ethereum.test.ts | 19 +++++++++++------ wasm/tests/CoinType.test.ts | 7 ++++--- wasm/tests/HDWallet.test.ts | 12 ++++++++--- wasm/tests/HRP.test.ts | 6 +++--- wasm/tests/Hash.test.ts | 15 ++++++++++---- wasm/tests/HexCoding.test.ts | 6 +++--- wasm/tests/Mnemonic.test.ts | 15 ++++++++++---- wasm/tests/PBKDF2.test.ts | 6 +++--- wasm/tests/StoredKey.test.ts | 6 +++--- wasm/tests/initWasm.test.ts | 19 +++++++++++++++++ 23 files changed, 164 insertions(+), 69 deletions(-) create mode 100644 wasm/tests/initWasm.test.ts diff --git a/.github/workflows/wasm-ci.yml b/.github/workflows/wasm-ci.yml index 140f5adc850..64a2449e9ad 100644 --- a/.github/workflows/wasm-ci.yml +++ b/.github/workflows/wasm-ci.yml @@ -50,6 +50,5 @@ jobs: - name: Test run: | - npm install && npm run copy:wasm - npm run build && npm run test + npm install && npm run build-and-test working-directory: wasm diff --git a/codegen/lib/ts_helper.rb b/codegen/lib/ts_helper.rb index cd54b6b0e66..78fb1908ea3 100644 --- a/codegen/lib/ts_helper.rb +++ b/codegen/lib/ts_helper.rb @@ -48,7 +48,7 @@ def self.combine_declaration_files wasm_src = File.expand_path(File.join(File.dirname(__FILE__), '../../wasm')) header = File.expand_path('copyright_header.erb', File.join(File.dirname(__FILE__), 'templates')) - combined = File.open("#{wasm_src}/lib/wallet-core.d.ts", 'w') + combined = File.open("#{wasm_src}/wallet-core.d.ts", 'w') # append header combined.write(File.read(header)) @@ -63,5 +63,31 @@ def self.combine_declaration_files end combined.close FileUtils.remove_dir("#{wasm_src}/lib/generated", true) + + # generate WalletCore interface + + interface = "export interface WalletCore {\n" + + combined = File.open("#{wasm_src}/wallet-core.d.ts", 'r') + all_lines = combined.read + combined.close + + export_regex = /^export (class|namespace) (.*)\b/ + declare_regex = /^declare function (.+?(?=\())/ + + all_lines.scan(export_regex).each do |match| + matched = match[1] + interface += " #{matched}: typeof #{matched};\n" + end + + all_lines.scan(declare_regex).each do |match| + matched = match[0] + interface += " #{matched}: typeof #{matched};\n" + end + interface += "}\n" + + File.open("#{wasm_src}/wallet-core.d.ts", 'a') do |file| + file << interface + end end end diff --git a/samples/node/index.js b/samples/node/index.js index c97ae2fb6a0..1c666a4687d 100755 --- a/samples/node/index.js +++ b/samples/node/index.js @@ -1,17 +1,13 @@ #!/usr/bin/env node -const { TW, WalletCore } = require('@trustwallet/wallet-core'); - -const sleep = async (milliseconds) => { - await new Promise(resolve => setTimeout(resolve, milliseconds)); -} +const { initWasm, TW } = require('@trustwallet/wallet-core'); (async function() { - await sleep(1000); - const { CoinType, HexCoding } = WalletCore; - + const start = new Date().getTime(); + console.log(`Initializing...`); + const { CoinType, HexCoding } = await initWasm(); + console.log(`Done in ${new Date().getTime() - start} ms`); console.log(HexCoding.decode("0xce2fd7544e0b2cc94692d4a704debef7bcb61328")); console.log(CoinType.ethereum.value); - console.log(TW); + console.log(TW.Ethereum); })(); - diff --git a/samples/wasm/README.md b/samples/wasm/README.md index 8b07630ba64..010195fdb38 100644 --- a/samples/wasm/README.md +++ b/samples/wasm/README.md @@ -38,5 +38,5 @@ npm run codegen:js-browser For modern javaScript sample, please check out: -- React: https://github.com/robot-ux/wallet-core-example +- React: https://github.com/hewigovens/wallet-core-react - Flutter: https://github.com/iampawan/Wallet-Core-Web/tree/dev diff --git a/wasm/.gitignore b/wasm/.gitignore index 011b114988d..c1327fb6af0 100644 --- a/wasm/.gitignore +++ b/wasm/.gitignore @@ -1,5 +1,5 @@ dist/ generated/ +wallet-core.d.ts lib/wallet-core.js -lib/wallet-core.d.ts lib/wallet-core.wasm diff --git a/wasm/CMakeLists.txt b/wasm/CMakeLists.txt index 3aeeddb5010..5a24ab5e4dc 100644 --- a/wasm/CMakeLists.txt +++ b/wasm/CMakeLists.txt @@ -21,6 +21,6 @@ set_target_properties(${TARGET_NAME} ) set_target_properties(${TARGET_NAME} PROPERTIES - COMPILE_FLAGS "-O3 -s USE_BOOST_HEADERS=1" - LINK_FLAGS "--bind --no-entry --closure=1 -O3 -s ALLOW_MEMORY_GROWTH=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1" + COMPILE_FLAGS "-O2 -sSTRICT -sUSE_BOOST_HEADERS=1" + LINK_FLAGS "--bind --no-entry --closure 1 -O2 -sSTRICT -sASSERTIONS -sMODULARIZE=1 -sALLOW_MEMORY_GROWTH=1 -sDYNAMIC_EXECUTION=0" ) diff --git a/wasm/index.ts b/wasm/index.ts index 8a5a24c3ad6..550165e7ca0 100644 --- a/wasm/index.ts +++ b/wasm/index.ts @@ -4,5 +4,11 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -export { TW } from "./generated/core_proto"; -export * as WalletCore from "./lib/wallet-core"; +import * as Loader from "./lib/wallet-core"; +import { TW } from "./generated/core_proto"; +import { WalletCore } from "./wallet-core"; + +declare function load(): Promise; + +export const initWasm: typeof load = Loader; +export { TW, WalletCore }; diff --git a/wasm/package.json b/wasm/package.json index c6642b071db..5397d3b48dd 100644 --- a/wasm/package.json +++ b/wasm/package.json @@ -11,7 +11,8 @@ "codegen:js-browser": "pbjs -t static-module '../src/proto/*.proto' -w closure --no-delimited --force-long -o ../samples/wasm/core_proto.js", "codegen:ts": "pbts -o generated/core_proto.d.ts generated/core_proto.js", "clean": "rm -rf dist generated && mkdir -p dist/generated generated", - "build": "npm run clean && npm run generate && cp -R generated lib dist && tsc", + "build": "npm run clean && npm run generate && cp -R generated lib dist && tsc && cp wallet-core.d.ts dist", + "build-and-test": "npm run copy:wasm && npm run build && npm test", "copy:wasm": "mkdir -p lib && cp ../wasm-build/wasm/wallet-core.* lib", "copy:wasm-sample": "cp ../wasm-build/wasm/wallet-core.* ../samples/wasm/" }, diff --git a/wasm/tests/AES.test.ts b/wasm/tests/AES.test.ts index 4d91a2c5ec0..1b176113c3f 100644 --- a/wasm/tests/AES.test.ts +++ b/wasm/tests/AES.test.ts @@ -7,11 +7,18 @@ import "mocha"; import { assert } from "chai"; import { Buffer } from "buffer"; -import { WalletCore } from "../dist"; +import { initWasm, WalletCore } from "../dist"; describe("AES", () => { + + let core: WalletCore; + + before(async () => { + core = await initWasm(); + }); + it("test decrypting", () => { - const { AES, HexCoding, AESPaddingMode } = WalletCore; + const { AES, HexCoding, AESPaddingMode } = core; const key = HexCoding.decode( "5caa3a74154cee16bd1b570a1330be46e086474ac2f4720530662ef1a469662c" @@ -29,7 +36,7 @@ describe("AES", () => { }); it("test encrypting", () => { - const { AES, HexCoding, AESPaddingMode } = WalletCore; + const { AES, HexCoding, AESPaddingMode } = core; const key = HexCoding.decode( "bbc82a01ebdb14698faee4a9e5038de72c995a9f6bcdb21903d62408b0c5ca96" diff --git a/wasm/tests/AnyAddress.test.ts b/wasm/tests/AnyAddress.test.ts index 80c89098ebf..4429091bf7e 100644 --- a/wasm/tests/AnyAddress.test.ts +++ b/wasm/tests/AnyAddress.test.ts @@ -6,11 +6,11 @@ import "mocha"; import { assert } from "chai"; -import { WalletCore } from "../dist"; +import { initWasm } from "../dist"; describe("AnyAddress", () => { - it("test validating Solana address", () => { - const { AnyAddress, HexCoding, CoinType } = WalletCore; + it("test validating Solana address", async () => { + const { AnyAddress, HexCoding, CoinType } = await initWasm(); var address = AnyAddress.createWithString( "7v91N7iZ9mNicL8WfG6cgSCKyRXydQjLh6UYBWwm6y1Q", diff --git a/wasm/tests/Base32.test.ts b/wasm/tests/Base32.test.ts index ada5219473f..8abe7caf6f2 100644 --- a/wasm/tests/Base32.test.ts +++ b/wasm/tests/Base32.test.ts @@ -6,11 +6,18 @@ import { assert } from "chai"; import { Buffer } from "buffer"; -import { WalletCore } from "../dist"; +import { initWasm, WalletCore } from "../dist"; describe("Base32", () => { + + let core: WalletCore; + + before(async () => { + core = await initWasm(); + }); + it("test decrypting", () => { - const { Base32 } = WalletCore; + const { Base32 } = core; const decoded = Base32.decode("JBSWY3DPK5XXE3DE"); @@ -18,7 +25,7 @@ describe("Base32", () => { }); it("test decrypting with alphabet", () => { - const { Base32 } = WalletCore; + const { Base32 } = core; const decoded = Base32.decodeWithAlphabet( "g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i", @@ -32,7 +39,7 @@ describe("Base32", () => { }); it("test encrypting", () => { - const { Base32 } = WalletCore; + const { Base32 } = core; const encoded = Base32.encode(Buffer.from("HelloWorld")); @@ -40,7 +47,7 @@ describe("Base32", () => { }); it("test encrypting with alphabet", () => { - const { Base32 } = WalletCore; + const { Base32 } = core; const encoded = Base32.encodeWithAlphabet( Buffer.from("7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"), diff --git a/wasm/tests/Base64.test.ts b/wasm/tests/Base64.test.ts index ea5448a89fb..12d9dc11388 100644 --- a/wasm/tests/Base64.test.ts +++ b/wasm/tests/Base64.test.ts @@ -6,11 +6,17 @@ import { assert } from "chai"; import { Buffer } from "buffer"; -import { WalletCore } from "../dist"; +import { initWasm, WalletCore } from "../dist"; describe("Base64", () => { + let core: WalletCore; + + before(async () => { + core = await initWasm(); + }); + it("test decoding", () => { - const { Base64 } = WalletCore; + const { Base64 } = core; const decoded = Base64.decode("SGVsbG9Xb3JsZA=="); @@ -18,7 +24,7 @@ describe("Base64", () => { }); it("test encoding", () => { - const { Base64 } = WalletCore; + const { Base64 } = core; const encoded = Base64.encode(Buffer.from("HelloWorld")); @@ -26,7 +32,7 @@ describe("Base64", () => { }); it("test encoding (URL-safe)", () => { - const { Base64 } = WalletCore; + const { Base64 } = core; const encoded = Base64.encodeUrl(Buffer.from("==?=")); @@ -34,7 +40,7 @@ describe("Base64", () => { }); it("test decoding (URL-safe)", () => { - const { Base64 } = WalletCore; + const { Base64 } = core; const decoded = Base64.decodeUrl("PT0_PQ=="); assert.equal(Buffer.from(decoded).toString(), "==?="); diff --git a/wasm/tests/Blockchain/Bitcoin.test.ts b/wasm/tests/Blockchain/Bitcoin.test.ts index cf518fdb8fa..4cad6e61e5d 100644 --- a/wasm/tests/Blockchain/Bitcoin.test.ts +++ b/wasm/tests/Blockchain/Bitcoin.test.ts @@ -6,7 +6,7 @@ import "mocha"; import { assert } from "chai"; -import { TW, WalletCore } from "../../dist"; +import { TW } from "../../dist"; describe("Bitcoin", () => { it("test Bitcoin SigningInput / SigningOutput", () => { diff --git a/wasm/tests/Blockchain/Ethereum.test.ts b/wasm/tests/Blockchain/Ethereum.test.ts index 33be2e86b32..5b6e17b0005 100644 --- a/wasm/tests/Blockchain/Ethereum.test.ts +++ b/wasm/tests/Blockchain/Ethereum.test.ts @@ -7,11 +7,18 @@ import "mocha"; import { assert } from "chai"; import { Buffer } from "buffer"; -import { TW, WalletCore } from "../../dist"; +import { TW, initWasm, WalletCore } from "../../dist"; describe("Ethereum", () => { + + let core: WalletCore; + + before(async () => { + core = await initWasm(); + }); + it("test address", () => { - const { PrivateKey, HexCoding, AnyAddress, CoinType, Curve } = WalletCore; + const { PrivateKey, HexCoding, AnyAddress, CoinType, Curve } = core; const data = HexCoding.decode("727f677b390c151caf9c206fd77f77918f56904b5504243db9b21e51182c4c06"); @@ -35,7 +42,7 @@ describe("Ethereum", () => { }); it("test signing transfer tx", () => { - const { HexCoding, AnySigner, CoinType } = WalletCore; + const { HexCoding, AnySigner, CoinType } = core; const input = TW.Ethereum.Proto.SigningInput.create({ toAddress: "0x3535353535353535353535353535353535353535", chainId: Buffer.from("01", "hex"), @@ -67,7 +74,7 @@ describe("Ethereum", () => { }); it("test signing eip1559 erc20 transfer tx", () => { - const { HexCoding, AnySigner, CoinType } = WalletCore; + const { HexCoding, AnySigner, CoinType } = core; const input = TW.Ethereum.Proto.SigningInput.create({ toAddress: "0x6b175474e89094c44da98b954eedeac495271d0f", @@ -98,7 +105,7 @@ describe("Ethereum", () => { }); it("test signing personal message", () => { - const { EthereumAbi, HexCoding, Hash, PrivateKey, Curve } = WalletCore; + const { EthereumAbi, HexCoding, Hash, PrivateKey, Curve } = core; const message = Buffer.from("Some data"); const prefix = Buffer.from("\x19Ethereum Signed Message:\n" + message.length); const hash = Hash.keccak256(Buffer.concat([prefix, message])); @@ -115,7 +122,7 @@ describe("Ethereum", () => { }); it("test signing EIP712 message", () => { - const { EthereumAbi, HexCoding, Hash, PrivateKey, Curve } = WalletCore; + const { EthereumAbi, HexCoding, Hash, PrivateKey, Curve } = core; const key = PrivateKey.createWithData(Hash.keccak256(Buffer.from("cow"))); const message = { diff --git a/wasm/tests/CoinType.test.ts b/wasm/tests/CoinType.test.ts index dd517715e8e..4c98365aa1b 100644 --- a/wasm/tests/CoinType.test.ts +++ b/wasm/tests/CoinType.test.ts @@ -6,11 +6,12 @@ import "mocha"; import { assert } from "chai"; -import { WalletCore } from "../dist"; +import { initWasm } from "../dist"; describe("CoinType", () => { - it("test raw value", () => { - const { CoinType } = WalletCore; + + it("test raw value", async () => { + const { CoinType } = await initWasm();; assert.equal(CoinType.bitcoin.value, 0); assert.equal(CoinType.litecoin.value, 2); diff --git a/wasm/tests/HDWallet.test.ts b/wasm/tests/HDWallet.test.ts index 56a612bd510..0270e539b5c 100644 --- a/wasm/tests/HDWallet.test.ts +++ b/wasm/tests/HDWallet.test.ts @@ -6,13 +6,19 @@ import "mocha"; import { assert } from "chai"; -import { WalletCore } from "../dist"; +import { initWasm, WalletCore } from "../dist"; import { Buffer } from "buffer"; describe("HDWallet", () => { + let core: WalletCore; + + before(async () => { + core = await initWasm(); + }); + it("test creating 24 words", () => { - const { HDWallet, Mnemonic } = WalletCore; + const { HDWallet, Mnemonic } = core; var wallet = HDWallet.create(256, "password"); const mnemonic = wallet.mnemonic(); @@ -24,7 +30,7 @@ describe("HDWallet", () => { }); it("test deriving Ethereum address", () => { - const { HDWallet, CoinType } = WalletCore; + const { HDWallet, CoinType } = core; var wallet = HDWallet.createWithMnemonic("ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal", "TREZOR"); const address = wallet.getAddressForCoin(CoinType.ethereum); diff --git a/wasm/tests/HRP.test.ts b/wasm/tests/HRP.test.ts index 5b94f747062..cd27ba37dcf 100644 --- a/wasm/tests/HRP.test.ts +++ b/wasm/tests/HRP.test.ts @@ -6,11 +6,11 @@ import "mocha"; import { assert } from "chai"; -import { WalletCore } from "../dist"; +import { initWasm } from "../dist"; describe("HRP", () => { - it("test string value", () => { - const { HRP, describeHRP } = WalletCore; + it("test string value", async () => { + const { HRP, describeHRP } = await initWasm(); assert.equal(describeHRP(HRP.bitcoin), "bc"); assert.equal(describeHRP(HRP.binance), "bnb"); diff --git a/wasm/tests/Hash.test.ts b/wasm/tests/Hash.test.ts index 33b2c723bb0..d882c77848b 100644 --- a/wasm/tests/Hash.test.ts +++ b/wasm/tests/Hash.test.ts @@ -7,11 +7,18 @@ import "mocha"; import { assert } from "chai"; import { Buffer } from "buffer"; -import { WalletCore } from "../dist"; +import { initWasm, WalletCore } from "../dist"; describe("Hash", () => { + + let core: WalletCore; + + before(async () => { + core = await initWasm(); + }); + it("test keccak256", () => { - const { Hash, HexCoding } = WalletCore; + const { Hash, HexCoding } = core; const sha3Hash = Hash.keccak256(Buffer.from("Test keccak-256")); @@ -22,7 +29,7 @@ describe("Hash", () => { }); it("test sha256", () => { - const { Hash, HexCoding } = WalletCore; + const { Hash, HexCoding } = core; const sha256Hash = Hash.sha256(Buffer.from("Test hash")); assert.equal( @@ -32,7 +39,7 @@ describe("Hash", () => { }); it("test sha512_256", () => { - const { Hash, HexCoding } = WalletCore; + const { Hash, HexCoding } = core; const hash = Hash.sha512_256(Buffer.from("hello")); assert.equal( diff --git a/wasm/tests/HexCoding.test.ts b/wasm/tests/HexCoding.test.ts index a3c8879e495..4b131831379 100644 --- a/wasm/tests/HexCoding.test.ts +++ b/wasm/tests/HexCoding.test.ts @@ -6,11 +6,11 @@ import "mocha"; import { assert } from "chai"; -import { WalletCore } from "../dist"; +import { initWasm } from "../dist"; describe("HexCoding", () => { - it("test encoding / decoding hex string", () => { - const { HexCoding } = WalletCore; + it("test encoding / decoding hex string", async () => { + const { HexCoding } = await initWasm(); const expected = new Uint8Array([0x52, 0x8]); const decoded = HexCoding.decode("0x5208"); diff --git a/wasm/tests/Mnemonic.test.ts b/wasm/tests/Mnemonic.test.ts index c178e6ebf83..9d0282eeebf 100644 --- a/wasm/tests/Mnemonic.test.ts +++ b/wasm/tests/Mnemonic.test.ts @@ -6,11 +6,18 @@ import "mocha"; import { assert } from "chai"; -import { WalletCore } from "../dist"; +import { initWasm, WalletCore } from "../dist"; describe("Mnemonic", () => { + + let core: WalletCore; + + before(async () => { + core = await initWasm(); + }); + it("test isValid", () => { - const { Mnemonic } = WalletCore; + const { Mnemonic } = core; assert.isTrue( Mnemonic.isValid( @@ -25,7 +32,7 @@ describe("Mnemonic", () => { }); it("test isValidWord", () => { - const { Mnemonic } = WalletCore; + const { Mnemonic } = core; assert.isTrue(Mnemonic.isValidWord("credit")); @@ -35,7 +42,7 @@ describe("Mnemonic", () => { }); it("test suggest", () => { - const { Mnemonic } = WalletCore; + const { Mnemonic } = core; assert.equal(Mnemonic.suggest("air"), "air airport"); assert.equal(Mnemonic.suggest("rob"), "robot robust"); diff --git a/wasm/tests/PBKDF2.test.ts b/wasm/tests/PBKDF2.test.ts index ee2199416fa..06024ee559d 100644 --- a/wasm/tests/PBKDF2.test.ts +++ b/wasm/tests/PBKDF2.test.ts @@ -7,11 +7,11 @@ import "mocha"; import { assert } from "chai"; import { Buffer } from "buffer"; -import { WalletCore } from "../dist"; +import { initWasm } from "../dist"; describe("PBKDF2", () => { - it("test sha256 hmac", () => { - const { PBKDF2, HexCoding } = WalletCore; + it("test sha256 hmac", async () => { + const { PBKDF2, HexCoding } = await initWasm(); const password = Buffer.from("password"); const salt = Buffer.from("salt"); diff --git a/wasm/tests/StoredKey.test.ts b/wasm/tests/StoredKey.test.ts index 2b0b6aa4950..d085dff9dc1 100644 --- a/wasm/tests/StoredKey.test.ts +++ b/wasm/tests/StoredKey.test.ts @@ -6,12 +6,12 @@ import "mocha"; import { assert } from "chai"; -import { WalletCore } from "../dist"; +import { initWasm } from "../dist"; import { Buffer } from "buffer"; describe("StoredKey", () => { - it("test importing mnemonic", () => { - const { StoredKey, CoinType } = WalletCore; + it("test importing mnemonic", async () => { + const { StoredKey, CoinType } = await initWasm(); const mnemonic = "team engine square letter hero song dizzy scrub tornado fabric divert saddle"; const password = Buffer.from("password"); diff --git a/wasm/tests/initWasm.test.ts b/wasm/tests/initWasm.test.ts new file mode 100644 index 00000000000..0fb9dd84fef --- /dev/null +++ b/wasm/tests/initWasm.test.ts @@ -0,0 +1,19 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import "mocha"; +import { assert } from "chai"; +import { initWasm } from "../dist"; + +describe("Module", () => { + it("load test", (done) => { + initWasm().then((WalletCore) => { + assert.isDefined(WalletCore); + assert.isNotNull(WalletCore); + done(); + }); + }).timeout(5000); +}); From a12f0e2dfbde1adcdcd882d8c87151e04aacc55e Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 4 Aug 2022 08:27:59 +0200 Subject: [PATCH 048/497] [Improvements]: speed up build time (#2426) * feat(clang_tidy): execute clang_tidy per target - try to build with ninja * feat: add dummy clang-tidy files to ignore generated code * fix(linux_ci): execute tests after build * feat(unity_build): activate unity build for TrustWalletCore Target * feat(unity_build): activate unity build for unit tests * feat(unity_build): fix ios build * feat(unity_build): make unity build a CMake Option * feat(linux_ci): enable clang tidy by default * fix: review comments * fix: review comments (namespace) * fix: review comments (redundant namespace) * fix: review comments (style) * use ninja -C + revert some style changes Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- .github/workflows/linux-ci.yml | 12 +-- .gitignore | 2 +- CMakeLists.txt | 16 ++- cmake/CompilerWarnings.cmake | 1 + cmake/StandardSettings.cmake | 5 + cmake/StaticAnalyzers.cmake | 18 ++-- src/Aeternity/Address.cpp | 6 +- src/Aeternity/Entry.cpp | 4 +- src/Aeternity/Signer.cpp | 11 ++- src/Aeternity/Signer.h | 6 +- src/Aeternity/Transaction.cpp | 5 +- src/Aion/Address.cpp | 4 +- src/Aion/Entry.cpp | 5 +- src/Aion/Signer.cpp | 5 +- src/Aion/Transaction.cpp | 7 +- src/Cosmos/Entry.cpp | 7 +- src/Cosmos/JsonSerialization.cpp | 9 +- src/Cosmos/JsonSerialization.h | 24 ++--- src/Cosmos/Protobuf/.clang-tidy | 6 ++ src/Cosmos/ProtobufSerialization.cpp | 13 +-- src/Cosmos/ProtobufSerialization.h | 6 +- src/Cosmos/Signer.cpp | 7 +- src/Decred/Address.cpp | 8 +- src/EOS/Action.h | 2 - src/Elrond/Address.cpp | 4 +- src/Elrond/Entry.cpp | 4 +- src/Elrond/Serialization.cpp | 20 ++-- src/Elrond/Serialization.h | 6 +- src/Ethereum/ABI/Array.cpp | 24 +++-- src/FIO/Address.cpp | 7 +- src/Generated/.clang-tidy | 6 ++ src/Harmony/Address.cpp | 3 +- src/Harmony/Entry.cpp | 5 +- src/Harmony/Signer.cpp | 50 +++++----- src/Icon/Address.cpp | 7 +- src/IoTeX/Address.cpp | 4 +- src/IoTeX/Entry.cpp | 5 +- src/Keystore/ScryptParameters.cpp | 28 +++--- src/Keystore/StoredKey.cpp | 48 ++++----- src/NEAR/Address.cpp | 11 ++- src/NEAR/Entry.cpp | 5 +- src/NEO/Address.cpp | 13 ++- src/NULS/Address.cpp | 13 +-- src/NULS/BinaryCoding.h | 15 +-- src/NULS/Entry.cpp | 5 +- src/NULS/Signer.cpp | 24 +++-- src/Nebulas/Address.cpp | 8 +- src/Nebulas/Entry.cpp | 4 +- src/Nebulas/Signer.cpp | 28 +++--- src/Nebulas/Transaction.cpp | 94 ++++++++++-------- src/Nimiq/Address.cpp | 4 + src/Oasis/Address.cpp | 16 +-- src/Oasis/Entry.cpp | 5 +- src/Oasis/Signer.cpp | 9 +- src/Oasis/Transaction.cpp | 9 +- src/Ontology/Address.cpp | 5 +- src/Ripple/Address.cpp | 4 + src/Ronin/Address.cpp | 9 +- src/Ronin/Entry.cpp | 5 +- src/Solana/Address.cpp | 7 +- src/Solana/Entry.cpp | 5 +- src/Stellar/Address.cpp | 6 +- src/Stellar/Signer.cpp | 118 +++++++++++------------ src/THORChain/Entry.cpp | 5 +- src/THORChain/Signer.cpp | 6 +- src/Tezos/Forging.cpp | 6 +- src/Tezos/Signer.cpp | 9 +- src/Tron/Entry.cpp | 4 +- src/VeChain/Signer.cpp | 5 +- src/Waves/Entry.cpp | 4 + src/Waves/Signer.cpp | 9 +- src/Waves/Transaction.cpp | 72 +++++++------- src/Zcash/Transaction.cpp | 4 +- src/Zilliqa/Entry.cpp | 5 +- src/interface/TWGroestlcoinAddress.cpp | 22 ++--- src/interface/TWSolanaAddress.cpp | 9 +- src/proto/.clang-tidy | 6 ++ tests/Aeternity/TransactionTests.cpp | 10 +- tests/Aion/AddressTests.cpp | 5 +- tests/Algorand/AddressTests.cpp | 9 +- tests/Algorand/SignerTests.cpp | 34 +++---- tests/Algorand/TWAnySignerTests.cpp | 9 +- tests/BinanceSmartChain/SignerTests.cpp | 4 +- tests/Bitcoin/BitcoinAddressTests.cpp | 24 +++-- tests/Bitcoin/TWBitcoinScriptTests.cpp | 16 ++- tests/BitcoinCash/TWBitcoinCashTests.cpp | 9 +- tests/BitcoinGold/TWBitcoinGoldTests.cpp | 20 ++-- tests/CMakeLists.txt | 3 + tests/Cardano/SigningTests.cpp | 76 +++++++-------- tests/Decred/SignerTests.cpp | 7 +- tests/EOS/AddressTests.cpp | 41 ++++---- tests/Elrond/AddressTests.cpp | 12 ++- tests/Elrond/SerializationTests.cpp | 9 +- tests/Elrond/SignerTests.cpp | 88 +++++++---------- tests/Elrond/TWAnySignerTests.cpp | 12 ++- tests/Ethereum/AbiStructTests.cpp | 80 +++++++-------- tests/Ethereum/AddressTests.cpp | 20 ++-- tests/FIO/TransactionBuilderTests.cpp | 52 +++++----- tests/Filecoin/AddressTests.cpp | 4 +- tests/Filecoin/TWAnySignerTests.cpp | 5 +- tests/Harmony/AddressTests.cpp | 5 +- tests/Harmony/TWAnySignerTests.cpp | 7 +- tests/Icon/AddressTests.cpp | 7 +- tests/Icon/TWAnySignerTests.cpp | 11 ++- tests/Litecoin/LitecoinAddressTests.cpp | 7 +- tests/Litecoin/TWLitecoinTests.cpp | 9 +- tests/NEO/AddressTests.cpp | 7 +- tests/Nano/AddressTests.cpp | 7 +- tests/Nano/SignerTests.cpp | 7 +- tests/Nano/TWAnySignerTests.cpp | 5 +- tests/Nimiq/AddressTests.cpp | 14 +-- tests/Oasis/AddressTests.cpp | 17 ++-- tests/Oasis/SignerTests.cpp | 11 ++- tests/Ontology/TWAnySignerTests.cpp | 5 +- tests/Osmosis/AddressTests.cpp | 7 +- tests/Osmosis/SignerTests.cpp | 7 +- tests/Osmosis/TWAnySignerTests.cpp | 9 +- tests/PrivateKeyTests.cpp | 70 ++++++-------- tests/Ripple/TWAnySignerTests.cpp | 5 +- tests/Ronin/TWAnySignerTests.cpp | 11 ++- tests/Solana/AddressTests.cpp | 19 ++-- tests/Solana/ProgramTests.cpp | 14 +-- tests/Stellar/AddressTests.cpp | 7 +- tests/Stellar/TWAnySignerTests.cpp | 7 +- tests/THORChain/TWSwapTests.cpp | 27 +++--- tests/Terra/SignerTests.cpp | 2 +- tests/Terra/SignerTestsClassic.cpp | 2 +- tests/Tezos/AddressTests.cpp | 28 +++--- tests/Tezos/SignerTests.cpp | 13 ++- tests/Theta/TWAnySignerTests.cpp | 9 +- tests/Waves/AddressTests.cpp | 7 +- tests/Waves/LeaseTests.cpp | 109 ++++++++++----------- 132 files changed, 1147 insertions(+), 872 deletions(-) create mode 100644 src/Cosmos/Protobuf/.clang-tidy create mode 100644 src/Generated/.clang-tidy create mode 100644 src/proto/.clang-tidy diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 6b493e72707..e4578e07c54 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -35,22 +35,14 @@ jobs: CC: /usr/bin/clang CXX: /usr/bin/clang++ - name: CMake (coverage/clang-tidy/clang-asan) - if: github.ref == 'refs/heads/master' run: | - cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DTW_CODE_COVERAGE=ON -DTW_ENABLE_CLANG_TIDY=ON -DTW_CLANG_ASAN=ON - env: - CC: /usr/bin/clang - CXX: /usr/bin/clang++ - - name: CMake (coverage) - if: github.ref != 'refs/heads/master' - run: | - cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DTW_CODE_COVERAGE=ON + cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DTW_UNITY_BUILD=ON -DTW_CODE_COVERAGE=ON -DTW_ENABLE_CLANG_TIDY=ON -DTW_CLANG_ASAN=ON -GNinja env: CC: /usr/bin/clang CXX: /usr/bin/clang++ - name: Build and test run: | - make -Cbuild -j12 tests TrezorCryptoTests + ninja -Cbuild tests TrezorCryptoTests build/trezor-crypto/crypto/tests/TrezorCryptoTests build/tests/tests tests --gtest_output=xml env: diff --git a/.gitignore b/.gitignore index 412379628d7..707a2517dee 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,7 @@ jni/java/wallet/core/jni jni/java/wallet/core/proto swift/Sources/Generated swift/wallet-core/ -src/Generated +src/Generated/*.cpp include/TrustWalletCore/TWHRP.h include/TrustWalletCore/TW*Proto.h include/TrustWalletCore/TWDerivation.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 44193b00e9b..3b061e1c15b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,10 +84,24 @@ endif () if (TW_BUILD_EXAMPLES) add_subdirectory(walletconsole/lib) add_subdirectory(walletconsole) -endif() +endif () if (TW_ENABLE_PVS_STUDIO) tw_add_pvs_studio_target(TrustWalletCore) +endif () + +if (TW_ENABLE_CLANG_TIDY) + tw_add_clang_tidy_target(TrustWalletCore) +endif () + +if (NOT ANDROID AND TW_UNITY_BUILD) + set_target_properties(TrustWalletCore PROPERTIES UNITY_BUILD ON) + + file(GLOB_RECURSE PROTOBUF_SOURCE_FILES CONFIGURE_DEPENDS src/Cosmos/Protobuf/*.pb.cc src/proto/*.pb.cc) + foreach(file ${PROTOBUF_SOURCE_FILES}) + set_property(SOURCE ${file} PROPERTY SKIP_UNITY_BUILD_INCLUSION ON) + endforeach() + message(STATUS "Unity build activated") endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/swift/cpp.xcconfig.in ${CMAKE_CURRENT_SOURCE_DIR}/swift/cpp.xcconfig @ONLY) diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake index a6e704a52b9..16fff2a832b 100644 --- a/cmake/CompilerWarnings.cmake +++ b/cmake/CompilerWarnings.cmake @@ -51,6 +51,7 @@ target_compile_options( -Wfatal-errors # short error report -Wshadow # warn the user if a variable declaration shadows one from a -Wshorten-64-to-32 + -Wno-nullability-completeness # parent context -Wnon-virtual-dtor # warn the user if a class with virtual functions has a # non-virtual destructor. This helps catch hard to track down memory errors diff --git a/cmake/StandardSettings.cmake b/cmake/StandardSettings.cmake index 6f20d870f1c..60dff027c54 100644 --- a/cmake/StandardSettings.cmake +++ b/cmake/StandardSettings.cmake @@ -12,6 +12,11 @@ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14" CACHE STRING "Minimum OS X deployment ve option(TW_IDE_CLION "Enable if your IDE is CLion" OFF) option(TW_IDE_VSCODE "Enable if your IDE is VSCode" OFF) +# +# Build Settings +# +option(TW_UNITY_BUILD "Enable Unity build for TrustWalletCore and unit tests." OFF) + # # Static analyzers # diff --git a/cmake/StaticAnalyzers.cmake b/cmake/StaticAnalyzers.cmake index a6e32b5b406..bb06683916e 100644 --- a/cmake/StaticAnalyzers.cmake +++ b/cmake/StaticAnalyzers.cmake @@ -1,11 +1,15 @@ if (TW_ENABLE_CLANG_TIDY) - find_program(CLANGTIDY clang-tidy) - if (CLANGTIDY) - set(CMAKE_CXX_CLANG_TIDY ${CLANGTIDY} -extra-arg=-Wno-unknown-warning-option) - message("Clang-Tidy finished setting up.") - else () - message(SEND_ERROR "Clang-Tidy requested but executable not found.") - endif () + macro(tw_add_clang_tidy_target target) + find_program(CLANGTIDY clang-tidy) + if (CLANGTIDY) + set_property( + TARGET ${target} + PROPERTY CXX_CLANG_TIDY clang-tidy;-extra-arg=-Wno-unknown-warning-option) + message("Clang-Tidy finished setting up.") + else () + message(SEND_ERROR "Clang-Tidy requested but executable not found.") + endif () + endmacro() endif () if (TW_ENABLE_PVS_STUDIO) diff --git a/src/Aeternity/Address.cpp b/src/Aeternity/Address.cpp index 101ba527854..af8e7e1f8d9 100644 --- a/src/Aeternity/Address.cpp +++ b/src/Aeternity/Address.cpp @@ -10,7 +10,7 @@ #include #include -using namespace TW::Aeternity; +namespace TW::Aeternity { /// Determines whether a string makes a valid address. bool Address::isValid(const std::string& string) { @@ -25,7 +25,7 @@ bool Address::isValid(const std::string& string) { } /// Initializes an address from a public key. -Address::Address(const PublicKey &publicKey) { +Address::Address(const PublicKey& publicKey) { if (publicKey.type != TWPublicKeyTypeED25519) { throw std::invalid_argument("Invalid public key type"); } @@ -56,3 +56,5 @@ bool Address::checkPayload(const std::string& payload) { unsigned long base58 = Base58::bitcoin.decodeCheck(payload).size(); return base58 == size; } + +} // namespace TW::Aeternity diff --git a/src/Aeternity/Entry.cpp b/src/Aeternity/Entry.cpp index 896b784716e..cab15ca9d26 100644 --- a/src/Aeternity/Entry.cpp +++ b/src/Aeternity/Entry.cpp @@ -9,9 +9,9 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Aeternity; using namespace std; +namespace TW::Aeternity { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -25,3 +25,5 @@ string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& p void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Aeternity diff --git a/src/Aeternity/Signer.cpp b/src/Aeternity/Signer.cpp index 7c9adf1fafa..2378aef1b63 100644 --- a/src/Aeternity/Signer.cpp +++ b/src/Aeternity/Signer.cpp @@ -14,9 +14,10 @@ #include using namespace TW; -using namespace TW::Aeternity; -Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { +namespace TW::Aeternity { + +Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto privateKey = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); std::string sender_id = input.from_address(); std::string recipient_id = input.to_address(); @@ -29,7 +30,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { /// implementation copied from /// https://github.com/aeternity/aepp-sdk-go/blob/07aa8a77e5/aeternity/helpers.go#L367 -Proto::SigningOutput Signer::sign(const TW::PrivateKey &privateKey, Transaction &transaction) { +Proto::SigningOutput Signer::sign(const TW::PrivateKey& privateKey, Transaction& transaction) { auto txRlp = transaction.encode(); /// append networkId and txRaw @@ -86,4 +87,6 @@ std::string Signer::encodeBase64WithChecksum(const std::string& prefix, const TW append(data, checksumPart); return prefix + TW::Base64::encode(data); -} \ No newline at end of file +} + +} // namespace TW::Aeternity diff --git a/src/Aeternity/Signer.h b/src/Aeternity/Signer.h index b1cb5aaa7bf..d356375055a 100644 --- a/src/Aeternity/Signer.h +++ b/src/Aeternity/Signer.h @@ -13,14 +13,14 @@ namespace TW::Aeternity { class Signer { - public: +public: /// Signs a Proto::SigningInput transaction static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept; /// Signs the given transaction. - static Proto::SigningOutput sign(const PrivateKey &privateKey, Transaction &transaction); + static Proto::SigningOutput sign(const PrivateKey& privateKey, Transaction& transaction); - private: +private: static const uint8_t checkSumSize = 4; static Data buildRlpTxRaw(Data& txRaw, Data& sigRaw); diff --git a/src/Aeternity/Transaction.cpp b/src/Aeternity/Transaction.cpp index c06d74d7efe..7ed0515b97b 100644 --- a/src/Aeternity/Transaction.cpp +++ b/src/Aeternity/Transaction.cpp @@ -10,8 +10,7 @@ #include #include -using namespace TW; -using namespace TW::Aeternity; +namespace TW::Aeternity { /// RLP returns a byte serialized representation Data Transaction::encode() { @@ -46,3 +45,5 @@ TW::Data Transaction::encodeSafeZero(uint256_t value) { } return Ethereum::RLP::encode(value); } + +} // namespace TW::Aeternity diff --git a/src/Aion/Address.cpp b/src/Aion/Address.cpp index 58872b004d1..e781c33b8fa 100644 --- a/src/Aion/Address.cpp +++ b/src/Aion/Address.cpp @@ -8,7 +8,7 @@ #include "../Hash.h" #include "../HexCoding.h" -using namespace TW::Aion; +namespace TW::Aion { bool Address::isValid(const std::string& string) { const auto data = parse_hex(string); @@ -40,3 +40,5 @@ Address::Address(const PublicKey& publicKey) { std::string Address::string() const { return "0x" + hex(bytes); } + +} // namespace TW::Aion diff --git a/src/Aion/Entry.cpp b/src/Aion/Entry.cpp index e9f79e1e333..f32ef1e3491 100644 --- a/src/Aion/Entry.cpp +++ b/src/Aion/Entry.cpp @@ -9,10 +9,11 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Aion; using namespace TW; using namespace std; +namespace TW::Aion { + // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -31,3 +32,5 @@ Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& a void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Aion diff --git a/src/Aion/Signer.cpp b/src/Aion/Signer.cpp index a4a3a4adf14..fe1048b70e5 100644 --- a/src/Aion/Signer.cpp +++ b/src/Aion/Signer.cpp @@ -11,7 +11,8 @@ #include using namespace TW; -using namespace TW::Aion; + +namespace TW::Aion { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { using boost::multiprecision::uint128_t; @@ -46,3 +47,5 @@ void Signer::sign(const PrivateKey& privateKey, Transaction& transaction) noexce transaction.signature = result; } + +} // namespace TW::Aion diff --git a/src/Aion/Transaction.cpp b/src/Aion/Transaction.cpp index 017dbe96896..327441c1eb3 100644 --- a/src/Aion/Transaction.cpp +++ b/src/Aion/Transaction.cpp @@ -4,14 +4,15 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "RLP.h" #include "Transaction.h" +#include "RLP.h" #include "../Ethereum/RLP.h" using namespace TW; -using namespace TW::Aion; using boost::multiprecision::uint128_t; +namespace TW::Aion { + Data Transaction::encode() const noexcept { auto encoded = Data(); append(encoded, Ethereum::RLP::encode(nonce)); @@ -27,3 +28,5 @@ Data Transaction::encode() const noexcept { } return Ethereum::RLP::encodeList(encoded); } + +} // namespace TW::Aion diff --git a/src/Cosmos/Entry.cpp b/src/Cosmos/Entry.cpp index bc5976080f4..bb8ee4698d1 100644 --- a/src/Cosmos/Entry.cpp +++ b/src/Cosmos/Entry.cpp @@ -9,10 +9,11 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Cosmos; using namespace TW; using namespace std; +namespace TW::Cosmos { + // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, [[maybe_unused]] const char* hrp) const { @@ -38,6 +39,8 @@ void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) con dataOut.insert(dataOut.end(), serializedOut.begin(), serializedOut.end()); } -string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { +string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key, coin); } + +} // namespace TW::Cosmos diff --git a/src/Cosmos/JsonSerialization.cpp b/src/Cosmos/JsonSerialization.cpp index cf77b344a5d..0b4879f98b9 100644 --- a/src/Cosmos/JsonSerialization.cpp +++ b/src/Cosmos/JsonSerialization.cpp @@ -13,13 +13,12 @@ #include "PrivateKey.h" using namespace TW; -using namespace TW::Cosmos; + +namespace TW::Cosmos::Json { using json = nlohmann::json; using string = std::string; -namespace TW::Cosmos { - const string TYPE_PREFIX_MSG_SEND = "cosmos-sdk/MsgSend"; const string TYPE_PREFIX_MSG_DELEGATE = "cosmos-sdk/MsgDelegate"; const string TYPE_PREFIX_MSG_UNDELEGATE = "cosmos-sdk/MsgUndelegate"; @@ -145,7 +144,7 @@ json messageWasmTerraTransfer(const Proto::Message_WasmTerraExecuteContractTrans { {"sender", msg.sender_address()}, {"contract", msg.contract_address()}, - {"execute_msg", wasmTerraExecuteTransferPayload(msg)}, + {"execute_msg", Protobuf::wasmTerraExecuteTransferPayload(msg)}, {"coins", json::array()} // used in case you are sending native tokens along with this message } } @@ -219,4 +218,4 @@ json transactionJSON(const Proto::SigningInput& input, const Data& signature) { return broadcastJSON(tx, input.mode()); } -} // namespace +} // namespace TW::Cosmos diff --git a/src/Cosmos/JsonSerialization.h b/src/Cosmos/JsonSerialization.h index 61b63e92dd8..3de2cd43443 100644 --- a/src/Cosmos/JsonSerialization.h +++ b/src/Cosmos/JsonSerialization.h @@ -6,24 +6,24 @@ #pragma once -#include "../proto/Cosmos.pb.h" #include "Data.h" +#include "../proto/Cosmos.pb.h" #include -using string = std::string; -using json = nlohmann::json; +extern const std::string TYPE_PREFIX_MSG_SEND; +extern const std::string TYPE_PREFIX_MSG_TRANSFER; +extern const std::string TYPE_PREFIX_MSG_DELEGATE; +extern const std::string TYPE_PREFIX_MSG_UNDELEGATE; +extern const std::string TYPE_PREFIX_MSG_REDELEGATE; +extern const std::string TYPE_PREFIX_MSG_WITHDRAW_REWARD; +extern const std::string TYPE_PREFIX_PUBLIC_KEY; -extern const string TYPE_PREFIX_MSG_SEND; -extern const string TYPE_PREFIX_MSG_TRANSFER; -extern const string TYPE_PREFIX_MSG_DELEGATE; -extern const string TYPE_PREFIX_MSG_UNDELEGATE; -extern const string TYPE_PREFIX_MSG_REDELEGATE; -extern const string TYPE_PREFIX_MSG_WITHDRAW_REWARD; -extern const string TYPE_PREFIX_PUBLIC_KEY; +namespace TW::Cosmos::Json { -namespace TW::Cosmos { +using string = std::string; +using json = nlohmann::json; json signaturePreimageJSON(const Proto::SigningInput& input); json transactionJSON(const Proto::SigningInput& input, const Data& signature); -} // namespace +} // namespace TW::Cosmos::json diff --git a/src/Cosmos/Protobuf/.clang-tidy b/src/Cosmos/Protobuf/.clang-tidy new file mode 100644 index 00000000000..2c22f7387dd --- /dev/null +++ b/src/Cosmos/Protobuf/.clang-tidy @@ -0,0 +1,6 @@ +--- +InheritParentConfig: false +Checks: '-*,misc-definitions-in-headers' +CheckOptions: + - { key: HeaderFileExtensions, value: "x" } +... diff --git a/src/Cosmos/ProtobufSerialization.cpp b/src/Cosmos/ProtobufSerialization.cpp index 4364b3e0409..2b1a6709eaa 100644 --- a/src/Cosmos/ProtobufSerialization.cpp +++ b/src/Cosmos/ProtobufSerialization.cpp @@ -28,10 +28,11 @@ #include using namespace TW; -using namespace TW::Cosmos; -namespace TW::Cosmos { +namespace TW::Cosmos::Protobuf { +using json = nlohmann::json; +using string = std::string; const auto ProtobufAnyNamespacePrefix = ""; // to override default 'type.googleapis.com' cosmos::base::v1beta1::Coin convertCoin(const Proto::Amount& amount) { @@ -131,7 +132,7 @@ google::protobuf::Any convertMessage(const Proto::Message& msg) { auto msgExecute = terra::wasm::v1beta1::MsgExecuteContract(); msgExecute.set_sender(wasmExecute.sender_address()); msgExecute.set_contract(wasmExecute.contract_address()); - const std::string payload = Cosmos::wasmTerraExecuteTransferPayload(wasmExecute).dump(); + const std::string payload = wasmTerraExecuteTransferPayload(wasmExecute).dump(); msgExecute.set_execute_msg(payload); any.PackFrom(msgExecute, ProtobufAnyNamespacePrefix); return any; @@ -144,7 +145,7 @@ google::protobuf::Any convertMessage(const Proto::Message& msg) { auto msgExecute = terra::wasm::v1beta1::MsgExecuteContract(); msgExecute.set_sender(wasmExecute.sender_address()); msgExecute.set_contract(wasmExecute.contract_address()); - const std::string payload = Cosmos::wasmTerraExecuteSendPayload(wasmExecute).dump(); + const std::string payload = wasmTerraExecuteSendPayload(wasmExecute).dump(); msgExecute.set_execute_msg(payload); any.PackFrom(msgExecute, ProtobufAnyNamespacePrefix); return any; @@ -186,7 +187,7 @@ google::protobuf::Any convertMessage(const Proto::Message& msg) { auto msgExecute = cosmwasm::wasm::v1::MsgExecuteContract(); msgExecute.set_sender(wasmExecute.sender_address()); msgExecute.set_contract(wasmExecute.contract_address()); - const std::string payload = Cosmos::wasmExecuteTransferPayload(wasmExecute).dump(); + const std::string payload = wasmExecuteTransferPayload(wasmExecute).dump(); msgExecute.set_msg(payload); any.PackFrom(msgExecute, ProtobufAnyNamespacePrefix); return any; @@ -199,7 +200,7 @@ google::protobuf::Any convertMessage(const Proto::Message& msg) { auto msgExecute = cosmwasm::wasm::v1::MsgExecuteContract(); msgExecute.set_sender(wasmExecute.sender_address()); msgExecute.set_contract(wasmExecute.contract_address()); - const std::string payload = Cosmos::wasmExecuteSendPayload(wasmExecute).dump(); + const std::string payload = wasmExecuteSendPayload(wasmExecute).dump(); msgExecute.set_msg(payload); any.PackFrom(msgExecute, ProtobufAnyNamespacePrefix); return any; diff --git a/src/Cosmos/ProtobufSerialization.h b/src/Cosmos/ProtobufSerialization.h index 28c49be0c57..035bb7f2c7e 100644 --- a/src/Cosmos/ProtobufSerialization.h +++ b/src/Cosmos/ProtobufSerialization.h @@ -6,15 +6,15 @@ #pragma once -#include "../proto/Cosmos.pb.h" #include "Data.h" +#include "../proto/Cosmos.pb.h" #include #include #include -namespace TW::Cosmos { +namespace TW::Cosmos::Protobuf { std::string buildProtoTxBody(const Proto::SigningInput& input); @@ -34,4 +34,4 @@ nlohmann::json wasmTerraExecuteTransferPayload(const Proto::Message_WasmTerraExe nlohmann::json wasmTerraExecuteSendPayload(const Proto::Message_WasmTerraExecuteContractSend& msg); -} // namespace +} // namespace TW::Cosmos::protobuf diff --git a/src/Cosmos/Signer.cpp b/src/Cosmos/Signer.cpp index 5c2a9e0ac60..7da012e0e3e 100644 --- a/src/Cosmos/Signer.cpp +++ b/src/Cosmos/Signer.cpp @@ -29,13 +29,13 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input, TWCoinType c Proto::SigningOutput Signer::signJsonSerialized(const Proto::SigningInput& input) noexcept { auto key = PrivateKey(input.private_key()); - auto preimage = signaturePreimageJSON(input).dump(); + auto preimage = Json::signaturePreimageJSON(input).dump(); auto hash = Hash::sha256(preimage); auto signedHash = key.sign(hash, TWCurveSECP256k1); auto output = Proto::SigningOutput(); auto signature = Data(signedHash.begin(), signedHash.end() - 1); - auto txJson = transactionJSON(input, signature); + auto txJson = Json::transactionJSON(input, signature); output.set_json(txJson.dump()); output.set_signature(signature.data(), signature.size()); output.set_serialized(""); @@ -44,6 +44,7 @@ Proto::SigningOutput Signer::signJsonSerialized(const Proto::SigningInput& input } Proto::SigningOutput Signer::signProtobuf(const Proto::SigningInput& input, TWCoinType coin) noexcept { + using namespace Protobuf; try { const auto serializedTxBody = buildProtoTxBody(input); const auto serializedAuthInfo = buildAuthInfo(input, coin); @@ -51,7 +52,7 @@ Proto::SigningOutput Signer::signProtobuf(const Proto::SigningInput& input, TWCo auto serializedTxRaw = buildProtoTxRaw(serializedTxBody, serializedAuthInfo, signature); auto output = Proto::SigningOutput(); - const string jsonSerialized = buildProtoTxJson(input, serializedTxRaw); + const std::string jsonSerialized = buildProtoTxJson(input, serializedTxRaw); output.set_serialized(jsonSerialized); output.set_signature(signature.data(), signature.size()); output.set_json(""); diff --git a/src/Decred/Address.cpp b/src/Decred/Address.cpp index 0d0d8c666b3..dd5bf2fd667 100644 --- a/src/Decred/Address.cpp +++ b/src/Decred/Address.cpp @@ -7,14 +7,16 @@ #include "Address.h" #include "../Base58.h" -#include "../Hash.h" #include "../Coin.h" +#include "../Hash.h" #include using namespace TW; using namespace TW::Decred; +namespace TW::Decred { + static const auto keyhashSize = Hash::ripemdSize; static const auto addressDataSize = keyhashSize + 2; @@ -27,7 +29,7 @@ bool Address::isValid(const std::string& string) noexcept { return false; } - return (data[1] == TW::p2pkhPrefix(TWCoinTypeDecred) || + return (data[1] == TW::p2pkhPrefix(TWCoinTypeDecred) || data[1] == TW::p2shPrefix(TWCoinTypeDecred)); } @@ -53,3 +55,5 @@ Address::Address(const PublicKey& publicKey) { std::string Address::string() const { return Base58::bitcoin.encodeCheck(bytes, Hash::HasherBlake256d); } + +} // namespace TW::Decred diff --git a/src/EOS/Action.h b/src/EOS/Action.h index cd55cb47fb5..c2ebcb6fa8f 100644 --- a/src/EOS/Action.h +++ b/src/EOS/Action.h @@ -12,8 +12,6 @@ #include #include -using Data = TW::Data; - namespace TW::EOS { class PermissionLevel { diff --git a/src/Elrond/Address.cpp b/src/Elrond/Address.cpp index 1af84ace200..581f95b1e9e 100644 --- a/src/Elrond/Address.cpp +++ b/src/Elrond/Address.cpp @@ -8,10 +8,12 @@ #include "Address.h" -using namespace TW::Elrond; +namespace TW::Elrond { const std::string Address::hrp = HRP_ELROND; bool Address::isValid(const std::string& string) { return Bech32Address::isValid(string, hrp); } + +} // namespace TW::Elrond diff --git a/src/Elrond/Entry.cpp b/src/Elrond/Entry.cpp index 7ff8917f7e0..2535f0bec96 100644 --- a/src/Elrond/Entry.cpp +++ b/src/Elrond/Entry.cpp @@ -9,10 +9,10 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Elrond; using namespace TW; using namespace std; +namespace TW::Elrond { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -38,3 +38,5 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } + +} // namespace TW::Elrond diff --git a/src/Elrond/Serialization.cpp b/src/Elrond/Serialization.cpp index 192cf935d66..ffe2241bd08 100644 --- a/src/Elrond/Serialization.cpp +++ b/src/Elrond/Serialization.cpp @@ -11,7 +11,7 @@ using namespace TW; -std::map fields_order { +std::map fields_order{ {"nonce", 1}, {"value", 2}, {"receiver", 3}, @@ -24,21 +24,21 @@ std::map fields_order { {"chainID", 10}, {"version", 11}, {"options", 12}, - {"signature", 13} -}; + {"signature", 13}}; struct FieldsSorter { - bool operator() (const string& lhs, const string& rhs) const { - return fields_order[lhs] < fields_order[rhs]; + bool operator()(const std::string& lhs, const std::string& rhs) const { + return fields_order[lhs] < fields_order[rhs]; } }; -template +template using sorted_map = std::map; using sorted_json = nlohmann::basic_json; sorted_json preparePayload(const Elrond::Transaction& transaction) { - sorted_json payload { + using namespace nlohmann; + sorted_json payload{ {"nonce", json(transaction.nonce)}, {"value", json(transaction.value)}, {"receiver", json(transaction.receiver)}, @@ -69,13 +69,13 @@ sorted_json preparePayload(const Elrond::Transaction& transaction) { return payload; } -string Elrond::serializeTransaction(const Elrond::Transaction& transaction) { +std::string Elrond::serializeTransaction(const Elrond::Transaction& transaction) { sorted_json payload = preparePayload(transaction); return payload.dump(); } -string Elrond::serializeSignedTransaction(const Elrond::Transaction& transaction, string signature) { +std::string Elrond::serializeSignedTransaction(const Elrond::Transaction& transaction, std::string signature) { sorted_json payload = preparePayload(transaction); - payload["signature"] = json(signature); + payload["signature"] = nlohmann::json(signature); return payload.dump(); } diff --git a/src/Elrond/Serialization.h b/src/Elrond/Serialization.h index dd0d57cb894..64023d47213 100644 --- a/src/Elrond/Serialization.h +++ b/src/Elrond/Serialization.h @@ -10,12 +10,12 @@ #include "Transaction.h" #include +namespace TW::Elrond { + using string = std::string; using json = nlohmann::json; -namespace TW::Elrond { - string serializeTransaction(const Transaction& transaction); string serializeSignedTransaction(const Transaction& transaction, string encodedSignature); -} // namespace +} // namespace TW::Elrond diff --git a/src/Ethereum/ABI/Array.cpp b/src/Ethereum/ABI/Array.cpp index 4f79e816ed7..60cd194c1b2 100644 --- a/src/Ethereum/ABI/Array.cpp +++ b/src/Ethereum/ABI/Array.cpp @@ -13,19 +13,26 @@ #include -using namespace TW::Ethereum::ABI; +namespace TW::Ethereum::ABI { + using namespace TW; using json = nlohmann::json; int ParamArray::addParam(const std::shared_ptr& param) { assert(param != nullptr); - if (param == nullptr) { return -1; } - if (_params.getCount() >= 1 && param->getType() != getProtoType()) { return -2; } // do not add different types + if (param == nullptr) { + return -1; + } + if (_params.getCount() >= 1 && param->getType() != getProtoType()) { + return -2; + } // do not add different types return _params.addParam(param); } void ParamArray::addParams(const std::vector>& params) { - for (auto p: params) { addParam(p); } + for (auto p : params) { + addParam(p); + } } std::shared_ptr ParamArray::getProtoElem() const { @@ -40,8 +47,7 @@ std::string ParamArray::getProtoType() const { return (proto != nullptr) ? proto->getType() : "__empty__"; } -size_t ParamArray::getSize() const -{ +size_t ParamArray::getSize() const { return 32 + _params.getSize(); } @@ -102,7 +108,7 @@ bool ParamArray::setValueJson(const std::string& value) { addParam(ParamFactory::make(getProtoType())); } int cnt = 0; - for (const auto& e: valuesJson) { + for (const auto& e : valuesJson) { std::string eString = e.is_string() ? e.get() : e.dump(); _params.getParamUnsafe(cnt)->setValueJson(eString); ++cnt; @@ -112,7 +118,7 @@ bool ParamArray::setValueJson(const std::string& value) { Data ParamArray::hashStruct() const { if (_params.getCount() == 0) { - return Hash::keccak256(Data()); + return Hash::keccak256(Data()); } Data hash(32); Data hashes = _params.encodeHashes(); @@ -126,3 +132,5 @@ std::string ParamArray::getExtraTypes(std::vector& ignoreList) cons const auto& proto = getProtoElem(); return (proto != nullptr) ? proto->getExtraTypes(ignoreList) : ""; } + +} // namespace TW::Ethereum::ABI diff --git a/src/FIO/Address.cpp b/src/FIO/Address.cpp index 362cd7c6a9d..52d1086e48f 100644 --- a/src/FIO/Address.cpp +++ b/src/FIO/Address.cpp @@ -4,16 +4,17 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include "Address.h" #include "../Base58.h" #include "../BinaryCoding.h" -#include "Address.h" #include #include using namespace TW; -using namespace TW::FIO; + +namespace TW::FIO { bool Address::isValid(const std::string& string) { return decodeKeyData(string).has_value(); @@ -101,3 +102,5 @@ PublicKey Address::publicKey() const { const Data keyData = TW::data(bytes.data(), PublicKey::secp256k1Size); return PublicKey(keyData, TWPublicKeyTypeSECP256k1); } + +} // namespace TW::FIO diff --git a/src/Generated/.clang-tidy b/src/Generated/.clang-tidy new file mode 100644 index 00000000000..2c22f7387dd --- /dev/null +++ b/src/Generated/.clang-tidy @@ -0,0 +1,6 @@ +--- +InheritParentConfig: false +Checks: '-*,misc-definitions-in-headers' +CheckOptions: + - { key: HeaderFileExtensions, value: "x" } +... diff --git a/src/Harmony/Address.cpp b/src/Harmony/Address.cpp index 69a68fab06a..e4be72aa81f 100644 --- a/src/Harmony/Address.cpp +++ b/src/Harmony/Address.cpp @@ -10,7 +10,8 @@ #include -using namespace TW::Harmony; +namespace TW::Harmony { const std::string Address::hrp = HRP_HARMONY; +} diff --git a/src/Harmony/Entry.cpp b/src/Harmony/Entry.cpp index ec8225be7cc..ad652105739 100644 --- a/src/Harmony/Entry.cpp +++ b/src/Harmony/Entry.cpp @@ -9,10 +9,11 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Harmony; using namespace TW; using namespace std; +namespace TW::Harmony { + // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -38,3 +39,5 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } + +} // namespace TW::Harmony diff --git a/src/Harmony/Signer.cpp b/src/Harmony/Signer.cpp index 160d2cc926b..5d0d7aefe82 100644 --- a/src/Harmony/Signer.cpp +++ b/src/Harmony/Signer.cpp @@ -9,11 +9,11 @@ #include "../HexCoding.h" #include - using namespace TW; -using namespace TW::Harmony; -std::tuple Signer::values(const uint256_t &chainID, +namespace TW::Harmony { + +std::tuple Signer::values(const uint256_t& chainID, const Data& signature) noexcept { auto r = load(Data(signature.begin(), signature.begin() + 32)); auto s = load(Data(signature.begin() + 32, signature.begin() + 64)); @@ -23,13 +23,13 @@ std::tuple Signer::values(const uint256_t &chai } std::tuple -Signer::sign(const uint256_t &chainID, const PrivateKey &privateKey, const Data& hash) noexcept { +Signer::sign(const uint256_t& chainID, const PrivateKey& privateKey, const Data& hash) noexcept { auto signature = privateKey.sign(hash, TWCurveSECP256k1); return values(chainID, signature); } template -Proto::SigningOutput Signer::prepareOutput(const Data& encoded, const T &transaction) noexcept { +Proto::SigningOutput Signer::prepareOutput(const Data& encoded, const T& transaction) noexcept { auto protoOutput = Proto::SigningOutput(); auto v = store(transaction.v, 1); @@ -44,7 +44,7 @@ Proto::SigningOutput Signer::prepareOutput(const Data& encoded, const T &transac return protoOutput; } -Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { +Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { if (input.has_transaction_message()) { return signTransaction(input); } @@ -76,7 +76,7 @@ std::string Signer::signJSON(const std::string& json, const Data& key) { return hex(Signer::sign(input).encoded()); } -Proto::SigningOutput Signer::signTransaction(const Proto::SigningInput &input) noexcept { +Proto::SigningOutput Signer::signTransaction(const Proto::SigningInput& input) noexcept { auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); Address toAddr; if (!Address::decode(input.transaction_message().to_address(), toAddr)) { @@ -104,7 +104,7 @@ Proto::SigningOutput Signer::signTransaction(const Proto::SigningInput &input) n return prepareOutput(encoded, transaction); } -Proto::SigningOutput Signer::signCreateValidator(const Proto::SigningInput &input) noexcept { +Proto::SigningOutput Signer::signCreateValidator(const Proto::SigningInput& input) noexcept { auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); auto description = Description( /* name */ input.staking_message().create_validator_message().description().name(), @@ -186,7 +186,7 @@ Proto::SigningOutput Signer::signCreateValidator(const Proto::SigningInput &inpu return prepareOutput>(encoded, stakingTx); } -Proto::SigningOutput Signer::signEditValidator(const Proto::SigningInput &input) noexcept { +Proto::SigningOutput Signer::signEditValidator(const Proto::SigningInput& input) noexcept { auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); auto description = Description( @@ -245,7 +245,7 @@ Proto::SigningOutput Signer::signEditValidator(const Proto::SigningInput &input) return prepareOutput>(encoded, stakingTx); } -Proto::SigningOutput Signer::signDelegate(const Proto::SigningInput &input) noexcept { +Proto::SigningOutput Signer::signDelegate(const Proto::SigningInput& input) noexcept { auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); Address delegatorAddr; @@ -275,7 +275,7 @@ Proto::SigningOutput Signer::signDelegate(const Proto::SigningInput &input) noex return prepareOutput>(encoded, stakingTx); } -Proto::SigningOutput Signer::signUndelegate(const Proto::SigningInput &input) noexcept { +Proto::SigningOutput Signer::signUndelegate(const Proto::SigningInput& input) noexcept { auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); Address delegatorAddr; @@ -305,7 +305,7 @@ Proto::SigningOutput Signer::signUndelegate(const Proto::SigningInput &input) no return prepareOutput>(encoded, stakingTx); } -Proto::SigningOutput Signer::signCollectRewards(const Proto::SigningInput &input) noexcept { +Proto::SigningOutput Signer::signCollectRewards(const Proto::SigningInput& input) noexcept { auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); Address delegatorAddr; @@ -329,14 +329,14 @@ Proto::SigningOutput Signer::signCollectRewards(const Proto::SigningInput &input } template -void Signer::sign(const PrivateKey &privateKey, const Data& hash, T &transaction) const noexcept { +void Signer::sign(const PrivateKey& privateKey, const Data& hash, T& transaction) const noexcept { auto tuple = sign(chainID, privateKey, hash); transaction.r = std::get<0>(tuple); transaction.s = std::get<1>(tuple); transaction.v = std::get<2>(tuple); } -Data Signer::rlpNoHash(const Transaction &transaction, const bool include_vrs) const noexcept { +Data Signer::rlpNoHash(const Transaction& transaction, const bool include_vrs) const noexcept { auto encoded = Data(); using namespace TW::Ethereum; append(encoded, RLP::encode(transaction.nonce)); @@ -360,7 +360,7 @@ Data Signer::rlpNoHash(const Transaction &transaction, const bool include_vrs) c } template -Data Signer::rlpNoHash(const Staking &transaction, const bool include_vrs) const +Data Signer::rlpNoHash(const Staking& transaction, const bool include_vrs) const noexcept { auto encoded = Data(); using namespace TW::Ethereum; @@ -382,7 +382,7 @@ Data Signer::rlpNoHash(const Staking &transaction, const bool include return RLP::encodeList(encoded); } -Data Signer::rlpNoHashDirective(const Staking &transaction) const noexcept { +Data Signer::rlpNoHashDirective(const Staking& transaction) const noexcept { auto encoded = Data(); using namespace TW::Ethereum; @@ -433,7 +433,7 @@ Data Signer::rlpNoHashDirective(const Staking &transaction) con return RLP::encodeList(encoded); } -Data Signer::rlpNoHashDirective(const Staking &transaction) const noexcept { +Data Signer::rlpNoHashDirective(const Staking& transaction) const noexcept { auto encoded = Data(); using namespace TW::Ethereum; @@ -466,7 +466,7 @@ Data Signer::rlpNoHashDirective(const Staking &transaction) const return RLP::encodeList(encoded); } -Data Signer::rlpNoHashDirective(const Staking &transaction) const noexcept { +Data Signer::rlpNoHashDirective(const Staking& transaction) const noexcept { auto encoded = Data(); using namespace TW::Ethereum; append(encoded, RLP::encode(transaction.stakeMsg.delegatorAddress.getKeyHash())); @@ -475,7 +475,7 @@ Data Signer::rlpNoHashDirective(const Staking &transaction) const noex return RLP::encodeList(encoded); } -Data Signer::rlpNoHashDirective(const Staking &transaction) const noexcept { +Data Signer::rlpNoHashDirective(const Staking& transaction) const noexcept { auto encoded = Data(); using namespace TW::Ethereum; append(encoded, RLP::encode(transaction.stakeMsg.delegatorAddress.getKeyHash())); @@ -484,27 +484,29 @@ Data Signer::rlpNoHashDirective(const Staking &transaction) const no return RLP::encodeList(encoded); } -Data Signer::rlpNoHashDirective(const Staking &transaction) const noexcept { +Data Signer::rlpNoHashDirective(const Staking& transaction) const noexcept { auto encoded = Data(); using namespace TW::Ethereum; append(encoded, RLP::encode(transaction.stakeMsg.delegatorAddress.getKeyHash())); return RLP::encodeList(encoded); } -std::string Signer::txnAsRLPHex(Transaction &transaction) const noexcept { +std::string Signer::txnAsRLPHex(Transaction& transaction) const noexcept { return TW::hex(rlpNoHash(transaction, false)); } template -std::string Signer::txnAsRLPHex(Staking &transaction) const noexcept { +std::string Signer::txnAsRLPHex(Staking& transaction) const noexcept { return TW::hex(rlpNoHash(transaction, false)); } -Data Signer::hash(const Transaction &transaction) const noexcept { +Data Signer::hash(const Transaction& transaction) const noexcept { return Hash::keccak256(rlpNoHash(transaction, false)); } template -Data Signer::hash(const Staking &transaction) const noexcept { +Data Signer::hash(const Staking& transaction) const noexcept { return Hash::keccak256(rlpNoHash(transaction, false)); } + +} // namespace TW::Harmony diff --git a/src/Icon/Address.cpp b/src/Icon/Address.cpp index 4c86ae521d9..08aaf4e60bd 100644 --- a/src/Icon/Address.cpp +++ b/src/Icon/Address.cpp @@ -15,6 +15,8 @@ using namespace TW; using namespace TW::Icon; +namespace TW::Icon { + static const std::string addressPrefix = "hx"; static const std::string contractPrefix = "cx"; @@ -46,7 +48,8 @@ Address::Address(const std::string& string) { std::copy(data.begin(), data.end(), bytes.begin()); } -Address::Address(const PublicKey& publicKey, enum AddressType type) : type(type) { +Address::Address(const PublicKey& publicKey, enum AddressType type) + : type(type) { auto hash = std::array(); sha3_256(publicKey.bytes.data() + 1, publicKey.bytes.size() - 1, hash.data()); std::copy(hash.end() - Address::size, hash.end(), bytes.begin()); @@ -62,3 +65,5 @@ std::string Address::string() const { return ""; } } + +} // namespace TW::Icon diff --git a/src/IoTeX/Address.cpp b/src/IoTeX/Address.cpp index 606af156391..7aca2f45b63 100644 --- a/src/IoTeX/Address.cpp +++ b/src/IoTeX/Address.cpp @@ -8,6 +8,8 @@ #include -using namespace TW::IoTeX; +namespace TW::IoTeX { const std::string Address::hrp = HRP_IOTEX; + +} diff --git a/src/IoTeX/Entry.cpp b/src/IoTeX/Entry.cpp index bda6036643c..5e427d85a67 100644 --- a/src/IoTeX/Entry.cpp +++ b/src/IoTeX/Entry.cpp @@ -9,9 +9,10 @@ #include "Address.h" #include "Signer.h" -using namespace TW::IoTeX; using namespace std; +namespace TW::IoTeX { + // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -25,3 +26,5 @@ string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& p void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::IoTeX diff --git a/src/Keystore/ScryptParameters.cpp b/src/Keystore/ScryptParameters.cpp index defc8788bb9..623cc070e61 100644 --- a/src/Keystore/ScryptParameters.cpp +++ b/src/Keystore/ScryptParameters.cpp @@ -43,7 +43,7 @@ std::optional ScryptParameters::validate() const { // Encoding/Decoding // ----------------- -namespace CodingKeys { +namespace CodingKeys::SP { static const auto salt = "salt"; static const auto desiredKeyLength = "dklen"; static const auto n = "n"; @@ -52,23 +52,23 @@ static const auto r = "r"; } // namespace CodingKeys ScryptParameters::ScryptParameters(const nlohmann::json& json) { - salt = parse_hex(json[CodingKeys::salt].get()); - desiredKeyLength = json[CodingKeys::desiredKeyLength]; - if (json.count(CodingKeys::n) != 0) - n = json[CodingKeys::n]; - if (json.count(CodingKeys::n) != 0) - p = json[CodingKeys::p]; - if (json.count(CodingKeys::n) != 0) - r = json[CodingKeys::r]; + salt = parse_hex(json[CodingKeys::SP::salt].get()); + desiredKeyLength = json[CodingKeys::SP::desiredKeyLength]; + if (json.count(CodingKeys::SP::n) != 0) + n = json[CodingKeys::SP::n]; + if (json.count(CodingKeys::SP::n) != 0) + p = json[CodingKeys::SP::p]; + if (json.count(CodingKeys::SP::n) != 0) + r = json[CodingKeys::SP::r]; } /// Saves `this` as a JSON object. nlohmann::json ScryptParameters::json() const { nlohmann::json j; - j[CodingKeys::salt] = hex(salt); - j[CodingKeys::desiredKeyLength] = desiredKeyLength; - j[CodingKeys::n] = n; - j[CodingKeys::p] = p; - j[CodingKeys::r] = r; + j[CodingKeys::SP::salt] = hex(salt); + j[CodingKeys::SP::desiredKeyLength] = desiredKeyLength; + j[CodingKeys::SP::n] = n; + j[CodingKeys::SP::p] = p; + j[CodingKeys::SP::r] = r; return j; } diff --git a/src/Keystore/StoredKey.cpp b/src/Keystore/StoredKey.cpp index 297eeb5443b..68124a9df72 100644 --- a/src/Keystore/StoredKey.cpp +++ b/src/Keystore/StoredKey.cpp @@ -301,7 +301,7 @@ StoredKey StoredKey::createWithJson(const nlohmann::json& json) { return storedKey; } -namespace CodingKeys { +namespace CodingKeys::SK { static const auto address = "address"; static const auto type = "type"; static const auto name = "name"; @@ -322,23 +322,23 @@ static const auto mnemonic = "mnemonic"; } // namespace TypeString void StoredKey::loadJson(const nlohmann::json& json) { - if (json.count(CodingKeys::type) != 0 && - json[CodingKeys::type].get() == TypeString::mnemonic) { + if (json.count(CodingKeys::SK::type) != 0 && + json[CodingKeys::SK::type].get() == TypeString::mnemonic) { type = StoredKeyType::mnemonicPhrase; } else { type = StoredKeyType::privateKey; } - if (json.count(CodingKeys::name) != 0) { - name = json[CodingKeys::name].get(); + if (json.count(CodingKeys::SK::name) != 0) { + name = json[CodingKeys::SK::name].get(); } - if (json.count(CodingKeys::id) != 0) { - id = json[CodingKeys::id].get(); + if (json.count(CodingKeys::SK::id) != 0) { + id = json[CodingKeys::SK::id].get(); } - if (json.count(CodingKeys::crypto) != 0) { - payload = EncryptedPayload(json[CodingKeys::crypto]); + if (json.count(CodingKeys::SK::crypto) != 0) { + payload = EncryptedPayload(json[CodingKeys::SK::crypto]); } else if (json.count(UppercaseCodingKeys::crypto) != 0) { // Workaround for myEtherWallet files payload = EncryptedPayload(json[UppercaseCodingKeys::crypto]); @@ -346,49 +346,49 @@ void StoredKey::loadJson(const nlohmann::json& json) { throw DecryptionError::invalidKeyFile; } - if (json.count(CodingKeys::activeAccounts) != 0 && - json[CodingKeys::activeAccounts].is_array()) { - for (auto& accountJSON : json[CodingKeys::activeAccounts]) { + if (json.count(CodingKeys::SK::activeAccounts) != 0 && + json[CodingKeys::SK::activeAccounts].is_array()) { + for (auto& accountJSON : json[CodingKeys::SK::activeAccounts]) { accounts.emplace_back(accountJSON); } } - if (accounts.empty() && json.count(CodingKeys::address) != 0 && - json[CodingKeys::address].is_string()) { + if (accounts.empty() && json.count(CodingKeys::SK::address) != 0 && + json[CodingKeys::SK::address].is_string()) { TWCoinType coin = TWCoinTypeEthereum; - if (json.count(CodingKeys::coin) != 0) { - coin = json[CodingKeys::coin].get(); + if (json.count(CodingKeys::SK::coin) != 0) { + coin = json[CodingKeys::SK::coin].get(); } - auto address = json[CodingKeys::address].get(); + auto address = json[CodingKeys::SK::address].get(); accounts.emplace_back(address, coin, TWDerivationDefault, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(coin), 0, 0, 0), "", ""); } } nlohmann::json StoredKey::json() const { nlohmann::json j; - j[CodingKeys::version] = 3; + j[CodingKeys::SK::version] = 3; switch (type) { case StoredKeyType::privateKey: - j[CodingKeys::type] = TypeString::privateKey; + j[CodingKeys::SK::type] = TypeString::privateKey; break; case StoredKeyType::mnemonicPhrase: - j[CodingKeys::type] = TypeString::mnemonic; + j[CodingKeys::SK::type] = TypeString::mnemonic; break; } if (id) { - j[CodingKeys::id] = *id; + j[CodingKeys::SK::id] = *id; } - j[CodingKeys::name] = name; - j[CodingKeys::crypto] = payload.json(); + j[CodingKeys::SK::name] = name; + j[CodingKeys::SK::crypto] = payload.json(); nlohmann::json accountsJSON = nlohmann::json::array(); for (const auto& account : accounts) { accountsJSON.push_back(account.json()); } - j[CodingKeys::activeAccounts] = accountsJSON; + j[CodingKeys::SK::activeAccounts] = accountsJSON; return j; } diff --git a/src/NEAR/Address.cpp b/src/NEAR/Address.cpp index 3d8eeff1fad..1d669e3d449 100644 --- a/src/NEAR/Address.cpp +++ b/src/NEAR/Address.cpp @@ -4,20 +4,21 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include "Address.h" #include "Base58.h" #include "HexCoding.h" -#include "Address.h" #include using namespace TW; -using namespace TW::NEAR; + +namespace TW::NEAR { bool Address::isValid(const std::string& string) { const auto data = Address::decodeLegacyAddress(string); if (data.has_value()) { return true; - } + } const auto parsed = parse_hex(string); return parsed.size() == PublicKey::ed25519Size; } @@ -40,7 +41,7 @@ Address::Address(const std::string& string) { std::copy(std::begin(*data), std::end(*data), std::begin(bytes)); } else { if (!Address::isValid(string)) { - throw std::invalid_argument("Invalid address string!"); + throw std::invalid_argument("Invalid address string!"); } const auto parsed = parse_hex(string); std::copy(std::begin(parsed), std::end(parsed), std::begin(bytes)); @@ -58,3 +59,5 @@ Address::Address(const PublicKey& publicKey) { std::string Address::string() const { return hex(bytes); } + +} // namespace TW::NEAR diff --git a/src/NEAR/Entry.cpp b/src/NEAR/Entry.cpp index e5b36a0b975..c33987cc422 100644 --- a/src/NEAR/Entry.cpp +++ b/src/NEAR/Entry.cpp @@ -9,10 +9,11 @@ #include "Address.h" #include "Signer.h" -using namespace TW::NEAR; using namespace TW; using namespace std; +namespace TW::NEAR { + // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -35,3 +36,5 @@ Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& a void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::NEAR diff --git a/src/NEO/Address.cpp b/src/NEO/Address.cpp index e58b3f32208..14a2df31c07 100644 --- a/src/NEO/Address.cpp +++ b/src/NEO/Address.cpp @@ -4,16 +4,17 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../Ontology/ParamsBuilder.h" +#include "OpCode.h" #include "../Base58.h" -#include "../Hash.h" #include "../Data.h" -#include "OpCode.h" +#include "../Hash.h" +#include "../Ontology/ParamsBuilder.h" #include "Address.h" using namespace TW; -using namespace TW::NEO; + +namespace TW::NEO { bool Address::isValid(const std::string& string) { const auto decoded = Base58::bitcoin.decodeCheck(string); @@ -36,7 +37,7 @@ Address::Address(const PublicKey& publicKey) { pkdata.push_back(CHECKSIG); auto keyHash = Hash::ripemd(Hash::sha256(pkdata)); - keyHash.insert(keyHash.begin(), (byte) Address::version); + keyHash.insert(keyHash.begin(), (byte)Address::version); if (keyHash.size() != Address::size) { throw std::invalid_argument("Invalid address key data"); @@ -60,3 +61,5 @@ Data Address::toScriptHash() const { std::copy(bytes.begin() + 1, bytes.begin() + Hash::ripemdSize + 1, data.begin()); return data; } + +} // namespace TW::NEO diff --git a/src/NULS/Address.cpp b/src/NULS/Address.cpp index 545a618f972..be8a488e320 100644 --- a/src/NULS/Address.cpp +++ b/src/NULS/Address.cpp @@ -12,7 +12,8 @@ #include "../HexCoding.h" using namespace TW; -using namespace TW::NULS; + +namespace TW::NULS { const std::string Address::prefix("NULSd"); const std::array Address::mainnetId = {0x01, 0x00}; @@ -21,7 +22,7 @@ bool Address::isValid(const std::string& string) { if (string.empty()) { return false; } - if (string.length() <= prefix.length()) { + if (string.length() <= prefix.length()) { return false; } @@ -51,10 +52,10 @@ Address::Address(const TW::PublicKey& publicKey) { } Address::Address(const std::string& string) { - if (false == isValid(string)){ + if (false == isValid(string)) { throw std::invalid_argument("Invalid address string"); } - std::string address = string.substr(prefix.length(), string.length() - prefix.length()); + std::string address = string.substr(prefix.length(), string.length() - prefix.length()); const auto decoded = Base58::bitcoin.decode(address); std::copy(decoded.begin(), decoded.end(), bytes.begin()); } @@ -71,7 +72,7 @@ std::string Address::string() const { return prefix + Base58::bitcoin.encode(bytes.begin(), bytes.end()); } -uint8_t Address::checksum(std::array& byteArray) const{ +uint8_t Address::checksum(std::array& byteArray) const { uint8_t checkSum = 0x00; for (int i = 0; i < 23; ++i) { checkSum ^= byteArray[i]; @@ -79,4 +80,4 @@ uint8_t Address::checksum(std::array& byteArray) const{ return checkSum; } - +} // namespace TW::NULS diff --git a/src/NULS/BinaryCoding.h b/src/NULS/BinaryCoding.h index 3909b5c2d98..51de36f5ec9 100644 --- a/src/NULS/BinaryCoding.h +++ b/src/NULS/BinaryCoding.h @@ -6,14 +6,15 @@ #pragma once -#include "../uint256.h" +#include "Address.h" #include "../BinaryCoding.h" -#include "../proto/NULS.pb.h" #include "../HexCoding.h" -#include "Address.h" +#include "../proto/NULS.pb.h" +#include "../uint256.h" using namespace TW; -using namespace TW::NULS; + +namespace TW::NULS { static inline void serializerRemark(std::string& remark, Data& data) { encodeVarInt(remark.length(), data); @@ -21,7 +22,7 @@ static inline void serializerRemark(std::string& remark, Data& data) { } static inline void serializerInput(const Proto::TransactionCoinFrom& input, Data& data) { - encodeVarInt(1, data); //there is one coinFrom + encodeVarInt(1, data); // there is one coinFrom const auto& fromAddress = input.from_address(); if (!NULS::Address::isValid(fromAddress)) { throw std::invalid_argument("Invalid address"); @@ -39,7 +40,7 @@ static inline void serializerInput(const Proto::TransactionCoinFrom& input, Data } static inline void serializerOutput(const Proto::TransactionCoinTo& output, Data& data) { - encodeVarInt(1, data); //there is one coinTo + encodeVarInt(1, data); // there is one coinTo const auto& toAddress = output.to_address(); if (!NULS::Address::isValid(toAddress)) { @@ -71,4 +72,4 @@ static inline Data makeTransactionSignature(PrivateKey& privateKey, Data& txHash return transactionSignature; } - +} // namespace TW::NULS diff --git a/src/NULS/Entry.cpp b/src/NULS/Entry.cpp index 56575ea447f..db59dba1bb1 100644 --- a/src/NULS/Entry.cpp +++ b/src/NULS/Entry.cpp @@ -9,9 +9,10 @@ #include "Address.h" #include "Signer.h" -using namespace TW::NULS; using namespace std; +namespace TW::NULS { + // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -25,3 +26,5 @@ string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& p void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::NULS diff --git a/src/NULS/Signer.cpp b/src/NULS/Signer.cpp index 1e0c903d2a0..77b83e6ebae 100644 --- a/src/NULS/Signer.cpp +++ b/src/NULS/Signer.cpp @@ -12,7 +12,8 @@ #include "../PrivateKey.h" using namespace TW; -using namespace TW::NULS; + +namespace TW::NULS { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto output = Proto::SigningOutput(); @@ -20,20 +21,21 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto signer = Signer(input); auto data = signer.sign(); output.set_encoded(data.data(), data.size()); + } catch (...) { } - catch(...) {} return output; } -Signer::Signer(const Proto::SigningInput& input) : input(input) { +Signer::Signer(const Proto::SigningInput& input) + : input(input) { Proto::TransactionCoinFrom coinFrom; coinFrom.set_from_address(input.from()); coinFrom.set_assets_chainid(input.chain_id()); coinFrom.set_assets_id(input.idassets_id()); - //need to update with amount + fee + // need to update with amount + fee coinFrom.set_id_amount(input.amount()); coinFrom.set_nonce(input.nonce()); - //default unlocked + // default unlocked coinFrom.set_locked(0); *tx.mutable_input() = coinFrom; @@ -88,13 +90,13 @@ Data Signer::sign() const { encode16LE(static_cast(tx.type()), dataRet); // Timestamp encode32LE(tx.timestamp(), dataRet); - // Remark + // Remark std::string remark = tx.remark(); serializerRemark(remark, dataRet); // txData encodeVarInt(0, dataRet); - //coinFrom and coinTo size + // coinFrom and coinTo size encodeVarInt(TRANSACTION_INPUT_SIZE + TRANSACTION_OUTPUT_SIZE, dataRet); // CoinData Input @@ -105,7 +107,7 @@ Data Signer::sign() const { // Calc transaction hash Data txHash = calcTransactionDigest(dataRet); - + Data privKey = data(input.private_key()); auto priv = PrivateKey(privKey); auto transactionSignature = makeTransactionSignature(priv, txHash); @@ -117,7 +119,7 @@ Data Signer::sign() const { uint32_t Signer::CalculatorTransactionSize(uint32_t inputCount, uint32_t outputCount, uint32_t remarkSize) const { uint32_t size = TRANSACTION_FIX_SIZE + TRANSACTION_SIG_MAX_SIZE + TRANSACTION_INPUT_SIZE * inputCount + - TRANSACTION_OUTPUT_SIZE * outputCount + remarkSize; + TRANSACTION_OUTPUT_SIZE * outputCount + remarkSize; return size; } @@ -127,4 +129,6 @@ uint64_t Signer::CalculatorTransactionFee(uint64_t size) const { fee += MIN_PRICE_PRE_1024_BYTES; } return fee; -} \ No newline at end of file +} + +} // namespace TW::NULS diff --git a/src/Nebulas/Address.cpp b/src/Nebulas/Address.cpp index ca94865b701..4b113b6cd8c 100644 --- a/src/Nebulas/Address.cpp +++ b/src/Nebulas/Address.cpp @@ -9,7 +9,7 @@ #include "../Hash.h" #include "../HexCoding.h" -using namespace TW::Nebulas; +namespace TW::Nebulas { bool Address::isValid(const std::string& string) { auto data = Base58::bitcoin.decode(string); @@ -46,14 +46,14 @@ Address::Address(const Data& data) { std::copy(data.begin(), data.end(), bytes.begin()); } -Address::Address(const PublicKey &publicKey) { +Address::Address(const PublicKey& publicKey) { if (publicKey.type != TWPublicKeyTypeSECP256k1Extended) { throw std::invalid_argument("Nebulas::Address needs an extended SECP256k1 public key."); } const auto data = publicKey.hash( {Address::AddressPrefix, Address::NormalType}, Hash::HasherSha3_256ripemd, false); - + std::copy(data.begin(), data.end(), bytes.begin()); auto checksum = Hash::sha3_256(data); std::copy(checksum.begin(), checksum.begin() + 4, bytes.begin() + 22); @@ -62,3 +62,5 @@ Address::Address(const PublicKey &publicKey) { std::string Address::string() const { return Base58::bitcoin.encode(bytes); } + +} // namespace TW::Nebulas diff --git a/src/Nebulas/Entry.cpp b/src/Nebulas/Entry.cpp index 0daf8594ffd..a8b4571e527 100644 --- a/src/Nebulas/Entry.cpp +++ b/src/Nebulas/Entry.cpp @@ -9,9 +9,9 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Nebulas; using namespace std; +namespace TW::Nebulas { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -25,3 +25,5 @@ string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& p void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Nebulas diff --git a/src/Nebulas/Signer.cpp b/src/Nebulas/Signer.cpp index 383ae6b3575..1d0159eeed4 100644 --- a/src/Nebulas/Signer.cpp +++ b/src/Nebulas/Signer.cpp @@ -9,21 +9,21 @@ #include "../HexCoding.h" using namespace TW; -using namespace TW::Nebulas; + +namespace TW::Nebulas { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto signer = Signer(load(input.chain_id())); auto tx = Transaction(Address(input.from_address()), - load(input.nonce()), - load(input.gas_price()), - load(input.gas_limit()), - Address(input.to_address()), - load(input.amount()), - load(input.timestamp()), - input.payload() - ); - + load(input.nonce()), + load(input.gas_price()), + load(input.gas_limit()), + Address(input.to_address()), + load(input.amount()), + load(input.timestamp()), + input.payload()); + auto privateKey = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); signer.sign(privateKey, tx); @@ -34,7 +34,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { return output; } -void Signer::sign(const PrivateKey &privateKey, Transaction &transaction) const noexcept { +void Signer::sign(const PrivateKey& privateKey, Transaction& transaction) const noexcept { transaction.hash = this->hash(transaction); transaction.chainID = chainID; transaction.algorithm = 1; @@ -42,12 +42,12 @@ void Signer::sign(const PrivateKey &privateKey, Transaction &transaction) const transaction.serializeToRaw(); } -Data Signer::hash(const Transaction &transaction) const noexcept { +Data Signer::hash(const Transaction& transaction) const noexcept { auto encoded = Data(); auto payload = Data(); auto* data = Transaction::newPayloadData(transaction.payload); payload.resize(data->ByteSizeLong()); - data->SerializePartialToArray(payload.data(),(int)payload.size()); + data->SerializePartialToArray(payload.data(), (int)payload.size()); delete data; encoded.insert(encoded.end(), transaction.from.bytes.begin(), transaction.from.bytes.end()); @@ -61,3 +61,5 @@ Data Signer::hash(const Transaction &transaction) const noexcept { encode256BE(encoded, transaction.gasLimit, 128); return Hash::sha3_256(encoded); } + +} // namespace TW::Nebulas diff --git a/src/Nebulas/Transaction.cpp b/src/Nebulas/Transaction.cpp index c243e3cd769..ce70cb617da 100644 --- a/src/Nebulas/Transaction.cpp +++ b/src/Nebulas/Transaction.cpp @@ -6,65 +6,73 @@ // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include + #include "Transaction.h" #include "../HexCoding.h" +#include using namespace TW; -using namespace TW::Nebulas; - -const char *Transaction::TxPayloadBinaryType = "binary"; -const char *Transaction::TxPayloadDeployType = "deploy"; -const char *Transaction::TxPayloadCallType = "call"; std::string htmlescape(const std::string& str) { std::string result; - for(size_t i=0; i': result += "\\u003e"; break; - case '<': result += "\\u003c"; break; - case 0x20: - if(i+1 < str.size()) { - if(str[i+1]==0x28) { - result += "\\u2028"; - ++i; - break; - } - else if (str[i+1]==0x29) { - result += "\\u2029"; - ++i; - break; - } + for (size_t i = 0; i < str.size(); ++i) { + switch (str[i]) { + case '&': + result += "\\u0026"; + break; + case '>': + result += "\\u003e"; + break; + case '<': + result += "\\u003c"; + break; + case 0x20: + if (i + 1 < str.size()) { + if (str[i + 1] == 0x28) { + result += "\\u2028"; + ++i; + break; + } else if (str[i + 1] == 0x29) { + result += "\\u2029"; + ++i; + break; } - default: result += str[i]; break; + } + default: + result += str[i]; + break; } } return result; } -Proto::Data* Transaction::newPayloadData(const std::string& payload){ +namespace TW::Nebulas { + +const char* Transaction::TxPayloadBinaryType = "binary"; +const char* Transaction::TxPayloadDeployType = "deploy"; +const char* Transaction::TxPayloadCallType = "call"; + +Proto::Data* Transaction::newPayloadData(const std::string& payload) { auto* data = new Proto::Data(); data->set_type(Transaction::TxPayloadBinaryType); nlohmann::json payloadData; - if(!payload.empty()) { + if (!payload.empty()) { auto json = nlohmann::json::parse(payload); - if(json.find("binary")!=json.end()) { + if (json.find("binary") != json.end()) { std::string binary_data = json["binary"]; - auto buff = Data(binary_data.begin(),binary_data.end()); + auto buff = Data(binary_data.begin(), binary_data.end()); payloadData["Data"]["type"] = "Buffer"; payloadData["Data"]["data"] = nlohmann::json(buff); } } - if(!payloadData.empty()) + if (!payloadData.empty()) data->set_payload(htmlescape(payloadData.dump())); return data; } -void Transaction::serializeToRaw(){ - if(signature.empty()) { +void Transaction::serializeToRaw() { + if (signature.empty()) { throw std::logic_error("The transaction is unsigned!"); } @@ -74,23 +82,25 @@ void Transaction::serializeToRaw(){ auto value = Data(); auto gas_price = Data(); auto gas_limit = Data(); - tx.set_hash(reinterpret_cast(hash.data()),hash.size()); - tx.set_from(from.bytes.data(),from.size); - tx.set_to(to.bytes.data(),to.size); + tx.set_hash(reinterpret_cast(hash.data()), hash.size()); + tx.set_from(from.bytes.data(), from.size); + tx.set_to(to.bytes.data(), to.size); encode256BE(value, amount, 128); - tx.set_value(value.data(),value.size()); + tx.set_value(value.data(), value.size()); tx.set_nonce((uint64_t)nonce); tx.set_timestamp((int64_t)timestamp); tx.set_allocated_data(data); tx.set_chain_id((uint32_t)chainID); encode256BE(gas_price, gasPrice, 128); - tx.set_gas_price(gas_price.data(),gas_price.size()); + tx.set_gas_price(gas_price.data(), gas_price.size()); encode256BE(gas_limit, gasLimit, 128); - tx.set_gas_limit(gas_limit.data(),gas_limit.size()); - + tx.set_gas_limit(gas_limit.data(), gas_limit.size()); + tx.set_alg((uint32_t)algorithm); - tx.set_sign(reinterpret_cast(signature.data()),signature.size()); + tx.set_sign(reinterpret_cast(signature.data()), signature.size()); raw.resize(tx.ByteSizeLong()); - tx.SerializeToArray(raw.data(),(int)raw.size()); -} \ No newline at end of file + tx.SerializeToArray(raw.data(), (int)raw.size()); +} + +} // namespace TW::Nebulas diff --git a/src/Nimiq/Address.cpp b/src/Nimiq/Address.cpp index 458507aa506..a214f586458 100644 --- a/src/Nimiq/Address.cpp +++ b/src/Nimiq/Address.cpp @@ -18,6 +18,8 @@ using namespace TW::Nimiq; +namespace TW::Nimiq { + static const char* BASE32_ALPHABET_NIMIQ = "0123456789ABCDEFGHJKLMNPQRSTUVXY"; static int check_append(int, uint8_t); @@ -150,3 +152,5 @@ static inline int check_add(int check, int num) { ; return (check + num) % 97; } + +} // namespace TW::Nimiq diff --git a/src/Oasis/Address.cpp b/src/Oasis/Address.cpp index af150206a80..ee4102f4d8f 100644 --- a/src/Oasis/Address.cpp +++ b/src/Oasis/Address.cpp @@ -9,19 +9,21 @@ #include #define COIN_ADDRESS_CONTEXT "oasis-core/address: staking" -#define COIN_ADDRESS_VERSION 0 +#define COIN_ADDRESS_VERSION 0 -using namespace TW::Oasis; +namespace TW::Oasis { const std::string Address::hrp = HRP_OASIS; -Address::Address(const Data& keyHash) : Bech32Address(hrp, keyHash) { +Address::Address(const Data& keyHash) + : Bech32Address(hrp, keyHash) { if (getKeyHash().size() != Address::size) { throw std::invalid_argument("invalid address data"); } } -Address::Address(const TW::PublicKey& publicKey) : Bech32Address(hrp){ +Address::Address(const TW::PublicKey& publicKey) + : Bech32Address(hrp) { if (publicKey.type != TWPublicKeyTypeED25519) { throw std::invalid_argument("address may only be an extended ED25519 public key"); } @@ -39,8 +41,9 @@ Address::Address(const TW::PublicKey& publicKey) : Bech32Address(hrp){ setKey(key); } -Address::Address(const std::string& addr) : Bech32Address(addr) { - if(!isValid(addr)) { +Address::Address(const std::string& addr) + : Bech32Address(addr) { + if (!isValid(addr)) { throw std::invalid_argument("invalid address string"); } } @@ -49,3 +52,4 @@ bool Address::isValid(const std::string& addr) { return Bech32Address::isValid(addr, hrp); } +} // namespace TW::Oasis diff --git a/src/Oasis/Entry.cpp b/src/Oasis/Entry.cpp index 9768dd42bb4..3dbaeeb4d24 100644 --- a/src/Oasis/Entry.cpp +++ b/src/Oasis/Entry.cpp @@ -9,9 +9,10 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Oasis; using namespace std; +namespace TW::Oasis { + // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -25,3 +26,5 @@ string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& p void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Oasis diff --git a/src/Oasis/Signer.cpp b/src/Oasis/Signer.cpp index 7babc53ee84..b9263a7d8d9 100644 --- a/src/Oasis/Signer.cpp +++ b/src/Oasis/Signer.cpp @@ -6,14 +6,14 @@ #include -#include "Signer.h" #include "Address.h" +#include "Signer.h" #define TRANSFER_METHOD "staking.Transfer" using namespace TW; -using namespace TW::Oasis; +namespace TW::Oasis { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto output = Proto::SigningOutput(); @@ -40,7 +40,7 @@ Data Signer::build() const { gasAmountStream >> gasAmount; Transaction transaction( - /* to */ address, + /* to */ address, /* method */ TRANSFER_METHOD, /* gasPrice */ input.transfer().gas_price(), /* gasAmount */ gasAmount, @@ -48,7 +48,6 @@ Data Signer::build() const { /* nonce */ input.transfer().nonce(), /* context */ input.transfer().context()); - auto privateKey = PrivateKey(input.private_key()); auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519); @@ -70,3 +69,5 @@ Data Signer::sign(Transaction& tx) const { auto signature = privateKey.sign(hash, TWCurveED25519); return Data(signature.begin(), signature.end()); } + +} // namespace TW::Oasis diff --git a/src/Oasis/Transaction.cpp b/src/Oasis/Transaction.cpp index c2f1cc88ffc..dece41bfb53 100644 --- a/src/Oasis/Transaction.cpp +++ b/src/Oasis/Transaction.cpp @@ -7,7 +7,10 @@ #include "Transaction.h" using namespace TW; -using namespace TW::Oasis; + +namespace TW::Oasis { + +// clang-format off // encodeVaruint encodes a 256-bit number into a big endian encoding, omitting leading zeros. static Data encodeVaruint(const uint256_t& value) { @@ -56,3 +59,7 @@ Data Transaction::serialize(Data& signature, PublicKey& publicKey) const { }); return signedMessage.encoded(); } + +// clang-format on + +} // namespace TW::Oasis diff --git a/src/Ontology/Address.cpp b/src/Ontology/Address.cpp index 76bd96365ef..9167c9eebf9 100644 --- a/src/Ontology/Address.cpp +++ b/src/Ontology/Address.cpp @@ -16,7 +16,8 @@ #include using namespace TW; -using namespace TW::Ontology; + +namespace TW::Ontology { Address::Address(const PublicKey& publicKey) { std::vector builder(publicKey.bytes); @@ -71,3 +72,5 @@ std::string Address::string() const { (int)b58StrSize + 1); return b58Str; } + +} // namespace TW::Ontology diff --git a/src/Ripple/Address.cpp b/src/Ripple/Address.cpp index 4f4a601f775..bd139a932cb 100644 --- a/src/Ripple/Address.cpp +++ b/src/Ripple/Address.cpp @@ -10,6 +10,8 @@ using namespace TW::Ripple; +namespace TW::Ripple { + bool Address::isValid(const std::string& string) { const auto decoded = Base58::ripple.decodeCheck(string); if (decoded.size() != Address::size) { @@ -35,3 +37,5 @@ Address::Address(const PublicKey& publicKey) { std::string Address::string() const { return Base58::ripple.encodeCheck(bytes); } + +} // namespace TW::Ripple diff --git a/src/Ronin/Address.cpp b/src/Ronin/Address.cpp index c6699436413..74555fb553a 100644 --- a/src/Ronin/Address.cpp +++ b/src/Ronin/Address.cpp @@ -11,7 +11,8 @@ #include "../HexCoding.h" const std::string prefix = "ronin:"; -using namespace TW::Ronin; + +namespace TW::Ronin { bool Address::isValid(const std::string& string) { // check prefix @@ -45,6 +46,10 @@ Address::Address(const std::string& string) { // Normalized: with ronin prefix, checksummed hex address, no 0x prefix std::string Address::string() const { std::string address = Ethereum::checksumed(*this); - if (address.size() >= 2 && address.substr(0, 2) == "0x") { address = address.substr(2); } // skip 0x + if (address.size() >= 2 && address.substr(0, 2) == "0x") { + address = address.substr(2); + } // skip 0x return prefix + address; } + +} // namespace TW::Ronin diff --git a/src/Ronin/Entry.cpp b/src/Ronin/Entry.cpp index 61384ad8737..d69ac356390 100644 --- a/src/Ronin/Entry.cpp +++ b/src/Ronin/Entry.cpp @@ -9,10 +9,11 @@ #include "Address.h" #include "../Ethereum/Signer.h" -using namespace TW::Ronin; using namespace TW; using namespace std; +namespace TW::Ronin { + bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } @@ -37,3 +38,5 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Ethereum::Signer::signJSON(json, key); } + +} // namespace TW::Ronin diff --git a/src/Solana/Address.cpp b/src/Solana/Address.cpp index c8a633eb853..3e4f77cface 100644 --- a/src/Solana/Address.cpp +++ b/src/Solana/Address.cpp @@ -5,8 +5,8 @@ // file LICENSE at the root of the source code distribution tree. #include "Address.h" -#include "Transaction.h" #include "Program.h" +#include "Transaction.h" #include "../Base58.h" #include "../Base58Address.h" #include "../Hash.h" @@ -16,7 +16,8 @@ #include using namespace TW; -using namespace TW::Solana; + +namespace TW::Solana { bool Address::isValid(const std::string& string) { const auto data = Base58::bitcoin.decode(string); @@ -58,3 +59,5 @@ Data Address::vector() const { Address Address::defaultTokenAddress(const Address& tokenMintAddress) { return TokenProgram::defaultTokenAddress(*this, tokenMintAddress); } + +} // namespace TW::Solana diff --git a/src/Solana/Entry.cpp b/src/Solana/Entry.cpp index ae9ef3e4e26..765c9c1927f 100644 --- a/src/Solana/Entry.cpp +++ b/src/Solana/Entry.cpp @@ -9,10 +9,11 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Solana; using namespace TW; using namespace std; +namespace TW::Solana { + // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -34,3 +35,5 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } + +} // namespace TW::Solana diff --git a/src/Stellar/Address.cpp b/src/Stellar/Address.cpp index c7197b89451..84b99a62bae 100644 --- a/src/Stellar/Address.cpp +++ b/src/Stellar/Address.cpp @@ -5,9 +5,9 @@ // file LICENSE at the root of the source code distribution tree. #include "Address.h" +#include "Crc.h" #include "../Base32.h" #include "../HexCoding.h" -#include "Crc.h" #include #include @@ -15,7 +15,7 @@ #include #include -using namespace TW::Stellar; +namespace TW::Stellar { bool Address::isValid(const std::string& string) { bool valid = false; @@ -82,3 +82,5 @@ std::string Address::string() const { auto out = Base32::encode(bytesAsData); return out; } + +} // namespace TW::Stellar diff --git a/src/Stellar/Signer.cpp b/src/Stellar/Signer.cpp index a2e78a25e7f..5d48a71551b 100644 --- a/src/Stellar/Signer.cpp +++ b/src/Stellar/Signer.cpp @@ -4,8 +4,8 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Base64.h" #include "Signer.h" +#include "Base64.h" #include "../BinaryCoding.h" #include "../Hash.h" #include "../HexCoding.h" @@ -14,8 +14,8 @@ #include using namespace TW; -using namespace TW::Stellar; +namespace TW::Stellar { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto signer = Signer(input); auto output = Proto::SigningOutput(); @@ -64,7 +64,7 @@ Data Signer::encode(const Proto::SigningInput& input) const { // Time bounds if (input.has_op_change_trust() && input.op_change_trust().valid_before() != 0) { encode32BE(1, data); - encode64BE(0, data); // from + encode64BE(0, data); // from encode64BE(input.op_change_trust().valid_before(), data); // to } else { encode32BE(0, data); // missing @@ -91,55 +91,51 @@ Data Signer::encode(const Proto::SigningInput& input) const { } // Operations - encode32BE(1, data); // Operation list size. Only 1 operation. - encode32BE(0, data); // Source equals account + encode32BE(1, data); // Operation list size. Only 1 operation. + encode32BE(0, data); // Source equals account encode32BE(operationType(input), data); // Operation type switch (input.operation_oneof_case()) { - case Proto::SigningInput::kOpCreateAccount: - default: - encodeAddress(Address(input.op_create_account().destination()), data); - encode64BE(input.op_create_account().amount(), data); - break; - - case Proto::SigningInput::kOpPayment: - encodeAddress(Address(input.op_payment().destination()), data); - encodeAsset(input.op_payment().asset(), data); - encode64BE(input.op_payment().amount(), data); - break; - - case Proto::SigningInput::kOpChangeTrust: - encodeAsset(input.op_change_trust().asset(), data); - encode64BE(0x7fffffffffffffff, data); // limit MAX - break; - - case Proto::SigningInput::kOpCreateClaimableBalance: - { - const auto ClaimantTypeV0 = 0; - encodeAsset(input.op_create_claimable_balance().asset(), data); - encode64BE(input.op_create_claimable_balance().amount(), data); - auto nClaimants = input.op_create_claimable_balance().claimants_size(); - encode32BE((uint32_t)nClaimants, data); - for (auto i = 0; i < nClaimants; ++i) { - encode32BE((uint32_t)ClaimantTypeV0, data); - encodeAddress(Address(input.op_create_claimable_balance().claimants(i).account()), data); - encode32BE((uint32_t)input.op_create_claimable_balance().claimants(i).predicate(), data); - // Note: other predicates not supported, predicate-specific data would follow here - } - } - break; - - case Proto::SigningInput::kOpClaimClaimableBalance: - { - const auto ClaimableBalanceIdTypeClaimableBalanceIdTypeV0 = 0; - encode32BE((uint32_t)ClaimableBalanceIdTypeClaimableBalanceIdTypeV0, data); - const auto balanceId = input.op_claim_claimable_balance().balance_id(); - if (balanceId.size() != 32) { - return Data(); - } - data.insert(data.end(), balanceId.begin(), balanceId.end()); - } - break; + case Proto::SigningInput::kOpCreateAccount: + default: + encodeAddress(Address(input.op_create_account().destination()), data); + encode64BE(input.op_create_account().amount(), data); + break; + + case Proto::SigningInput::kOpPayment: + encodeAddress(Address(input.op_payment().destination()), data); + encodeAsset(input.op_payment().asset(), data); + encode64BE(input.op_payment().amount(), data); + break; + + case Proto::SigningInput::kOpChangeTrust: + encodeAsset(input.op_change_trust().asset(), data); + encode64BE(0x7fffffffffffffff, data); // limit MAX + break; + + case Proto::SigningInput::kOpCreateClaimableBalance: { + const auto ClaimantTypeV0 = 0; + encodeAsset(input.op_create_claimable_balance().asset(), data); + encode64BE(input.op_create_claimable_balance().amount(), data); + auto nClaimants = input.op_create_claimable_balance().claimants_size(); + encode32BE((uint32_t)nClaimants, data); + for (auto i = 0; i < nClaimants; ++i) { + encode32BE((uint32_t)ClaimantTypeV0, data); + encodeAddress(Address(input.op_create_claimable_balance().claimants(i).account()), data); + encode32BE((uint32_t)input.op_create_claimable_balance().claimants(i).predicate(), data); + // Note: other predicates not supported, predicate-specific data would follow here + } + } break; + + case Proto::SigningInput::kOpClaimClaimableBalance: { + const auto ClaimableBalanceIdTypeClaimableBalanceIdTypeV0 = 0; + encode32BE((uint32_t)ClaimableBalanceIdTypeClaimableBalanceIdTypeV0, data); + const auto balanceId = input.op_claim_claimable_balance().balance_id(); + if (balanceId.size() != 32) { + return Data(); + } + data.insert(data.end(), balanceId.begin(), balanceId.end()); + } break; } encode32BE(0, data); // Ext @@ -148,17 +144,17 @@ Data Signer::encode(const Proto::SigningInput& input) const { uint32_t Signer::operationType(const Proto::SigningInput& input) { switch (input.operation_oneof_case()) { - case Proto::SigningInput::kOpCreateAccount: - default: - return 0; - case Proto::SigningInput::kOpPayment: - return 1; - case Proto::SigningInput::kOpChangeTrust: - return 6; - case Proto::SigningInput::kOpCreateClaimableBalance: - return 14; - case Proto::SigningInput::kOpClaimClaimableBalance: - return 15; + case Proto::SigningInput::kOpCreateAccount: + default: + return 0; + case Proto::SigningInput::kOpPayment: + return 1; + case Proto::SigningInput::kOpChangeTrust: + return 6; + case Proto::SigningInput::kOpCreateClaimableBalance: + return 14; + case Proto::SigningInput::kOpClaimClaimableBalance: + return 15; } } @@ -197,3 +193,5 @@ void Signer::pad(Data& data) const { data.insert(data.end(), 0); } } + +} // namespace TW::Stellar diff --git a/src/THORChain/Entry.cpp b/src/THORChain/Entry.cpp index 1fb86e7cbff..02c1d4f97c0 100644 --- a/src/THORChain/Entry.cpp +++ b/src/THORChain/Entry.cpp @@ -9,9 +9,10 @@ #include "Signer.h" #include "../proto/Cosmos.pb.h" -using namespace TW::THORChain; using namespace std; +namespace TW::THORChain { + // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { @@ -24,3 +25,5 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } + +} // namespace TW::THORChain diff --git a/src/THORChain/Signer.cpp b/src/THORChain/Signer.cpp index fa79a09404a..30ebb84217b 100644 --- a/src/THORChain/Signer.cpp +++ b/src/THORChain/Signer.cpp @@ -8,12 +8,12 @@ #include "../Cosmos/Signer.h" #include "../proto/Cosmos.pb.h" -#include #include +#include using namespace TW; -using namespace TW::THORChain; +namespace TW::THORChain { const std::string TYPE_PREFIX_MSG_SEND = "thorchain/MsgSend"; Cosmos::Proto::SigningOutput Signer::sign(Cosmos::Proto::SigningInput& input) noexcept { @@ -32,3 +32,5 @@ std::string Signer::signJSON(const std::string& json, const Data& key) { auto output = Signer::sign(input); return output.json(); } + +} // namespace TW::THORChain diff --git a/src/Tezos/Forging.cpp b/src/Tezos/Forging.cpp index 52ad9a31fe6..91f33014410 100644 --- a/src/Tezos/Forging.cpp +++ b/src/Tezos/Forging.cpp @@ -63,10 +63,10 @@ Data forgePublicKey(PublicKey publicKey) { Data forgeZarith(uint64_t input) { Data forged = Data(); while (input >= 0x80) { - forged.push_back(static_cast((input & 0xff) | 0x80)); + forged.push_back(static_cast((input & 0xff) | 0x80)); input >>= 7; } - forged.push_back(static_cast(input)); + forged.push_back(static_cast(input)); return forged; } @@ -83,7 +83,7 @@ Data forgeOperation(const Operation& operation) { if (operation.kind() == Operation_OperationKind_REVEAL) { auto publicKey = PublicKey(data(operation.reveal_operation_data().public_key()), TWPublicKeyTypeED25519); auto forgedPublicKey = forgePublicKey(publicKey); - + forged.push_back(Operation_OperationKind_REVEAL); append(forged, forgedSource); append(forged, forgedFee); diff --git a/src/Tezos/Signer.cpp b/src/Tezos/Signer.cpp index b0732fd78c9..c695827b2cb 100644 --- a/src/Tezos/Signer.cpp +++ b/src/Tezos/Signer.cpp @@ -4,8 +4,8 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "OperationList.h" #include "Signer.h" +#include "OperationList.h" #include "../Hash.h" #include "../HexCoding.h" @@ -15,12 +15,13 @@ #include using namespace TW; -using namespace TW::Tezos; + +namespace TW::Tezos { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto operationList = Tezos::OperationList(input.operation_list().branch()); for (Proto::Operation operation : input.operation_list().operations()) { - operationList.addOperation(operation); + operationList.addOperation(operation); } auto signer = Signer(); @@ -58,3 +59,5 @@ Data Signer::signData(const PrivateKey& privateKey, const Data& data) { append(signedData, signature); return signedData; } + +} // namespace TW::Tezos diff --git a/src/Tron/Entry.cpp b/src/Tron/Entry.cpp index 5daceac1b61..056728c4bc6 100644 --- a/src/Tron/Entry.cpp +++ b/src/Tron/Entry.cpp @@ -9,9 +9,9 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Tron; using namespace std; +namespace TW::Tron { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -25,3 +25,5 @@ string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& p void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Tron diff --git a/src/VeChain/Signer.cpp b/src/VeChain/Signer.cpp index 3b12d7818bd..7cbfd00d333 100644 --- a/src/VeChain/Signer.cpp +++ b/src/VeChain/Signer.cpp @@ -9,7 +9,8 @@ #include "../Hash.h" using namespace TW; -using namespace TW::VeChain; + +namespace TW::VeChain { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); @@ -41,3 +42,5 @@ Data Signer::sign(const PrivateKey& privateKey, Transaction& transaction) noexce auto signature = privateKey.sign(hash, TWCurveSECP256k1); return Data(signature.begin(), signature.end()); } + +} // namespace TW::VeChain diff --git a/src/Waves/Entry.cpp b/src/Waves/Entry.cpp index cb84f452cb7..1886c93248b 100644 --- a/src/Waves/Entry.cpp +++ b/src/Waves/Entry.cpp @@ -12,6 +12,8 @@ using namespace TW::Waves; using namespace std; +namespace TW::Waves { + // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -25,3 +27,5 @@ string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& p void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Waves diff --git a/src/Waves/Signer.cpp b/src/Waves/Signer.cpp index 701d47e869b..93716de50d4 100644 --- a/src/Waves/Signer.cpp +++ b/src/Waves/Signer.cpp @@ -9,7 +9,8 @@ #include "../Hash.h" using namespace TW; -using namespace TW::Waves; + +namespace TW::Waves { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto privateKey = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); @@ -19,12 +20,12 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { Data signature = Signer::sign(privateKey, transaction); Proto::SigningOutput output = Proto::SigningOutput(); - output.set_signature(reinterpret_cast(signature.data()), signature.size()); + output.set_signature(reinterpret_cast(signature.data()), signature.size()); output.set_json(transaction.buildJson(signature).dump()); return output; } -Data Signer::sign(const PrivateKey &privateKey, Transaction &transaction) noexcept { +Data Signer::sign(const PrivateKey& privateKey, Transaction& transaction) noexcept { try { auto bytesToSign = transaction.serializeToSign(); auto signature = privateKey.sign(bytesToSign, TWCurveCurve25519); @@ -33,3 +34,5 @@ Data Signer::sign(const PrivateKey &privateKey, Transaction &transaction) noexce return Data(); } } + +} // namespace TW::Waves diff --git a/src/Waves/Transaction.cpp b/src/Waves/Transaction.cpp index ee9d2a5af44..36ac5cb3447 100644 --- a/src/Waves/Transaction.cpp +++ b/src/Waves/Transaction.cpp @@ -11,7 +11,8 @@ #include "../HexCoding.h" using namespace TW; -using namespace TW::Waves; + +namespace TW::Waves { using json = nlohmann::json; @@ -20,7 +21,7 @@ const std::string Transaction::WAVES = "WAVES"; Data serializeTransfer(int64_t amount, std::string asset, int64_t fee, std::string fee_asset, Address to, const Data& attachment, int64_t timestamp, const Data& pub_key) { auto data = Data(); if (asset.empty()) { - asset = Transaction::WAVES; + asset = Transaction::WAVES; } if (fee_asset.empty()) { fee_asset = Transaction::WAVES; @@ -46,7 +47,7 @@ Data serializeTransfer(int64_t amount, std::string asset, int64_t fee, std::stri encode64BE(fee, data); append(data, Data(std::begin(to.bytes), std::end(to.bytes))); encodeDynamicLengthBytes(attachment, data); - + return data; } @@ -61,7 +62,7 @@ Data serializeLease(int64_t amount, int64_t fee, Address to, int64_t timestamp, encode64BE(amount, data); encode64BE(fee, data); encode64BE(timestamp, data); - + return data; } @@ -75,13 +76,13 @@ Data serializeCancelLease(const Data& leaseId, int64_t fee, int64_t timestamp, c encode64BE(fee, data); encode64BE(timestamp, data); append(data, leaseId); - + return data; } json jsonTransfer(const Data& signature, int64_t amount, const std::string& asset, int64_t fee, const std::string& fee_asset, Address to, const Data& attachment, int64_t timestamp, const Data& pub_key) { json jsonTx; - + jsonTx["type"] = TransactionType::transfer; jsonTx["version"] = TransactionVersion::V2; jsonTx["fee"] = fee; @@ -97,13 +98,13 @@ json jsonTransfer(const Data& signature, int64_t amount, const std::string& asse } jsonTx["amount"] = amount; jsonTx["attachment"] = Base58::bitcoin.encode(attachment); - + return jsonTx; } json jsonLease(const Data& signature, int64_t amount, int64_t fee, Address to, int64_t timestamp, const Data& pub_key) { json jsonTx; - + jsonTx["type"] = TransactionType::lease; jsonTx["version"] = TransactionVersion::V2; jsonTx["fee"] = fee; @@ -112,13 +113,13 @@ json jsonLease(const Data& signature, int64_t amount, int64_t fee, Address to, i jsonTx["proofs"] = json::array({Base58::bitcoin.encode(signature)}); jsonTx["recipient"] = Address(to).string(); jsonTx["amount"] = amount; - + return jsonTx; } json jsonCancelLease(const Data& signature, const Data& leaseId, int64_t fee, int64_t timestamp, const Data& pub_key) { json jsonTx; - + jsonTx["type"] = TransactionType::cancelLease; jsonTx["version"] = TransactionVersion::V2; jsonTx["fee"] = fee; @@ -127,7 +128,7 @@ json jsonCancelLease(const Data& signature, const Data& leaseId, int64_t fee, in jsonTx["chainId"] = 87; // mainnet jsonTx["timestamp"] = timestamp; jsonTx["proofs"] = json::array({Base58::bitcoin.encode(signature)}); - + return jsonTx; } @@ -154,49 +155,44 @@ Data Transaction::serializeToSign() const { auto leaseId = Base58::bitcoin.decode(message.lease_id()); return serializeCancelLease(leaseId, message.fee(), input.timestamp(), pub_key); } - + return Data(); } - - - - json Transaction::buildJson(const Data& signature) const { if (input.has_transfer_message()) { auto message = input.transfer_message(); auto attachment = Data(message.attachment().begin(), message.attachment().end()); return jsonTransfer( - signature, - message.amount(), - message.asset(), - message.fee(), - message.fee_asset(), - Address(message.to()), - attachment, - input.timestamp(), - pub_key); + signature, + message.amount(), + message.asset(), + message.fee(), + message.fee_asset(), + Address(message.to()), + attachment, + input.timestamp(), + pub_key); } else if (input.has_lease_message()) { auto message = input.lease_message(); return jsonLease( - signature, - message.amount(), - message.fee(), - Address(message.to()), - input.timestamp(), - pub_key); + signature, + message.amount(), + message.fee(), + Address(message.to()), + input.timestamp(), + pub_key); } else if (input.has_cancel_lease_message()) { auto message = input.cancel_lease_message(); auto leaseId = Base58::bitcoin.decode(message.lease_id()); return jsonCancelLease( - signature, - leaseId, - message.fee(), - input.timestamp(), - pub_key); + signature, + leaseId, + message.fee(), + input.timestamp(), + pub_key); } return nullptr; } - - +} // namespace TW::Waves diff --git a/src/Zcash/Transaction.cpp b/src/Zcash/Transaction.cpp index c12bab72c0c..20ac5669afb 100644 --- a/src/Zcash/Transaction.cpp +++ b/src/Zcash/Transaction.cpp @@ -25,9 +25,9 @@ const auto shieldedSpendHashPersonalization = Data({'Z','c','a','s','h','S','S', const auto shieldedOutputsHashPersonalization = Data({'Z','c','a','s','h','S','O','u','t','p','u','t','H','a','s','h'}); /// See https://github.com/zcash/zips/blob/master/zip-0205.rst#sapling-deployment BRANCH_ID section -const std::array Zcash::SaplingBranchID = {0xbb, 0x09, 0xb8, 0x76}; +const std::array Zcash::SaplingBranchID = {0xbb, 0x09, 0xb8, 0x76}; /// See https://github.com/zcash/zips/blob/master/zip-0206.rst#blossom-deployment BRANCH_ID section -const std::array Zcash::BlossomBranchID = {0x60, 0x0e, 0xb4, 0x2b}; +const std::array Zcash::BlossomBranchID = {0x60, 0x0e, 0xb4, 0x2b}; Data Transaction::getPreImage(const Bitcoin::Script& scriptCode, size_t index, enum TWBitcoinSigHashType hashType, uint64_t amount) const { diff --git a/src/Zilliqa/Entry.cpp b/src/Zilliqa/Entry.cpp index b005e72a5d9..ca66e3637bd 100644 --- a/src/Zilliqa/Entry.cpp +++ b/src/Zilliqa/Entry.cpp @@ -9,10 +9,11 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Zilliqa; using namespace TW; using namespace std; +namespace TW::Zilliqa { + // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -39,3 +40,5 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } + +} // namespace TW::Zilliqa diff --git a/src/interface/TWGroestlcoinAddress.cpp b/src/interface/TWGroestlcoinAddress.cpp index 11d28b4780a..e825cc591f1 100644 --- a/src/interface/TWGroestlcoinAddress.cpp +++ b/src/interface/TWGroestlcoinAddress.cpp @@ -11,34 +11,32 @@ #include -using namespace TW::Groestlcoin; - -bool TWGroestlcoinAddressEqual(struct TWGroestlcoinAddress *_Nonnull lhs, struct TWGroestlcoinAddress *_Nonnull rhs) { +bool TWGroestlcoinAddressEqual(struct TWGroestlcoinAddress* _Nonnull lhs, struct TWGroestlcoinAddress* _Nonnull rhs) { return lhs->impl.bytes == rhs->impl.bytes; } -bool TWGroestlcoinAddressIsValidString(TWString *_Nonnull string) { +bool TWGroestlcoinAddressIsValidString(TWString* _Nonnull string) { auto& s = *reinterpret_cast(string); - return Address::isValid(s); + return TW::Groestlcoin::Address::isValid(s); } -struct TWGroestlcoinAddress *_Nullable TWGroestlcoinAddressCreateWithString(TWString *_Nonnull string) { +struct TWGroestlcoinAddress* _Nullable TWGroestlcoinAddressCreateWithString(TWString* _Nonnull string) { auto& s = *reinterpret_cast(string); - if (!Address::isValid(s)) { + if (!TW::Groestlcoin::Address::isValid(s)) { return nullptr; } - return new TWGroestlcoinAddress{ Address(s) }; + return new TWGroestlcoinAddress{TW::Groestlcoin::Address(s)}; } -struct TWGroestlcoinAddress *_Nonnull TWGroestlcoinAddressCreateWithPublicKey(struct TWPublicKey *_Nonnull publicKey, uint8_t prefix) { - return new TWGroestlcoinAddress{ Address(publicKey->impl, prefix) }; +struct TWGroestlcoinAddress* _Nonnull TWGroestlcoinAddressCreateWithPublicKey(struct TWPublicKey* _Nonnull publicKey, uint8_t prefix) { + return new TWGroestlcoinAddress{TW::Groestlcoin::Address(publicKey->impl, prefix)}; } -void TWGroestlcoinAddressDelete(struct TWGroestlcoinAddress *_Nonnull address) { +void TWGroestlcoinAddressDelete(struct TWGroestlcoinAddress* _Nonnull address) { delete address; } -TWString *_Nonnull TWGroestlcoinAddressDescription(struct TWGroestlcoinAddress *_Nonnull address) { +TWString* _Nonnull TWGroestlcoinAddressDescription(struct TWGroestlcoinAddress* _Nonnull address) { const auto str = address->impl.string(); return TWStringCreateWithUTF8Bytes(str.c_str()); } diff --git a/src/interface/TWSolanaAddress.cpp b/src/interface/TWSolanaAddress.cpp index 023b9033ed8..df311698057 100644 --- a/src/interface/TWSolanaAddress.cpp +++ b/src/interface/TWSolanaAddress.cpp @@ -4,27 +4,26 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include #include "Solana/Address.h" +#include -using namespace TW::Solana; using namespace TW; struct TWSolanaAddress* _Nullable TWSolanaAddressCreateWithString(TWString* _Nonnull string) { auto& str = *reinterpret_cast(string); - return new TWSolanaAddress{Address(str)}; + return new TWSolanaAddress{Solana::Address(str)}; } void TWSolanaAddressDelete(struct TWSolanaAddress* _Nonnull address) { delete address; } -TWString *_Nullable TWSolanaAddressDefaultTokenAddress(struct TWSolanaAddress* _Nonnull address, TWString* _Nonnull tokenMintAddress) { +TWString* _Nullable TWSolanaAddressDefaultTokenAddress(struct TWSolanaAddress* _Nonnull address, TWString* _Nonnull tokenMintAddress) { try { if (address == nullptr || tokenMintAddress == nullptr) { return nullptr; } - Address tokenMint = Address(TWStringUTF8Bytes(tokenMintAddress)); + Solana::Address tokenMint = Solana::Address(TWStringUTF8Bytes(tokenMintAddress)); std::string defaultAddress = address->impl.defaultTokenAddress(tokenMint).string(); return TWStringCreateWithUTF8Bytes(defaultAddress.c_str()); } catch (...) { diff --git a/src/proto/.clang-tidy b/src/proto/.clang-tidy new file mode 100644 index 00000000000..2c22f7387dd --- /dev/null +++ b/src/proto/.clang-tidy @@ -0,0 +1,6 @@ +--- +InheritParentConfig: false +Checks: '-*,misc-definitions-in-headers' +CheckOptions: + - { key: HeaderFileExtensions, value: "x" } +... diff --git a/tests/Aeternity/TransactionTests.cpp b/tests/Aeternity/TransactionTests.cpp index 025eb2dc056..384216ba3e4 100644 --- a/tests/Aeternity/TransactionTests.cpp +++ b/tests/Aeternity/TransactionTests.cpp @@ -4,8 +4,6 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Aeternity/Address.cpp" -#include "Aeternity/Transaction.cpp" #include "HexCoding.h" #include "PrivateKey.h" #include "../interface/TWTestUtilities.h" @@ -14,6 +12,8 @@ #include #include +using namespace TW::Aeternity; + TEST(AeternityTransaction, EncodeRlp) { std::string sender_id = "ak_2a1j2Mk9YSmC1gioUq4PWRm3bsv887MbuRVwyv4KaUGoR1eiKi"; std::string recipient_id = "ak_Egp9yVdpxmvAfQ7vsXGvpnyfNq71msbdUpkMNYGTeTe8kPL3v"; @@ -25,7 +25,7 @@ TEST(AeternityTransaction, EncodeRlp) { auto tx = Transaction(sender_id, recipient_id, amount, fee, payload, ttl, nonce); auto encodedTx = tx.encode(); - auto encodedTxHex = hex(encodedTx); + auto encodedTxHex = TW::hex(encodedTx); ASSERT_EQ(encodedTxHex, "f85f0c01a101cea7ade470c9f99d9d4e400880a86f1d49bb444b62f11a9ebb64bbcfeb73fef3a1011f13a3b08bf001400662a68b69d875f7803cec4c08647f6ed5d84c7897bd50a30a8612309ce5400083014345318b48656c6c6f20576f726c64"); } @@ -41,7 +41,7 @@ TEST(AeternityTransaction, EncodeRlpWithZeroAmount) { auto tx = Transaction(sender_id, recipient_id, amount, fee, payload, ttl, nonce); auto encodedTx = tx.encode(); - auto encodedTxHex = hex(encodedTx); + auto encodedTxHex = TW::hex(encodedTx); ASSERT_EQ(encodedTxHex, "f85f0c01a101cea7ade470c9f99d9d4e400880a86f1d49bb444b62f11a9ebb64bbcfeb73fef3a1011f13a3b08bf001400662a68b69d875f7803cec4c08647f6ed5d84c7897bd50a3008612309ce5400083014345318b48656c6c6f20576f726c64"); } @@ -57,7 +57,7 @@ TEST(AeternityTransaction, EncodeRlpWithZeroTtl) { auto tx = Transaction(sender_id, recipient_id, amount, fee, payload, ttl, nonce); auto encodedTx = tx.encode(); - auto encodedTxHex = hex(encodedTx); + auto encodedTxHex = TW::hex(encodedTx); ASSERT_EQ(encodedTxHex, "f85c0c01a101cea7ade470c9f99d9d4e400880a86f1d49bb444b62f11a9ebb64bbcfeb73fef3a1011f13a3b08bf001400662a68b69d875f7803cec4c08647f6ed5d84c7897bd50a30a8612309ce5400000318b48656c6c6f20576f726c64"); } diff --git a/tests/Aion/AddressTests.cpp b/tests/Aion/AddressTests.cpp index 5942e0ce0b6..05f37edb64e 100644 --- a/tests/Aion/AddressTests.cpp +++ b/tests/Aion/AddressTests.cpp @@ -10,7 +10,8 @@ #include using namespace TW; -using namespace TW::Aion; + +namespace TW::Aion::tests { TEST(AionAddress, FromPublicKey) { auto publicKey = PublicKey(parse_hex("01a775daa30b33fda3091768f0561c8042ee23cb48a6a3e5d7e8248b13d04a48a7"), TWPublicKeyTypeED25519); @@ -31,3 +32,5 @@ TEST(AionAddress, isValid) { ASSERT_TRUE(Address::isValid(validAddress)); ASSERT_FALSE(Address::isValid(invalidAddress)); } + +} // namespace TW::Aion::tests diff --git a/tests/Algorand/AddressTests.cpp b/tests/Algorand/AddressTests.cpp index 0ed495d060e..6edff289604 100644 --- a/tests/Algorand/AddressTests.cpp +++ b/tests/Algorand/AddressTests.cpp @@ -4,15 +4,16 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "HexCoding.h" #include "Algorand/Address.h" -#include "PublicKey.h" +#include "HexCoding.h" #include "PrivateKey.h" +#include "PublicKey.h" #include #include using namespace TW; -using namespace TW::Algorand; + +namespace TW::Algorand::tests { TEST(AlgorandAddress, Validation) { // empty address @@ -43,3 +44,5 @@ TEST(AlgorandAddress, FromString) { auto address = Address("PITDOF57RHOVLT37KM7DCXDCETLDL3OA5CBAN7LQ44Z36LGFC27IJ2IQ64"); ASSERT_EQ(address.string(), "PITDOF57RHOVLT37KM7DCXDCETLDL3OA5CBAN7LQ44Z36LGFC27IJ2IQ64"); } + +} // namespace TW::Algorand::tests diff --git a/tests/Algorand/SignerTests.cpp b/tests/Algorand/SignerTests.cpp index f9cfcecb2bf..d3efef06418 100644 --- a/tests/Algorand/SignerTests.cpp +++ b/tests/Algorand/SignerTests.cpp @@ -5,17 +5,18 @@ // file LICENSE at the root of the source code distribution tree. #include "Algorand/Address.h" -#include "Algorand/Signer.h" #include "Algorand/BinaryCoding.h" -#include "HexCoding.h" +#include "Algorand/Signer.h" #include "Base64.h" +#include "HexCoding.h" #include "PrivateKey.h" #include "PublicKey.h" #include #include using namespace TW; -using namespace TW::Algorand; + +namespace TW::Algorand::tests { TEST(AlgorandSigner, EncodeNumbers) { auto tests = { @@ -39,9 +40,7 @@ TEST(AlgorandSigner, EncodeStrings) { std::make_tuple("It's like JSON. but fast and small.", "d92349742773206c696b65204a534f4e2e20627574206661737420616e6420736d616c6c2e"), std::make_tuple( "MessagePack is an efficient binary serialization format. It lets you exchange data among multiple languages like JSON. But it's faster and smaller. Small integers are encoded into a single byte, and typical short strings require only one extra byte in addition to the strings themselves.", - "da011f4d6573736167655061636b20697320616e20656666696369656e742062696e6172792073657269616c697a6174696f6e20666f726d61742e204974206c65747320796f752065786368616e6765206461746120616d6f6e67206d756c7469706c65206c616e677561676573206c696b65204a534f4e2e2042757420697427732066617374657220616e6420736d616c6c65722e20536d616c6c20696e7465676572732061726520656e636f64656420696e746f20612073696e676c6520627974652c20616e64207479706963616c2073686f727420737472696e67732072657175697265206f6e6c79206f6e65206578747261206279746520696e206164646974696f6e20746f2074686520737472696e6773207468656d73656c7665732e" - ) - }; + "da011f4d6573736167655061636b20697320616e20656666696369656e742062696e6172792073657269616c697a6174696f6e20666f726d61742e204974206c65747320796f752065786368616e6765206461746120616d6f6e67206d756c7469706c65206c616e677561676573206c696b65204a534f4e2e2042757420697427732066617374657220616e6420736d616c6c65722e20536d616c6c20696e7465676572732061726520656e636f64656420696e746f20612073696e676c6520627974652c20616e64207479706963616c2073686f727420737472696e67732072657175697265206f6e6c79206f6e65206578747261206279746520696e206164646974696f6e20746f2074686520737472696e6773207468656d73656c7665732e")}; for (auto& test : tests) { Data data; @@ -75,8 +74,7 @@ TEST(AlgorandSigner, Sign) { /* note */ note, /* type */ "pay", /* genesis id*/ genesisId, - /* genesis hash*/ genesisHash - ); + /* genesis hash*/ genesisHash); auto serialized = transaction.serialize(); auto signature = Signer::sign(key, transaction); @@ -101,14 +99,13 @@ TEST(AlgorandSigner, SignAsset) { /* to */ to, /* fee */ 2340, /* amount */ 1000000, - /* asset id */13379146, + /* asset id */ 13379146, /* first round */ 15775683, /* last round */ 15776683, /* note */ note, /* type */ "axfer", /* genesis id*/ genesisId, - /* genesis hash*/ genesisHash - ); + /* genesis hash*/ genesisHash); auto serialized = transaction.serialize(); auto signature = Signer::sign(key, transaction); @@ -130,14 +127,13 @@ TEST(AlgorandSigner, SignAssetOptIn) { auto transaction = OptInAssetTransaction( /* from */ address, /* fee */ 2340, - /* asset id */13379146, + /* asset id */ 13379146, /* first round */ 15775553, /* last round */ 15776553, /* note */ note, /* type */ "axfer", /* genesis id*/ genesisId, - /* genesis hash*/ genesisHash - ); + /* genesis hash*/ genesisHash); auto serialized = transaction.serialize(); auto signature = Signer::sign(key, transaction); @@ -151,7 +147,7 @@ TEST(AlgorandSigner, SignAssetOptIn) { TEST(AlgorandSigner, ProtoSignerOptIn) { // https://testnet.algoexplorer.io/tx/47LE2QS4B5N6IFHXOUN2MJUTCOQCHNY6AB3AJYECK4IM2VYKJDKQ auto optIn = new Proto::AssetOptIn(); - optIn -> set_asset_id(13379146); + optIn->set_asset_id(13379146); auto privateKey = parse_hex("5a6a3cfe5ff4cc44c19381d15a0d16de2a76ee5c9b9d83b232e38cb5a2c84b04"); @@ -175,9 +171,9 @@ TEST(AlgorandSigner, ProtoSignerOptIn) { TEST(AlgorandSigner, ProtoSignerAssetTransaction) { // https://testnet.algoexplorer.io/tx/NJ62HYO2LC222AVLIN2GW5LKIWKLGC7NZLIQ3DUL2RDVRYO2UW7A auto transaction = new Proto::AssetTransfer(); - transaction -> set_asset_id(13379146); - transaction -> set_amount(1000000); - transaction -> set_to_address("GJIWJSX2EU5RC32LKTDDXWLA2YICBHKE35RV2ZPASXZYKWUWXFLKNFSS4U"); + transaction->set_asset_id(13379146); + transaction->set_amount(1000000); + transaction->set_to_address("GJIWJSX2EU5RC32LKTDDXWLA2YICBHKE35RV2ZPASXZYKWUWXFLKNFSS4U"); auto privateKey = parse_hex("5a6a3cfe5ff4cc44c19381d15a0d16de2a76ee5c9b9d83b232e38cb5a2c84b04"); @@ -197,3 +193,5 @@ TEST(AlgorandSigner, ProtoSignerAssetTransaction) { ASSERT_EQ(hex(encoded), "82a3736967c440412720eff99a17280a437bdb8eeba7404b855d6433fffd5dde7f7966c1f9ae531a1af39e18b8a58b4a6c6acb709cca92f8a18c36d8328be9520c915311027005a374786e8aa461616d74ce000f4240a461726376c420325164cafa253b116f4b54c63bd960d610209d44df635d65e095f3855a96b956a3666565cd0924a26676ce00f0b7c3a367656eac746573746e65742d76312e30a26768c4204863b518a4b3c84ec810f22d4f1081cb0f71f059a7ac20dec62f7f70e5093a22a26c76ce00f0bbaba3736e64c42082872d60c338cb928006070e02ec0942addcb79e7fbd01c76458aea526899bd3a474797065a56178666572a478616964ce00cc264a"); } + +} // namespace TW::Algorand::tests diff --git a/tests/Algorand/TWAnySignerTests.cpp b/tests/Algorand/TWAnySignerTests.cpp index 63723876d9e..5b3e00aa411 100644 --- a/tests/Algorand/TWAnySignerTests.cpp +++ b/tests/Algorand/TWAnySignerTests.cpp @@ -4,8 +4,8 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "HexCoding.h" #include "Base64.h" +#include "HexCoding.h" #include "proto/Algorand.pb.h" #include @@ -13,13 +13,14 @@ #include using namespace TW; -using namespace TW::Algorand; + +namespace TW::Algorand::tests { TEST(TWAnySignerAlgorand, Sign) { auto privateKey = parse_hex("d5b43d706ef0cb641081d45a2ec213b5d8281f439f2425d1af54e2afdaabf55b"); auto note = parse_hex("68656c6c6f"); auto genesisHash = Base64::decode("wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="); - + Proto::SigningInput input; auto& transaction = *input.mutable_transfer(); transaction.set_to_address("CRLADAHJZEW2GFY2UPEHENLOGCUOU74WYSTUXQLVLJUJFHEUZOHYZNWYR4"); @@ -47,3 +48,5 @@ TEST(TWAnySignerAlgorand, SignJSON) { ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeAlgorand)); assertStringsEqual(result, "82a3736967c440baa00062adcdcb5875e4435cdc6885d26bfe5308ab17983c0fda790b7103051fcb111554e5badfc0ac7edf7e1223a434342a9eeed5cdb047690827325051560ba374786e8aa3616d74cf000000e8d4a51000a3666565ce00040358a26676ce001d9167a367656eac6d61696e6e65742d76312e30a26768c420c061c4d8fc1dbdded2d7604be4568e3f6d041987ac37bde4b620b5ab39248adfa26c76ce001d954fa46e6f7465c40568656c6c6fa3726376c42014560180e9c92da3171aa3c872356e30a8ea7f96c4a74bc1755a68929c94cb8fa3736e64c42061bf060efc02e2887dfffc8ed85268c8c091c013eedf315bc50794d02a8791ada474797065a3706179"); } + +} // namespace TW::Algorand::tests diff --git a/tests/BinanceSmartChain/SignerTests.cpp b/tests/BinanceSmartChain/SignerTests.cpp index f4e5f4645b0..579cbb4ef18 100644 --- a/tests/BinanceSmartChain/SignerTests.cpp +++ b/tests/BinanceSmartChain/SignerTests.cpp @@ -38,7 +38,7 @@ TEST(BinanceSmartChain, SignNativeTransfer) { // addr: 0xB9F5771C27664bF2282D98E09D7F50cEc7cB01a7 mnemonic: isolate dismiss ... cruel note auto privateKey = PrivateKey(parse_hex("4f96ed80e9a7555a6f74b3d658afdd9c756b0a40d4ca30c42c2039eb449bb904")); uint256_t chainID = 97; - auto signature = Signer::sign(privateKey, chainID, transaction); + auto signature = Ethereum::Signer::sign(privateKey, chainID, transaction); auto encoded = transaction->encoded(signature, chainID); ASSERT_EQ(hex(encoded), "f86c808504a817c8008252089431be00eb1fc8e14a696dbc72f746ec3e95f49683872386f26fc100008081e5a057806b486844c5d0b7b5ce34b289f4e8776aa1fe24a3311cef5053995c51050ca07697aa0695de27da817625df0e7e4c64b0ab22d9df30aec92299a7b380be8db7"); @@ -54,7 +54,7 @@ TEST(BinanceSmartChain, SignTokenTransfer) { func.encode(payloadFunction); EXPECT_EQ(hex(payloadFunction), "a9059cbb00000000000000000000000031be00eb1fc8e14a696dbc72f746ec3e95f49683000000000000000000000000000000000000000000000000002386f26fc10000"); - auto input = Proto::SigningInput(); + auto input = Ethereum::Proto::SigningInput(); auto chainId = store(uint256_t(97)); auto nonce = store(uint256_t(30)); auto gasPrice = store(uint256_t(20000000000)); diff --git a/tests/Bitcoin/BitcoinAddressTests.cpp b/tests/Bitcoin/BitcoinAddressTests.cpp index 6739fb4961e..dd769f6a29e 100644 --- a/tests/Bitcoin/BitcoinAddressTests.cpp +++ b/tests/Bitcoin/BitcoinAddressTests.cpp @@ -5,16 +5,17 @@ // file LICENSE at the root of the source code distribution tree. #include "Bitcoin/Address.h" -#include -#include "PublicKey.h" #include "Bitcoin/Script.h" #include "HexCoding.h" +#include "PublicKey.h" +#include -#include #include +#include using namespace TW; -using namespace TW::Bitcoin; + +namespace TW::Bitcoin::tests { const char* TestPubKey1 = "039d645d2ce630c2a9a6dbe0cbd0a8fcb7b70241cb8a48424f25593290af2494b9"; const char* TestP2phkAddr1 = "12dNaXQtN5Asn2YFwT1cvciCrJa525fAe4"; @@ -50,20 +51,21 @@ TEST(BitcoinAddress, P2SH_CreateFromString) { TEST(BitcoinAddress, P2WPKH_Nested_P2SH) { // P2SH address cannot be created directly from pubkey, script is built const auto publicKey = PublicKey(parse_hex(TestPubKey1), TWPublicKeyTypeSECP256k1); - + const auto pubKeyHash = publicKey.hash({}); EXPECT_EQ(hex(pubKeyHash), "11d91ce1cc681f95583da3f4a6841c174be950c7"); - + const auto script = Script::buildPayToV0WitnessProgram(pubKeyHash); - EXPECT_EQ(hex(script.bytes), "0014" "11d91ce1cc681f95583da3f4a6841c174be950c7"); - + EXPECT_EQ(hex(script.bytes), "0014" + "11d91ce1cc681f95583da3f4a6841c174be950c7"); + const auto scriptHash = Hash::sha256ripemd(script.bytes.data(), script.bytes.size()); EXPECT_EQ(hex(scriptHash), "ee1e69460b59027d9df0a79ca2c92aa382a25fb7"); - + Data addressData = {TWCoinTypeP2shPrefix(TWCoinTypeBitcoin)}; TW::append(addressData, scriptHash); EXPECT_EQ(hex(addressData), TestP2shData1); - + const auto address = Address(addressData); EXPECT_EQ(address.string(), TestP2shAddr1); EXPECT_EQ(hex(address.bytes), TestP2shData1); @@ -74,3 +76,5 @@ TEST(BitcoinAddress, P2SH_CreateFromData) { EXPECT_EQ(address.string(), TestP2shAddr1); EXPECT_EQ(hex(address.bytes), TestP2shData1); } + +} // namespace TW::Bitcoin::tests diff --git a/tests/Bitcoin/TWBitcoinScriptTests.cpp b/tests/Bitcoin/TWBitcoinScriptTests.cpp index e08a46dbea4..db0511e3ab8 100644 --- a/tests/Bitcoin/TWBitcoinScriptTests.cpp +++ b/tests/Bitcoin/TWBitcoinScriptTests.cpp @@ -11,11 +11,15 @@ #include +namespace TW::Bitcoin::tests { + +// clang-format off const auto PayToScriptHash = WRAP(TWBitcoinScript, TWBitcoinScriptCreateWithData(DATA("a914" "4733f37cf4db86fbc2efed2500b4f4e49f312023" "87").get())); const auto PayToWitnessScriptHash = WRAP(TWBitcoinScript, TWBitcoinScriptCreateWithData(DATA("0020" "ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3db").get())); const auto PayToWitnessPublicKeyHash = WRAP(TWBitcoinScript, TWBitcoinScriptCreateWithData(DATA("0014" "79091972186c449eb1ded22b78e40d009bdf0089").get())); const auto PayToPublicKeySecp256k1 = WRAP(TWBitcoinScript, TWBitcoinScriptCreateWithData(DATA("21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "ac").get())); const auto PayToPublicKeyHash = WRAP(TWBitcoinScript, TWBitcoinScriptCreateWithData(DATA("76a914" "79091972186c449eb1ded22b78e40d009bdf0089" "88ac").get())); +// clang-format on TEST(TWBitcoinScript, Create) { auto data = DATA("a9144733f37cf4db86fbc2efed2500b4f4e49f31202387"); @@ -117,7 +121,9 @@ TEST(TWBitcoinScript, BuildPayToPublicKey) { const auto script = WRAP(TWBitcoinScript, TWBitcoinScriptBuildPayToPublicKey(pubkey.get())); ASSERT_TRUE(script.get() != nullptr); const auto hex = WRAPS(TWStringCreateWithHexData(WRAPD(TWBitcoinScriptData(script.get())).get())); - ASSERT_STREQ(TWStringUTF8Bytes(hex.get()), "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "ac"); + ASSERT_STREQ(TWStringUTF8Bytes(hex.get()), "21" + "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" + "ac"); } TEST(TWBitcoinScript, BuildPayToWitnessPubkeyHash) { @@ -125,7 +131,8 @@ TEST(TWBitcoinScript, BuildPayToWitnessPubkeyHash) { const auto script = WRAP(TWBitcoinScript, TWBitcoinScriptBuildPayToWitnessPubkeyHash(hash.get())); ASSERT_TRUE(script.get() != nullptr); const auto hex = WRAPS(TWStringCreateWithHexData(WRAPD(TWBitcoinScriptData(script.get())).get())); - ASSERT_STREQ(TWStringUTF8Bytes(hex.get()), "0014" "79091972186c449eb1ded22b78e40d009bdf0089"); + ASSERT_STREQ(TWStringUTF8Bytes(hex.get()), "0014" + "79091972186c449eb1ded22b78e40d009bdf0089"); } TEST(TWBitcoinScript, BuildPayToWitnessScriptHash) { @@ -133,7 +140,8 @@ TEST(TWBitcoinScript, BuildPayToWitnessScriptHash) { const auto script = WRAP(TWBitcoinScript, TWBitcoinScriptBuildPayToWitnessScriptHash(hash.get())); ASSERT_TRUE(script.get() != nullptr); const auto hex = WRAPS(TWStringCreateWithHexData(WRAPD(TWBitcoinScriptData(script.get())).get())); - ASSERT_STREQ(TWStringUTF8Bytes(hex.get()), "0020" "ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3db"); + ASSERT_STREQ(TWStringUTF8Bytes(hex.get()), "0020" + "ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3db"); } TEST(TWBitcoinScript, ScriptHash) { @@ -233,3 +241,5 @@ TEST(TWBitcoinSigHashType, IsNone) { EXPECT_FALSE(TWBitcoinSigHashTypeIsNone(TWBitcoinSigHashTypeAll)); EXPECT_FALSE(TWBitcoinSigHashTypeIsNone(TWBitcoinSigHashTypeFork)); } + +} // namespace TW::Bitcoin::tests diff --git a/tests/BitcoinCash/TWBitcoinCashTests.cpp b/tests/BitcoinCash/TWBitcoinCashTests.cpp index 80b204de8df..e4f960149f6 100644 --- a/tests/BitcoinCash/TWBitcoinCashTests.cpp +++ b/tests/BitcoinCash/TWBitcoinCashTests.cpp @@ -23,8 +23,10 @@ #include using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin::tests { + +// clang-format off TEST(BitcoinCash, Address) { EXPECT_TRUE(TWAnyAddressIsValid(STRING("pqx578nanz2h2estzmkr53zqdg6qt8xyqvwhn6qeyc").get(), TWCoinTypeBitcoinCash)); EXPECT_TRUE(TWAnyAddressIsValid(STRING("bitcoincash:pqx578nanz2h2estzmkr53zqdg6qt8xyqvwhn6qeyc").get(), TWCoinTypeBitcoinCash)); @@ -34,7 +36,7 @@ TEST(BitcoinCash, ValidAddress) { auto string = STRING("bitcoincash:qqa2qx0d8tegw32xk8u75ws055en4x3h2u0e6k46y4"); auto address = WRAP(TWAnyAddress, TWAnyAddressCreateWithString(string.get(), TWCoinTypeBitcoinCash)); ASSERT_NE(address.get(), nullptr); - + auto script = WRAP(TWBitcoinScript, TWBitcoinScriptLockScriptForAddress(string.get(), TWCoinTypeBitcoinCash)); ASSERT_FALSE(TWBitcoinScriptSize(script.get()) == 0); } @@ -161,3 +163,6 @@ TEST(BitcoinCash, SignTransaction) { "e510000000000000" "1976a9149e089b6889e032d46e3b915a3392edfd616fb1c488ac" "00000000"); } +// clang-format on + +} // namespace TW::Bitcoin::tests diff --git a/tests/BitcoinGold/TWBitcoinGoldTests.cpp b/tests/BitcoinGold/TWBitcoinGoldTests.cpp index 1621692b37b..6c4247b4f90 100644 --- a/tests/BitcoinGold/TWBitcoinGoldTests.cpp +++ b/tests/BitcoinGold/TWBitcoinGoldTests.cpp @@ -6,25 +6,27 @@ #include #include -#include #include +#include #include #include -#include "Bitcoin/SegwitAddress.h" -#include "proto/Bitcoin.pb.h" #include "Bitcoin/OutPoint.h" #include "Bitcoin/Script.h" +#include "Bitcoin/SegwitAddress.h" +#include "Bitcoin/SigHashType.h" #include "Bitcoin/Transaction.h" #include "Bitcoin/TransactionBuilder.h" #include "Bitcoin/TransactionSigner.h" -#include "Bitcoin/SigHashType.h" #include "HexCoding.h" +#include "proto/Bitcoin.pb.h" #include "../interface/TWTestUtilities.h" using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin::tests { + +// clang-format off TEST(TWBitcoinGoldScript, LockScriptTest) { auto script = WRAP(TWBitcoinScript, TWBitcoinScriptLockScriptForAddress(STRING("btg1q6572ulr0kmywle8a30lvagm9xsg9k9n5cmzfdj").get(), TWCoinTypeBitcoinGold)); auto scriptData = WRAPD(TWBitcoinScriptData(script.get())); @@ -79,7 +81,7 @@ TEST(TWBitcoinGoldTxGeneration, TxGeneration) { auto utxoKey0 = parse_hex("cbe13a79b82ec7f8871b336a64fd8d531f598e7c9022e29c67e824cfd54af57f"); input.add_private_key(utxoKey0.data(), utxoKey0.size()); input.set_lock_time(0x00098971); - + auto scriptPub1 = Script(parse_hex("0014db746a75d9aae8995d135b1e19a04d7765242a8f")); auto scriptHash = std::vector(); @@ -94,7 +96,7 @@ TEST(TWBitcoinGoldTxGeneration, TxGeneration) { auto utxo0Script = parse_hex("0014d53cae7c6fb6c8efe4fd8bfecea36534105b1674"); utxo0->set_script(utxo0Script.data(), utxo0Script.size()); utxo0->set_amount(10000); - + auto hash0 = parse_hex("5727794fa2b94aa22a226e206130524201ede9b50e032526e713c848493a890f"); utxo0->mutable_out_point()->set_hash(hash0.data(), hash0.size()); utxo0->mutable_out_point()->set_index(0); @@ -122,4 +124,6 @@ TEST(TWBitcoinGoldTxGeneration, TxGeneration) { "71890900" // nLockTime ); } - +// clang-format on + +} // namespace TW::Bitcoin::tests diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 958d830d97d..746cff782a1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -26,6 +26,9 @@ add_executable(tests ${test_sources}) target_link_libraries(tests gtest_main TrezorCrypto TrustWalletCore walletconsolelib protobuf Boost::boost) target_include_directories(tests PRIVATE ${CMAKE_SOURCE_DIR}/src) target_compile_options(tests PRIVATE "-Wall") +if (NOT ANDROID AND TW_UNITY_BUILD) + set_target_properties(tests PROPERTIES UNITY_BUILD ON) +endif() set_target_properties(tests PROPERTIES diff --git a/tests/Cardano/SigningTests.cpp b/tests/Cardano/SigningTests.cpp index f16820f87d1..aec7cba248d 100644 --- a/tests/Cardano/SigningTests.cpp +++ b/tests/Cardano/SigningTests.cpp @@ -4,26 +4,25 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Cardano/Signer.h" #include "Cardano/AddressV3.h" +#include "Cardano/Signer.h" #include "proto/Cardano.pb.h" #include -#include "PrivateKey.h" -#include "HexCoding.h" #include "Cbor.h" +#include "HexCoding.h" +#include "PrivateKey.h" #include "uint256.h" -#include #include "../interface/TWTestUtilities.h" +#include #include #include - -using namespace TW::Cardano; using namespace TW; using namespace std; +namespace TW::Cardano::tests { const auto privateKeyTest1 = "089b68e458861be0c44bf9f7967f05cc91e51ede86dc679448a3566990b7785bd48c330875b1e0d03caaed0e67cecc42075dce1c7a13b1c49240508848ac82f603391c68824881ae3fc23a56a1a75ada3b96382db502e37564e84a5413cfaf1290dbd508e5ec71afaea98da2df1533c22ef02a26bb87b31907d0b2738fb7785b38d53aa68fc01230784c9209b2b2a2faf28491b3b1f1d221e63e704bbd0403c4154425dfbb01a2c5c042da411703603f89af89e57faae2946e2a5c18b1c5ca0e"; const auto ownAddress1 = "addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23"; @@ -37,13 +36,13 @@ TEST(CardanoSigning, SelectInputs) { TxInput{{parse_hex("0004"), 3}, "ad04", 600, {}}, }); - { // 2 + { // 2 const auto s1 = Signer::selectInputsWithTokens(inputs, 1500, {}); ASSERT_EQ(s1.size(), 2ul); EXPECT_EQ(s1[0].amount, 900ul); EXPECT_EQ(s1[1].amount, 700ul); } - { // all + { // all const auto s1 = Signer::selectInputsWithTokens(inputs, 10000, {}); ASSERT_EQ(s1.size(), 4ul); EXPECT_EQ(s1[0].amount, 900ul); @@ -51,25 +50,23 @@ TEST(CardanoSigning, SelectInputs) { EXPECT_EQ(s1[2].amount, 600ul); EXPECT_EQ(s1[3].amount, 300ul); } - { // 3 + { // 3 const auto s1 = Signer::selectInputsWithTokens(inputs, 2000, {}); ASSERT_EQ(s1.size(), 3ul); } - { // 1 + { // 1 const auto s1 = Signer::selectInputsWithTokens(inputs, 500, {}); ASSERT_EQ(s1.size(), 1ul); } - { // at least 0 is returned + { // at least 0 is returned const auto s1 = Signer::selectInputsWithTokens(inputs, 0, {}); ASSERT_EQ(s1.size(), 1ul); } } -Proto::SigningInput createSampleInput(uint64_t amount, int utxoCount = 10, - const std::string& alternateToAddress = "", bool omitPrivateKey = false -) { - const std::string toAddress = (alternateToAddress.length() > 0) ? alternateToAddress : - "addr1q92cmkgzv9h4e5q7mnrzsuxtgayvg4qr7y3gyx97ukmz3dfx7r9fu73vqn25377ke6r0xk97zw07dqr9y5myxlgadl2s0dgke5"; +Proto::SigningInput createSampleInput(uint64_t amount, int utxoCount = 10, + const std::string& alternateToAddress = "", bool omitPrivateKey = false) { + const std::string toAddress = (alternateToAddress.length() > 0) ? alternateToAddress : "addr1q92cmkgzv9h4e5q7mnrzsuxtgayvg4qr7y3gyx97ukmz3dfx7r9fu73vqn25377ke6r0xk97zw07dqr9y5myxlgadl2s0dgke5"; Proto::SigningInput input; if (utxoCount >= 1) { @@ -115,7 +112,7 @@ TEST(CardanoSigning, Plan) { EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); EXPECT_EQ(plan.error, Common::Proto::OK); } - { // very small target amount + { // very small target amount input.mutable_transfer_message()->set_amount(1); auto signer = Signer(input); const auto plan = signer.doPlan(); @@ -125,7 +122,7 @@ TEST(CardanoSigning, Plan) { EXPECT_EQ(plan.fee, 168435ul); EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); } - { // small target amount + { // small target amount input.mutable_transfer_message()->set_amount(2000000); auto signer = Signer(input); const auto plan = signer.doPlan(); @@ -135,7 +132,7 @@ TEST(CardanoSigning, Plan) { EXPECT_EQ(plan.fee, 168611ul); EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); } - { // small target amount requested, but max amount + { // small target amount requested, but max amount input.mutable_transfer_message()->set_amount(2000000); input.mutable_transfer_message()->set_use_max_amount(true); auto signer = Signer(input); @@ -165,7 +162,7 @@ TEST(CardanoSigning, PlanForceFee) { EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); EXPECT_EQ(plan.error, Common::Proto::OK); } - { // tiny fee + { // tiny fee auto fee = 100ul; input.mutable_transfer_message()->set_force_fee(fee); auto signer = Signer(input); @@ -176,7 +173,7 @@ TEST(CardanoSigning, PlanForceFee) { EXPECT_EQ(plan.change, availableAmount - requestedAmount - fee); EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); } - { // large fee + { // large fee auto fee = 1200000ul; input.mutable_transfer_message()->set_force_fee(fee); auto signer = Signer(input); @@ -187,7 +184,7 @@ TEST(CardanoSigning, PlanForceFee) { EXPECT_EQ(plan.change, availableAmount - requestedAmount - fee); EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); } - { // very large fee, larger than possible, truncated + { // very large fee, larger than possible, truncated auto fee = 3000000ul; input.mutable_transfer_message()->set_force_fee(fee); auto signer = Signer(input); @@ -198,7 +195,7 @@ TEST(CardanoSigning, PlanForceFee) { EXPECT_EQ(plan.change, 0ul); EXPECT_EQ(plan.amount + plan.change + plan.fee, plan.availableAmount); } - { // force fee and max amount: fee is used, amount is max, change 0 + { // force fee and max amount: fee is used, amount is max, change 0 auto fee = 160000ul; input.mutable_transfer_message()->set_force_fee(fee); input.mutable_transfer_message()->set_use_max_amount(true); @@ -295,7 +292,6 @@ TEST(CardanoSigning, PlanAndSignTransfer1) { EXPECT_EQ(hex(txid), "e319c0bfc99cdb79d64f00b7e8fb8bfbf29fa70554c84f101e92b7dfed172448"); } - TEST(CardanoSigning, PlanAndSignMaxAmount) { auto input = createSampleInput(7000000); input.mutable_transfer_message()->set_use_max_amount(true); @@ -326,7 +322,7 @@ TEST(CardanoSigning, PlanAndSignMaxAmount) { } TEST(CardanoSigning, SignNegative) { - { // plan with error + { // plan with error auto input = createSampleInput(7000000); const auto error = Common::Proto::Error_invalid_memo; input.mutable_plan()->set_error(error); @@ -334,25 +330,25 @@ TEST(CardanoSigning, SignNegative) { const auto output = signer.sign(); EXPECT_EQ(output.error(), error); } - { // zero requested amount + { // zero requested amount auto input = createSampleInput(0); auto signer = Signer(input); const auto output = signer.sign(); EXPECT_EQ(output.error(), Common::Proto::Error_zero_amount_requested); } - { // no utxo + { // no utxo auto input = createSampleInput(7000000, 0); auto signer = Signer(input); const auto output = signer.sign(); EXPECT_EQ(output.error(), Common::Proto::Error_missing_input_utxos); } - { // low balance + { // low balance auto input = createSampleInput(7000000000); auto signer = Signer(input); const auto output = signer.sign(); EXPECT_EQ(output.error(), Common::Proto::Error_low_balance); } - { // missing private key + { // missing private key auto input = createSampleInput(7000000, 10, "", true); auto signer = Signer(input); const auto output = signer.sign(); @@ -528,7 +524,7 @@ TEST(CardanoSigning, SignTransferToken) { input.mutable_transfer_message()->set_use_max_amount(false); input.set_ttl(53333333); - { // check min ADA amount, set it + { // check min ADA amount, set it const auto bundleProtoData = data(input.transfer_message().token_amount().SerializeAsString()); const auto minAdaAmount = TWCardanoMinAdaAmount(&bundleProtoData); EXPECT_EQ(minAdaAmount, 1444443ul); @@ -609,7 +605,7 @@ TEST(CardanoSigning, SignTransferToken_1dd248) { input.mutable_transfer_message()->set_use_max_amount(false); input.set_ttl(61232158); - { // check min ADA amount + { // check min ADA amount const auto bundleProtoData = data(input.transfer_message().token_amount().SerializeAsString()); EXPECT_EQ(TWCardanoMinAdaAmount(&bundleProtoData), 1444443ul); EXPECT_GT(input.transfer_message().amount(), TWCardanoMinAdaAmount(&bundleProtoData)); @@ -683,7 +679,7 @@ TEST(CardanoSigning, SignTransferTokenMaxAmount_620b71) { auto* toToken = input.mutable_transfer_message()->mutable_token_amount()->add_token(); toToken->set_policy_id(sundaeTokenPolicy); toToken->set_asset_name("SUNDAE"); - const auto toTokenAmount = store(uint256_t(666)); // doesn't matter, max is used + const auto toTokenAmount = store(uint256_t(666)); // doesn't matter, max is used input.mutable_transfer_message()->set_use_max_amount(true); input.set_ttl(61085916); @@ -757,16 +753,14 @@ TEST(CardanoSigning, SignMessageWithKey) { "69272d81c376382b8a87c21370a7ae9618df8da708d1a9490939ec54ebe43000" "1111111111111111111111111111111111111111111111111111111111111111" "1111111111111111111111111111111111111111111111111111111111111111" - "1111111111111111111111111111111111111111111111111111111111111111" - )); + "1111111111111111111111111111111111111111111111111111111111111111")); const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano); - EXPECT_EQ(hex(publicKey.bytes), - "e6f04522f875c1563682ca876ddb04c2e2e3ae718e3ff9f11c03dd9f9dccf698" - "69272d81c376382b8a87c21370a7ae9618df8da708d1a9490939ec54ebe43000" - "857eed804ff087b97f87848f6493e87257a8c5203cb9f422f6e7a7d8a4d299f3" - "1111111111111111111111111111111111111111111111111111111111111111" - ); + EXPECT_EQ(hex(publicKey.bytes), + "e6f04522f875c1563682ca876ddb04c2e2e3ae718e3ff9f11c03dd9f9dccf698" + "69272d81c376382b8a87c21370a7ae9618df8da708d1a9490939ec54ebe43000" + "857eed804ff087b97f87848f6493e87257a8c5203cb9f422f6e7a7d8a4d299f3" + "1111111111111111111111111111111111111111111111111111111111111111"); const auto sampleMessageStr = "Hello world"; const auto sampleMessage = data(sampleMessageStr); @@ -815,3 +809,5 @@ TEST(CardanoSigning, AnyPlan1) { EXPECT_EQ(plan2.change, plan.change()); } } + +} // namespace TW::Cardano::tests diff --git a/tests/Decred/SignerTests.cpp b/tests/Decred/SignerTests.cpp index e2282b76fba..85cf02ea128 100644 --- a/tests/Decred/SignerTests.cpp +++ b/tests/Decred/SignerTests.cpp @@ -16,8 +16,10 @@ #include using namespace TW; -using namespace TW::Decred; +namespace TW::Decred::tests { + +// clang-format off TEST(DecredSigner, SignP2PKH) { const auto privateKey = PrivateKey(parse_hex("22a47fa09a223f2aa079edf85a7c2d4f8720ee63e502ee2869afab7de234b80c")); const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); @@ -427,3 +429,6 @@ TEST(DecredSigning, SignP2WPKH_NegativeAddressWrongType) { ASSERT_FALSE(result) << std::to_string(result.error()); } +// clang-format on + +} // namespace TW::Decred::tests diff --git a/tests/EOS/AddressTests.cpp b/tests/EOS/AddressTests.cpp index 25ff60f2dd9..e11efc7feeb 100644 --- a/tests/EOS/AddressTests.cpp +++ b/tests/EOS/AddressTests.cpp @@ -12,7 +12,8 @@ #include using namespace TW; -using namespace TW::EOS; + +namespace TW::EOS::tests { TEST(EOSAddress, Invalid) { ASSERT_FALSE(Address::isValid("abc")); @@ -28,40 +29,36 @@ TEST(EOSAddress, Invalid) { TEST(EOSAddress, Base58) { ASSERT_EQ( Address("EOS65QzSGJ579GPNKtZoZkChTzsxR4B48RCfiS82m2ymJR6VZCjTF").string(), - "EOS65QzSGJ579GPNKtZoZkChTzsxR4B48RCfiS82m2ymJR6VZCjTF" - ); + "EOS65QzSGJ579GPNKtZoZkChTzsxR4B48RCfiS82m2ymJR6VZCjTF"); ASSERT_EQ( Address("EOS55hdeEZHoArE8LLTv6drj2yR1K1AH8wAPT4kjTVSnkmQc3nzwQ").string(), - "EOS55hdeEZHoArE8LLTv6drj2yR1K1AH8wAPT4kjTVSnkmQc3nzwQ" - ); + "EOS55hdeEZHoArE8LLTv6drj2yR1K1AH8wAPT4kjTVSnkmQc3nzwQ"); ASSERT_EQ( Address("PUB_R1_5hieQEFWh68h6bjaYAY25Ptd2bmqLCaFsunaneh9gZsmSgUBUe").string(), - "PUB_R1_5hieQEFWh68h6bjaYAY25Ptd2bmqLCaFsunaneh9gZsmSgUBUe" - ); + "PUB_R1_5hieQEFWh68h6bjaYAY25Ptd2bmqLCaFsunaneh9gZsmSgUBUe"); ASSERT_EQ( Address("PUB_R1_7M9ckjr6p5CmS3N3yLPg9vcTB5NHmLcMHwZ3iGccEVfbjJRHv3").string(), - "PUB_R1_7M9ckjr6p5CmS3N3yLPg9vcTB5NHmLcMHwZ3iGccEVfbjJRHv3" - ); + "PUB_R1_7M9ckjr6p5CmS3N3yLPg9vcTB5NHmLcMHwZ3iGccEVfbjJRHv3"); } TEST(EOSAddress, FromPrivateKey) { - std::string privArray[] { "8e14ef506fee5e0aaa32f03a45242d32d0eb993ffe25ce77542ef07219db667c", - "e2bfd815c5923f404388a3257aa5527f0f52e92ce364e1e26a04d270c901edda", - "e6b783120a21cb234d8e15077ce186c47261d1043781ab8b16b84f2acd377668", - "bb96c0a4a6ec9c93ccc0b2cbad6b0e8110b9ca4731aef9c6937b99552a319b03" }; + std::string privArray[]{"8e14ef506fee5e0aaa32f03a45242d32d0eb993ffe25ce77542ef07219db667c", + "e2bfd815c5923f404388a3257aa5527f0f52e92ce364e1e26a04d270c901edda", + "e6b783120a21cb234d8e15077ce186c47261d1043781ab8b16b84f2acd377668", + "bb96c0a4a6ec9c93ccc0b2cbad6b0e8110b9ca4731aef9c6937b99552a319b03"}; - Type privTypes[] { Type::Legacy, Type::Legacy, Type::ModernR1, Type::ModernR1 }; + Type privTypes[]{Type::Legacy, Type::Legacy, Type::ModernR1, Type::ModernR1}; - std::string pubArray[] { "EOS6TFKUKVvtvjRq9T4fV9pdxNUuJke92nyb4rzSFtZfdR5ssmVuY", - "EOS5YtaCcbPJ3BknNBTDezE9eJoGNnAVuUwT8bnxhSRS5dqRvyfxr", - "PUB_R1_67itCyDj42CRgtpyP4fLbAccBYnVHGeZQujQAeK3fyNbvfvZM6", - "PUB_R1_5DpVkbrMBDnY4JRhiEdHLmdLDKGQLNfL7X7it2pqT7Uk83ccDL" }; + std::string pubArray[]{"EOS6TFKUKVvtvjRq9T4fV9pdxNUuJke92nyb4rzSFtZfdR5ssmVuY", + "EOS5YtaCcbPJ3BknNBTDezE9eJoGNnAVuUwT8bnxhSRS5dqRvyfxr", + "PUB_R1_67itCyDj42CRgtpyP4fLbAccBYnVHGeZQujQAeK3fyNbvfvZM6", + "PUB_R1_5DpVkbrMBDnY4JRhiEdHLmdLDKGQLNfL7X7it2pqT7Uk83ccDL"}; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) { const auto privateKey = PrivateKey(parse_hex(privArray[i])); const auto publicKey = PublicKey(privateKey.getPublicKey(privTypes[i] == Type::Legacy ? TWPublicKeyTypeSECP256k1 : TWPublicKeyTypeNIST256p1)); const auto address = Address(publicKey, privTypes[i]); - + ASSERT_EQ(address.string(), pubArray[i]); } } @@ -74,4 +71,6 @@ TEST(EOSAddress, IsValid) { ASSERT_NO_THROW(Address(parse_hex("039d91164ea04f4e751762643ef4ae520690af361b8e677cf341fd213419956b356cb721b7"), Type::ModernR1)); ASSERT_NO_THROW(Address(parse_hex("02d3c8e736a9a50889766caf3c37bd16e2fecc7340b3130e25d4c01b153f996a10a78afc0e"), Type::Legacy)); -} \ No newline at end of file +} + +} // namespace TW::EOS::tests diff --git a/tests/Elrond/AddressTests.cpp b/tests/Elrond/AddressTests.cpp index ef387f5ad79..a96a0f53c1a 100644 --- a/tests/Elrond/AddressTests.cpp +++ b/tests/Elrond/AddressTests.cpp @@ -7,15 +7,15 @@ #include #include +#include "Elrond/Address.h" #include "HexCoding.h" -#include "PublicKey.h" #include "PrivateKey.h" -#include "Elrond/Address.h" +#include "PublicKey.h" #include "TestAccounts.h" using namespace TW; -using namespace TW::Elrond; +namespace TW::Elrond::tests { TEST(ElrondAddress, Valid) { ASSERT_TRUE(Address::isValid(ALICE_BECH32)); @@ -35,7 +35,7 @@ TEST(ElrondAddress, FromString) { Address alice, bob, carol; ASSERT_TRUE(Address::decode(ALICE_BECH32, alice)); ASSERT_TRUE(Address::decode(BOB_BECH32, bob)); - + ASSERT_EQ(ALICE_PUBKEY_HEX, hex(alice.getKeyHash())); ASSERT_EQ(BOB_PUBKEY_HEX, hex(bob.getKeyHash())); } @@ -43,7 +43,7 @@ TEST(ElrondAddress, FromString) { TEST(ElrondAddress, FromData) { const auto alice = Address(parse_hex(ALICE_PUBKEY_HEX)); const auto bob = Address(parse_hex(BOB_PUBKEY_HEX)); - + ASSERT_EQ(ALICE_BECH32, alice.string()); ASSERT_EQ(BOB_BECH32, bob.string()); } @@ -65,3 +65,5 @@ TEST(ElrondAddress, FromPublicKey) { auto bob = PublicKey(parse_hex(BOB_PUBKEY_HEX), TWPublicKeyTypeED25519); ASSERT_EQ(BOB_BECH32, Address(bob).string()); } + +} // namespace TW::Elrond::tests diff --git a/tests/Elrond/SerializationTests.cpp b/tests/Elrond/SerializationTests.cpp index 3da9803f7e5..c1a730de8c7 100644 --- a/tests/Elrond/SerializationTests.cpp +++ b/tests/Elrond/SerializationTests.cpp @@ -4,16 +4,17 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include "boost/format.hpp" #include #include -#include "boost/format.hpp" -#include "HexCoding.h" #include "Elrond/Serialization.h" +#include "HexCoding.h" #include "TestAccounts.h" using namespace TW; -using namespace TW::Elrond; + +namespace TW::Elrond::tests { TEST(ElrondSerialization, SignableString) { Transaction transaction; @@ -58,3 +59,5 @@ TEST(ElrondSerialization, SignableStringWithoutData) { string jsonString = serializeTransaction(transaction); ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"abba","sender":"feed","gasPrice":0,"gasLimit":0,"chainID":"1","version":1})", jsonString); } + +} // namespace TW::Elrond::tests diff --git a/tests/Elrond/SignerTests.cpp b/tests/Elrond/SignerTests.cpp index 88540c19392..aeaa8455a69 100644 --- a/tests/Elrond/SignerTests.cpp +++ b/tests/Elrond/SignerTests.cpp @@ -4,19 +4,19 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include #include "boost/format.hpp" +#include +#include "Elrond/Address.h" +#include "Elrond/Signer.h" #include "HexCoding.h" #include "PrivateKey.h" #include "PublicKey.h" -#include "Elrond/Signer.h" -#include "Elrond/Address.h" #include "TestAccounts.h" using namespace TW; -using namespace TW::Elrond; +namespace TW::Elrond::tests { TEST(ElrondSigner, SignGenericAction) { auto input = Proto::SigningInput(); @@ -47,7 +47,7 @@ TEST(ElrondSigner, SignGenericActionJSON) { // Shuffle some fields, assume arbitrary order in the input auto input = (boost::format(R"({"genericAction" : {"accounts": {"senderNonce": 7, "receiver": "%1%", "sender": "%2%"}, "data": "foo", "value": "0", "version": 1}, "gasPrice": 1000000000, "gasLimit": 50000, "chainId": "1"})") % BOB_BECH32 % ALICE_BECH32).str(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); - + auto encoded = Signer::signJSON(input, privateKey.bytes); auto expectedSignature = "e8647dae8b16e034d518a1a860c6a6c38d16192d0f1362833e62424f424e5da660770dff45f4b951d9cc58bfb9d14559c977d443449bfc4b8783ff9c84065700"; auto expectedEncoded = (boost::format(R"({"nonce":7,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":1000000000,"gasLimit":50000,"data":"Zm9v","chainID":"1","version":1,"signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str(); @@ -69,7 +69,7 @@ TEST(ElrondSigner, SignWithoutData) { input.set_gas_price(1000000000); input.set_gas_limit(50000); input.set_chain_id("1"); - + auto output = Signer::sign(input); auto signature = output.signature(); auto encoded = output.encoded(); @@ -84,7 +84,7 @@ TEST(ElrondSigner, SignJSONWithoutData) { // Shuffle some fields, assume arbitrary order in the input auto input = (boost::format(R"({"genericAction" : {"accounts": {"senderNonce": 0, "receiver": "%1%", "sender": "%2%"}, "value": "0", "version": 1}, "gasPrice": 1000000000, "gasLimit": 50000, "chainId": "1"})") % BOB_BECH32 % ALICE_BECH32).str(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); - + auto encoded = Signer::signJSON(input, privateKey.bytes); auto expectedSignature = "c7253b821c68011584ebd3a5bb050ade19235c2d10260e411e523105826c40a79849b3eeb96fcc2a7a6b1fa140b6756f50b249e005be056ce0cf53125e0b1b00"; auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":1000000000,"gasLimit":50000,"chainID":"1","version":1,"signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str(); @@ -115,17 +115,13 @@ TEST(ElrondSigner, SignWithUsernames) { auto signature = output.signature(); auto encoded = output.encoded(); auto expectedSignature = "1bed82c3f91c9d24f3a163e7b93a47453d70e8743201fe7d3656c0214569566a76503ef0968279ac942ca43b9c930bd26638dfb075a220ce80b058ab7bca140a"; - auto expectedEncoded = - ( - boost::format(R"({"nonce":89,"value":"0","receiver":"%1%","sender":"%2%","senderUsername":"%3%","receiverUsername":"%4%","gasPrice":1000000000,"gasLimit":50000,"chainID":"local-testnet","version":1,"signature":"%5%"})") - % BOB_BECH32 - % ALICE_BECH32 - // "alice" - % "YWxpY2U=" - // "bob" - % "Ym9i" - % expectedSignature - ).str(); + auto expectedEncoded = + (boost::format(R"({"nonce":89,"value":"0","receiver":"%1%","sender":"%2%","senderUsername":"%3%","receiverUsername":"%4%","gasPrice":1000000000,"gasLimit":50000,"chainID":"local-testnet","version":1,"signature":"%5%"})") % BOB_BECH32 % ALICE_BECH32 + // "alice" + % "YWxpY2U=" + // "bob" + % "Ym9i" % expectedSignature) + .str(); ASSERT_EQ(expectedSignature, signature); ASSERT_EQ(expectedEncoded, encoded); @@ -144,7 +140,7 @@ TEST(ElrondSigner, SignWithOptions) { input.mutable_generic_action()->set_version(1); // We'll set a dummy value on the "options" field (merely an example). // Currently, the "options" field should be ignored (not set) by applications using TW Core. - // In the future, TW Core will handle specific transaction options + // In the future, TW Core will handle specific transaction options // (such as the "SignedWithHash" flag, as seen in https://github.com/ElrondNetwork/elrond-go-core/blob/main/core/versioning/txVersionChecker.go) // when building and signing transactions. input.mutable_generic_action()->set_options(42); @@ -156,13 +152,8 @@ TEST(ElrondSigner, SignWithOptions) { auto signature = output.signature(); auto encoded = output.encoded(); auto expectedSignature = "d9a624f13960ae1cc471de48bdb43b101b9d469bb8b159f68bb629bb32d0109e1acfebb62d6d2fc5786c0b85f9e7ce2caff74988864a8285f34797c5a5fa5801"; - auto expectedEncoded = - ( - boost::format(R"({"nonce":89,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":1000000000,"gasLimit":50000,"chainID":"local-testnet","version":1,"options":42,"signature":"%3%"})") - % BOB_BECH32 - % ALICE_BECH32 - % expectedSignature - ).str(); + auto expectedEncoded = + (boost::format(R"({"nonce":89,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":1000000000,"gasLimit":50000,"chainID":"local-testnet","version":1,"options":42,"signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str(); ASSERT_EQ(expectedEncoded, encoded); ASSERT_EQ(expectedSignature, signature); @@ -177,18 +168,13 @@ TEST(ElrondSigner, SignEGLDTransfer) { input.mutable_egld_transfer()->mutable_accounts()->set_sender(ALICE_BECH32); input.mutable_egld_transfer()->mutable_accounts()->set_receiver(BOB_BECH32); input.mutable_egld_transfer()->set_amount("1000000000000000000"); - + auto output = Signer::sign(input); auto signature = output.signature(); auto encoded = output.encoded(); auto expectedSignature = "7e1c4c63b88ea72dcf7855a54463b1a424eb357ac3feb4345221e512ce07c7a50afb6d7aec6f480b554e32cf2037082f3bc17263d1394af1f3ef240be53c930b"; - auto expectedEncoded = - ( - boost::format(R"({"nonce":7,"value":"1000000000000000000","receiver":"%1%","sender":"%2%","gasPrice":1000000000,"gasLimit":50000,"chainID":"1","version":1,"signature":"%3%"})") - % BOB_BECH32 - % ALICE_BECH32 - % expectedSignature - ).str(); + auto expectedEncoded = + (boost::format(R"({"nonce":7,"value":"1000000000000000000","receiver":"%1%","sender":"%2%","gasPrice":1000000000,"gasLimit":50000,"chainID":"1","version":1,"signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str(); ASSERT_EQ(expectedSignature, signature); ASSERT_EQ(expectedEncoded, encoded); @@ -204,20 +190,16 @@ TEST(ElrondSigner, SignESDTTransfer) { input.mutable_esdt_transfer()->mutable_accounts()->set_receiver(BOB_BECH32); input.mutable_esdt_transfer()->set_token_identifier("MYTOKEN-1234"); input.mutable_esdt_transfer()->set_amount("10000000000000"); - + auto output = Signer::sign(input); auto signature = output.signature(); auto encoded = output.encoded(); auto expectedSignature = "9add6d9ac3f1a1fddb07b934e8a73cad3b8c232bdf29d723c1b38ad619905f03e864299d06eb3fe3bbb48a9f1d9b7f14e21dc5eaffe0c87f5718ad0c4198bb0c"; - auto expectedEncoded = - ( - boost::format(R"({"nonce":7,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":1000000000,"gasLimit":425000,"data":"%3%","chainID":"1","version":1,"signature":"%4%"})") - % BOB_BECH32 - % ALICE_BECH32 - // "ESDTTransfer@4d59544f4b454e2d31323334@09184e72a000" - % "RVNEVFRyYW5zZmVyQDRkNTk1NDRmNGI0NTRlMmQzMTMyMzMzNEAwOTE4NGU3MmEwMDA=" - % expectedSignature - ).str(); + auto expectedEncoded = + (boost::format(R"({"nonce":7,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":1000000000,"gasLimit":425000,"data":"%3%","chainID":"1","version":1,"signature":"%4%"})") % BOB_BECH32 % ALICE_BECH32 + // "ESDTTransfer@4d59544f4b454e2d31323334@09184e72a000" + % "RVNEVFRyYW5zZmVyQDRkNTk1NDRmNGI0NTRlMmQzMTMyMzMzNEAwOTE4NGU3MmEwMDA=" % expectedSignature) + .str(); ASSERT_EQ(expectedSignature, signature); ASSERT_EQ(expectedEncoded, encoded); @@ -234,21 +216,19 @@ TEST(ElrondSigner, SignESDTNFTTransfer) { input.mutable_esdtnft_transfer()->set_token_collection("LKMEX-aab910"); input.mutable_esdtnft_transfer()->set_token_nonce(4); input.mutable_esdtnft_transfer()->set_amount("184300000000000000"); - + auto output = Signer::sign(input); auto signature = output.signature(); auto encoded = output.encoded(); auto expectedSignature = "cc935685d5b31525e059a16a832cba98dee751983a5a93de4198f6553a2c55f5f1e0b4300fe9077376fa754546da0b0f6697e66462101a209aafd0fc775ab60a"; - auto expectedEncoded = - ( - boost::format(R"({"nonce":7,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":1000000000,"gasLimit":937500,"data":"%3%","chainID":"1","version":1,"signature":"%4%"})") - % ALICE_BECH32 - % ALICE_BECH32 - // "ESDTNFTTransfer@4c4b4d45582d616162393130@04@028ec3dfa01ac000@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8" - % "RVNEVE5GVFRyYW5zZmVyQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAwNEAwMjhlYzNkZmEwMWFjMDAwQDgwNDlkNjM5ZTVhNjk4MGQxY2QyMzkyYWJjY2U0MTAyOWNkYTc0YTE1NjM1MjNhMjAyZjA5NjQxY2MyNjE4Zjg=" - % expectedSignature - ).str(); + auto expectedEncoded = + (boost::format(R"({"nonce":7,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":1000000000,"gasLimit":937500,"data":"%3%","chainID":"1","version":1,"signature":"%4%"})") % ALICE_BECH32 % ALICE_BECH32 + // "ESDTNFTTransfer@4c4b4d45582d616162393130@04@028ec3dfa01ac000@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8" + % "RVNEVE5GVFRyYW5zZmVyQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAwNEAwMjhlYzNkZmEwMWFjMDAwQDgwNDlkNjM5ZTVhNjk4MGQxY2QyMzkyYWJjY2U0MTAyOWNkYTc0YTE1NjM1MjNhMjAyZjA5NjQxY2MyNjE4Zjg=" % expectedSignature) + .str(); ASSERT_EQ(expectedSignature, signature); ASSERT_EQ(expectedEncoded, encoded); } + +} // namespace TW::Elrond::tests diff --git a/tests/Elrond/TWAnySignerTests.cpp b/tests/Elrond/TWAnySignerTests.cpp index 380c2c7de7b..277864dbe9e 100644 --- a/tests/Elrond/TWAnySignerTests.cpp +++ b/tests/Elrond/TWAnySignerTests.cpp @@ -4,18 +4,18 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include #include "boost/format.hpp" +#include -#include -#include "HexCoding.h" -#include "../interface/TWTestUtilities.h" #include "Elrond/Signer.h" +#include "HexCoding.h" #include "TestAccounts.h" +#include "../interface/TWTestUtilities.h" +#include using namespace TW; -using namespace TW::Elrond; +namespace TW::Elrond::tests { TEST(TWAnySignerElrond, Sign) { auto input = Proto::SigningInput(); @@ -55,3 +55,5 @@ TEST(TWAnySignerElrond, SignJSON) { ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeElrond)); assertStringsEqual(encoded, expectedEncoded.c_str()); } + +} // namespace TW::Elrond::tests diff --git a/tests/Ethereum/AbiStructTests.cpp b/tests/Ethereum/AbiStructTests.cpp index 2a20569d1ec..be9b6dabd91 100644 --- a/tests/Ethereum/AbiStructTests.cpp +++ b/tests/Ethereum/AbiStructTests.cpp @@ -7,19 +7,21 @@ #include "Ethereum/ABI.h" #include "Ethereum/Address.h" #include "Ethereum/Signer.h" +#include "../interface/TWTestUtilities.h" #include #include -#include "../interface/TWTestUtilities.h" #include #include -using namespace TW::Ethereum::ABI; -using namespace TW::Ethereum; using namespace TW; extern std::string TESTS_ROOT; +namespace TW::Ethereum::tests { + +using namespace ABI; + std::string load_file(const std::string path) { std::ifstream stream(path); std::string content((std::istreambuf_iterator(stream)), (std::istreambuf_iterator())); @@ -27,7 +29,7 @@ std::string load_file(const std::string path) { } // https://github.com/MetaMask/eth-sig-util/blob/main/test/index.ts - +// clang-format off ParamStruct msgPersonCow2("Person", std::vector>{ std::make_shared("name", std::make_shared("Cow")), std::make_shared("wallets", std::make_shared(std::vector>{ @@ -212,17 +214,17 @@ TEST(EthereumAbiStruct, encodeTypes_v4) { EXPECT_EQ(hex(msgPersonCow2.hashType()), "fabfe1ed996349fc6027709802be19d047da1aa5d6894ff5f6486d92db2e6860"); - EXPECT_EQ(hex(msgPersonCow2.encodeHashes()), - "fabfe1ed996349fc6027709802be19d047da1aa5d6894ff5f6486d92db2e6860" - "8c1d2bd5348394761719da11ec67eedae9502d137e8940fee8ecd6f641ee1648" - "8a8bfe642b9fc19c25ada5dadfd37487461dc81dd4b0778f262c163ed81b5e2a"); + EXPECT_EQ(hex(msgPersonCow2.encodeHashes()), + "fabfe1ed996349fc6027709802be19d047da1aa5d6894ff5f6486d92db2e6860" + "8c1d2bd5348394761719da11ec67eedae9502d137e8940fee8ecd6f641ee1648" + "8a8bfe642b9fc19c25ada5dadfd37487461dc81dd4b0778f262c163ed81b5e2a"); EXPECT_EQ(hex(msgPersonCow2.hashStruct()), "9b4846dd48b866f0ac54d61b9b21a9e746f921cefa4ee94c4c0a1c49c774f67f"); - EXPECT_EQ(hex(msgPersonBob3.encodeHashes()), - "fabfe1ed996349fc6027709802be19d047da1aa5d6894ff5f6486d92db2e6860" - "28cac318a86c8a0a6a9156c2dba2c8c2363677ba0514ef616592d81557e679b6" - "d2734f4c86cc3bd9cabf04c3097589d3165d95e4648fc72d943ed161f651ec6d"); + EXPECT_EQ(hex(msgPersonBob3.encodeHashes()), + "fabfe1ed996349fc6027709802be19d047da1aa5d6894ff5f6486d92db2e6860" + "28cac318a86c8a0a6a9156c2dba2c8c2363677ba0514ef616592d81557e679b6" + "d2734f4c86cc3bd9cabf04c3097589d3165d95e4648fc72d943ed161f651ec6d"); EXPECT_EQ(hex(msgPersonBob3.hashStruct()), "efa62530c7ae3a290f8a13a5fc20450bdb3a6af19d9d9d2542b5a94e631a9168"); @@ -230,11 +232,11 @@ TEST(EthereumAbiStruct, encodeTypes_v4) { EXPECT_EQ(hex(msgMailCow2Bob3.hashType()), "4bd8a9a2b93427bb184aca81e24beb30ffa3c747e2a33d4225ec08bf12e2e753"); - EXPECT_EQ(hex(msgMailCow2Bob3.encodeHashes()), - "4bd8a9a2b93427bb184aca81e24beb30ffa3c747e2a33d4225ec08bf12e2e753" - "9b4846dd48b866f0ac54d61b9b21a9e746f921cefa4ee94c4c0a1c49c774f67f" - "ca322beec85be24e374d18d582a6f2997f75c54e7993ab5bc07404ce176ca7cd" - "b5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8"); + EXPECT_EQ(hex(msgMailCow2Bob3.encodeHashes()), + "4bd8a9a2b93427bb184aca81e24beb30ffa3c747e2a33d4225ec08bf12e2e753" + "9b4846dd48b866f0ac54d61b9b21a9e746f921cefa4ee94c4c0a1c49c774f67f" + "ca322beec85be24e374d18d582a6f2997f75c54e7993ab5bc07404ce176ca7cd" + "b5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8"); EXPECT_EQ(hex(msgMailCow2Bob3.hashStruct()), "eb4221181ff3f1a83ea7313993ca9218496e424604ba9492bb4052c03d5c3df8"); @@ -331,27 +333,27 @@ TEST(EthereumAbiStruct, encodeTypes_v4Rec) { EXPECT_EQ(hex(msgPersonRecursive.hashType()), "7c5c8e90cb92c8da53b893b24962513be98afcf1b57b00327ae4cc14e3a64116"); - EXPECT_EQ(hex(msgPersonRecursiveMother.encodeHashes()), - "7c5c8e90cb92c8da53b893b24962513be98afcf1b57b00327ae4cc14e3a64116" - "afe4142a2b3e7b0503b44951e6030e0e2c5000ef83c61857e2e6003e7aef8570" - "0000000000000000000000000000000000000000000000000000000000000000" - "88f14be0dd46a8ec608ccbff6d3923a8b4e95cdfc9648f0db6d92a99a264cb36"); + EXPECT_EQ(hex(msgPersonRecursiveMother.encodeHashes()), + "7c5c8e90cb92c8da53b893b24962513be98afcf1b57b00327ae4cc14e3a64116" + "afe4142a2b3e7b0503b44951e6030e0e2c5000ef83c61857e2e6003e7aef8570" + "0000000000000000000000000000000000000000000000000000000000000000" + "88f14be0dd46a8ec608ccbff6d3923a8b4e95cdfc9648f0db6d92a99a264cb36"); EXPECT_EQ(hex(msgPersonRecursiveMother.hashStruct()), "9ebcfbf94f349de50bcb1e3aa4f1eb38824457c99914fefda27dcf9f99f6178b"); - EXPECT_EQ(hex(msgPersonRecursiveFather.encodeHashes()), - "7c5c8e90cb92c8da53b893b24962513be98afcf1b57b00327ae4cc14e3a64116" - "b2a7c7faba769181e578a391a6a6811a3e84080c6a3770a0bf8a856dfa79d333" - "0000000000000000000000000000000000000000000000000000000000000000" - "02cc7460f2c9ff107904cff671ec6fee57ba3dd7decf999fe9fe056f3fd4d56e"); + EXPECT_EQ(hex(msgPersonRecursiveFather.encodeHashes()), + "7c5c8e90cb92c8da53b893b24962513be98afcf1b57b00327ae4cc14e3a64116" + "b2a7c7faba769181e578a391a6a6811a3e84080c6a3770a0bf8a856dfa79d333" + "0000000000000000000000000000000000000000000000000000000000000000" + "02cc7460f2c9ff107904cff671ec6fee57ba3dd7decf999fe9fe056f3fd4d56e"); EXPECT_EQ(hex(msgPersonRecursiveFather.hashStruct()), "b852e5abfeff916a30cb940c4e24c43cfb5aeb0fa8318bdb10dd2ed15c8c70d8"); - EXPECT_EQ(hex(msgPersonRecursive.encodeHashes()), - "7c5c8e90cb92c8da53b893b24962513be98afcf1b57b00327ae4cc14e3a64116" - "e8d55aa98b6b411f04dbcf9b23f29247bb0e335a6bc5368220032fdcb9e5927f" - "9ebcfbf94f349de50bcb1e3aa4f1eb38824457c99914fefda27dcf9f99f6178b" - "b852e5abfeff916a30cb940c4e24c43cfb5aeb0fa8318bdb10dd2ed15c8c70d8"); + EXPECT_EQ(hex(msgPersonRecursive.encodeHashes()), + "7c5c8e90cb92c8da53b893b24962513be98afcf1b57b00327ae4cc14e3a64116" + "e8d55aa98b6b411f04dbcf9b23f29247bb0e335a6bc5368220032fdcb9e5927f" + "9ebcfbf94f349de50bcb1e3aa4f1eb38824457c99914fefda27dcf9f99f6178b" + "b852e5abfeff916a30cb940c4e24c43cfb5aeb0fa8318bdb10dd2ed15c8c70d8"); EXPECT_EQ(hex(msgPersonRecursive.hashStruct()), "fdc7b6d35bbd81f7fa78708604f57569a10edff2ca329c8011373f0667821a45"); @@ -462,7 +464,7 @@ TEST(EthereumAbiStruct, hashStructJson) { })"); ASSERT_EQ(hex(hash), "0b4bb85394b9ebb1c2425e283c9e734a9a7a832622e97c998f77e1c7a3f01a20"); } - { // edge cases + { // edge cases EXPECT_EXCEPTION(ParamStruct::hashStructJson("NOT_A_JSON"), "Could not parse Json"); EXPECT_EXCEPTION(ParamStruct::hashStructJson("+/{\\"), "Could not parse Json"); EXPECT_EXCEPTION(ParamStruct::hashStructJson(""), "Could not parse Json"); @@ -610,7 +612,7 @@ TEST(EthereumAbiStruct, ParamStructMakeStruct) { EXPECT_EQ(hex(s->hashStruct()), "c52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e"); } - { // extra param + { // extra param std::shared_ptr s = ParamStruct::makeStruct("Person", R"({"extra_param": "extra_value", "name": "Cow", "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"})", R"({"Person": [{"name": "name", "type": "string"}, {"name": "wallet", "type": "address"}]})"); @@ -618,14 +620,14 @@ TEST(EthereumAbiStruct, ParamStructMakeStruct) { EXPECT_EQ(s->encodeType(), "Person(string name,address wallet)"); EXPECT_EQ(hex(s->hashStruct()), "fc71e5fa27ff56c350aa531bc129ebdf613b772b6604664f5d8dbe21b85eb0c8"); } - { // empty array + { // empty array std::shared_ptr s = ParamStruct::makeStruct("Person", R"({"extra_param": "extra_value", "name": "Cow", "wallets": []})", R"({"Person": [{"name": "name", "type": "string"}, {"name": "wallets", "type": "address[]"}]})"); ASSERT_NE(s.get(), nullptr); EXPECT_EQ(s->encodeType(), "Person(string name,address[] wallets)"); } - { // missing param + { // missing param std::shared_ptr s = ParamStruct::makeStruct("Person", R"({"wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"})", R"({"Person": [{"name": "name", "type": "string"}, {"name": "wallet", "type": "address"}]})"); @@ -688,7 +690,7 @@ TEST(EthereumAbiStruct, ParamFactoryMakeTypes) { EXPECT_EQ(tt[0]->encodeType(), "Mail(Person from,Person to,string contents)Person(string name,address wallet)"); EXPECT_EQ(tt[1]->encodeType(), "Person(string name,address wallet)"); } - { // edge cases + { // edge cases EXPECT_EXCEPTION(ParamStruct::makeTypes("NOT_A_JSON"), "Could not parse types Json"); EXPECT_EXCEPTION(ParamStruct::makeTypes("+/{\\"), "Could not parse types Json"); EXPECT_EXCEPTION(ParamStruct::makeTypes(""), "Could not parse types Json"); @@ -711,7 +713,7 @@ TEST(EthereumAbiStruct, ParamFactoryMakeType) { ASSERT_EQ(t->getCount(), 2ul); ASSERT_EQ(t->encodeType(), "Person(string name,address wallet)"); } - { // edge cases + { // edge cases EXPECT_EXCEPTION(ParamStruct::makeType("", ""), "Missing type name"); EXPECT_EXCEPTION(ParamStruct::makeType("Person", "NOT_A_JSON"), "Could not parse type Json"); EXPECT_EXCEPTION(ParamStruct::makeType("Person", "+/{\\"), "Could not parse type Json"); @@ -906,3 +908,5 @@ TEST(EthereumAbiStruct, ParamHashStruct) { EXPECT_EQ(hex(p->hashStruct()), "5c6090c0461491a2941743bda5c3658bf1ea53bbd3edcde54e16205e18b45792"); } } +// clang-format on +} // namespace TW::Ethereum::tests diff --git a/tests/Ethereum/AddressTests.cpp b/tests/Ethereum/AddressTests.cpp index f2fab5a7c5a..2c4ca5745e7 100644 --- a/tests/Ethereum/AddressTests.cpp +++ b/tests/Ethereum/AddressTests.cpp @@ -11,7 +11,8 @@ #include using namespace TW; -using namespace TW::Ethereum; + +namespace TW::Ethereum::tests { TEST(EthereumAddress, Invalid) { ASSERT_FALSE(Address::isValid("abc")); @@ -22,24 +23,19 @@ TEST(EthereumAddress, Invalid) { TEST(EthereumAddress, EIP55) { ASSERT_EQ( Address(parse_hex("5aaeb6053f3e94c9b9a09f33669435e7ef1beaed")).string(), - "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed" - ); + "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"); ASSERT_EQ( Address(parse_hex("0x5AAEB6053F3E94C9b9A09f33669435E7Ef1BEAED")).string(), - "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed" - ); + "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"); ASSERT_EQ( Address(parse_hex("0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359")).string(), - "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359" - ); + "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"); ASSERT_EQ( Address(parse_hex("0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB")).string(), - "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB" - ); + "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"); ASSERT_EQ( Address(parse_hex("0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb")).string(), - "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb" - ); + "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"); } TEST(EthereumAddress, String) { @@ -59,3 +55,5 @@ TEST(EthereumAddress, IsValid) { ASSERT_FALSE(Address::isValid("abc")); ASSERT_TRUE(Address::isValid("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")); } + +} // namespace TW::Ethereum::tests diff --git a/tests/FIO/TransactionBuilderTests.cpp b/tests/FIO/TransactionBuilderTests.cpp index 816c8025fb1..e1d2945f1e3 100644 --- a/tests/FIO/TransactionBuilderTests.cpp +++ b/tests/FIO/TransactionBuilderTests.cpp @@ -5,22 +5,23 @@ // file LICENSE at the root of the source code distribution tree. #include "FIO/Action.h" +#include "FIO/NewFundsRequest.h" #include "FIO/Transaction.h" #include "FIO/TransactionBuilder.h" -#include "FIO/NewFundsRequest.h" -#include "HexCoding.h" #include "BinaryCoding.h" +#include "HexCoding.h" #include -#include #include +#include using namespace TW; using namespace TW::FIO; using namespace std; +namespace TW::FIO::tests { const Data chainId = parse_hex("4e46572250454b796d7296eec9e8896327ea82dd40f2cd74cf1b1d8ba90bcd77"); // 5KEDWtAUJcFX6Vz38WXsAQAv2geNqT7UaZC8gYu9kTuryr3qkri FIO6m1fMdTpRkRBnedvYshXCxLFiC5suRU8KDfx8xxtXp2hntxpnf @@ -50,7 +51,7 @@ TEST(FIOTransactionBuilder, RegisterFioAddress) { uint64_t fee = 5000000000; string t = TransactionBuilder::createRegisterFioAddress(addr6M, privKeyBA, "adam@fiotestnet", - chainParams, fee, "rewards@wallet", 1579784511); + chainParams, fee, "rewards@wallet", 1579784511); EXPECT_EQ(R"({"compression":"none","packed_context_free_data":"","packed_trx":"3f99295ec99b904215ff0000000001003056372503a85b0000c6eaa66498ba01102b2f46fca756b200000000a8ed3232650f6164616d4066696f746573746e65743546494f366d31664d645470526b52426e6564765973685843784c4669433573755255384b44667838787874587032686e7478706e6600f2052a01000000102b2f46fca756b20e726577617264734077616c6c657400","signatures":["SIG_K1_K19ugLriG3ApYgjJCRDsy21p9xgsjbDtqBuZrmAEix9XYzndR1kNbJ6fXCngMJMAhxUHfwHAsPnh58otXiJZkazaM1EkS5"]})", t); } @@ -58,11 +59,8 @@ TEST(FIOTransactionBuilder, RegisterFioAddress) { TEST(FIOTransactionBuilder, AddPubAddress) { ChainParams chainParams{chainId, 11565, 4281229859}; - string t = TransactionBuilder::createAddPubAddress(addr6M, privKeyBA, "adam@fiotestnet", { - {"BTC", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v"}, - {"ETH", "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51"}, - {"BNB", "bnb1ts3dg54apwlvr9hupv2n0j6e46q54znnusjk9s"}}, - chainParams, 0, "rewards@wallet", 1579729429); + string t = TransactionBuilder::createAddPubAddress(addr6M, privKeyBA, "adam@fiotestnet", {{"BTC", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v"}, {"ETH", "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51"}, {"BNB", "bnb1ts3dg54apwlvr9hupv2n0j6e46q54znnusjk9s"}}, + chainParams, 0, "rewards@wallet", 1579729429); EXPECT_EQ(R"({"compression":"none","packed_context_free_data":"","packed_trx":"15c2285e2d2d23622eff0000000001003056372503a85b0000c6eaa664523201102b2f46fca756b200000000a8ed3232c9010f6164616d4066696f746573746e65740303425443034254432a626331717679343037347267676b647232707a773576706e6e3632656730736d7a6c787770373064377603455448034554482a30786365356342366339324461333762624261393142643430443443394434443732344133613846353103424e4203424e422a626e6231747333646735346170776c76723968757076326e306a366534367135347a6e6e75736a6b39730000000000000000102b2f46fca756b20e726577617264734077616c6c657400","signatures":["SIG_K1_K3zimaMKU8cBhVRPw46KM2u7uQWaAKXrnoeYZ7MEbp6sVJcDQmQR2RtdavpUPwkAnYUkd8NqLun8H48tcxZBcTUgkiPGVJ"]})", t); } @@ -74,7 +72,7 @@ TEST(FIOTransactionBuilder, Transfer) { uint64_t fee = 250000000; string t = TransactionBuilder::createTransfer(addr6M, privKeyBA, payee, amount, - chainParams, fee, "rewards@wallet", 1579790000); + chainParams, fee, "rewards@wallet", 1579790000); EXPECT_EQ(R"({"compression":"none","packed_context_free_data":"","packed_trx":"b0ae295e50c3400a6dee00000000010000980ad20ca85be0e1d195ba85e7cd01102b2f46fca756b200000000a8ed32325d3546494f37754d5a6f6565693548745841443234433479436b70575762663234626a597472524e6a57646d474358485a63637775694500ca9a3b0000000080b2e60e00000000102b2f46fca756b20e726577617264734077616c6c657400","signatures":["SIG_K1_K9VRCnvaTYN7vgcoVKVXgyJTdKUGV8hLXgFLoEbvqAcFxy7DXQ1rSnAfEuabi4ATkgmvnpaSBdVFN7TBtM1wrbZYqeJQw9"]})", t); } @@ -84,7 +82,7 @@ TEST(FIOTransactionBuilder, RenewFioAddress) { uint64_t fee = 3000000000; string t = TransactionBuilder::createRenewFioAddress(addr6M, privKeyBA, "nick@fiotestnet", - chainParams, fee, "rewards@wallet", 1579785000); + chainParams, fee, "rewards@wallet", 1579785000); EXPECT_EQ(R"({"compression":"none","packed_context_free_data":"","packed_trx":"289b295ec99b904215ff0000000001003056372503a85b80b1ba2919aea6ba01102b2f46fca756b200000000a8ed32322f0f6e69636b4066696f746573746e6574005ed0b200000000102b2f46fca756b20e726577617264734077616c6c657400","signatures":["SIG_K1_Jxz7oCJ7Z4ECsxqb2utqBcyP3zPQCeQCBws9wWQjyptUKoWVk2AyCVEqtdMHJwqtLniio5Z7npMnaZB8E4pa2G75P9uGkb"]})", t); } @@ -94,7 +92,7 @@ TEST(FIOTransactionBuilder, NewFundsRequest) { ChainParams chainParams{chainId, 18484, 3712870657}; const Data iv = parse_hex("000102030405060708090a0b0c0d0e0f"); // use fixed iv for testability string t = TransactionBuilder::createNewFundsRequest( - Address("FIO5NMm9Vf3NjYFnhoc7yxTCrLW963KPUCzeMGv3SJ6zR3GMez4ub"), privKeyBA, + Address("FIO5NMm9Vf3NjYFnhoc7yxTCrLW963KPUCzeMGv3SJ6zR3GMez4ub"), privKeyBA, "tag@fiotestnet", "FIO7iYHtDhs45smFgSqLyJ6Zi4D3YG8K5bZGyxmshLCDXXBPbbmJN", "dapixbp@fiotestnet", "14R4wEsGT58chmqo7nB65Dy4je6TiijDWc", "1", "BTC", "payment", "", "", chainParams, 800000000, "", 1583528215, iv); @@ -103,19 +101,19 @@ TEST(FIOTransactionBuilder, NewFundsRequest) { ChainParams chainParams{chainId, 39881, 4279583376}; uint64_t fee = 3000000000; - + const Data iv = parse_hex("000102030405060708090a0b0c0d0e0f"); // use fixed iv for testability string t = TransactionBuilder::createNewFundsRequest(addr6M, privKeyBA, - "mario@fiotestnet", "FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o", "alice@fiotestnet", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v", - "5", "BTC", "Memo", "Hash", "https://trustwallet.com", - chainParams, fee, "rewards@wallet", 1579785000, iv); + "mario@fiotestnet", "FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o", "alice@fiotestnet", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v", + "5", "BTC", "Memo", "Hash", "https://trustwallet.com", + chainParams, fee, "rewards@wallet", 1579785000, iv); EXPECT_EQ(R"({"compression":"none","packed_context_free_data":"","packed_trx":"289b295ec99b904215ff000000000100403ed4aa0ba85b00acba384dbdb89a01102b2f46fca756b200000000a8ed32328802106d6172696f4066696f746573746e657410616c6963654066696f746573746e6574c00141414543417751464267634943516f4c4441304f442f3575342f6b436b7042554c4a44682f546951334d31534f4e4938426668496c4e54766d39354249586d54396f616f7a55632f6c6c3942726e57426563464e767a76766f6d3751577a517250717241645035683433305732716b52355266416555446a704f514732364c347a6936767241553052764855474e382b685779736a6971506b2b7a455a444952534678426268796c69686d59334f4752342f5a46466358484967343241327834005ed0b2000000000c716466656a7a32613577706c0e726577617264734077616c6c657400","signatures":["SIG_K1_Kk79iVcQMpqpVgZwGTmC1rxgCTLy5BDFtHd8FvjRNm2FqNHR9dpeUmPTNqBKGMNG3BsPy4c5u26TuEDpS87SnyMpF43cZk"]})", t); } TEST(FIOTransaction, ActionRegisterFioAddressInternal) { RegisterFioAddressData radata("adam@fiotestnet", addr6M.string(), - 5000000000, "rewards@wallet", "qdfejz2a5wpl"); + 5000000000, "rewards@wallet", "qdfejz2a5wpl"); Data ser1; radata.serialize(ser1); EXPECT_EQ( @@ -153,11 +151,8 @@ TEST(FIOTransaction, ActionRegisterFioAddressInternal) { } TEST(FIOTransaction, ActionAddPubAddressInternal) { - AddPubAddressData aadata("adam@fiotestnet", { - {"BTC", "BTC", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v"}, - {"ETH", "ETH", "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51"}, - {"BNB", "BNB", "bnb1ts3dg54apwlvr9hupv2n0j6e46q54znnusjk9s"}}, - 0, "rewards@wallet", "qdfejz2a5wpl"); + AddPubAddressData aadata("adam@fiotestnet", {{"BTC", "BTC", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v"}, {"ETH", "ETH", "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51"}, {"BNB", "BNB", "bnb1ts3dg54apwlvr9hupv2n0j6e46q54znnusjk9s"}}, + 0, "rewards@wallet", "qdfejz2a5wpl"); Data ser1; aadata.serialize(ser1); EXPECT_EQ( @@ -196,21 +191,21 @@ TEST(FIOTransaction, ActionAddPubAddressInternal) { TEST(FIONewFundsContent, serialize) { { - NewFundsContent newFunds {"bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v", "10", "BTC", "BTC", "Memo", "Hash", "https://trustwallet.com"}; + NewFundsContent newFunds{"bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v", "10", "BTC", "BTC", "Memo", "Hash", "https://trustwallet.com"}; Data ser; newFunds.serialize(ser); EXPECT_EQ(hex(ser), "2a626331717679343037347267676b647232707a773576706e6e3632656730736d7a6c78777037306437760231300342544303425443044d656d6f04486173681768747470733a2f2f747275737477616c6c65742e636f6d0000000000"); } { // empty struct - NewFundsContent newFunds {"", "", "", "", "", "", ""}; + NewFundsContent newFunds{"", "", "", "", "", "", ""}; Data ser; newFunds.serialize(ser); EXPECT_EQ(hex(ser), "000000000000000000000000"); } { // test from https://github.com/fioprotocol/fiojs/blob/master/src/tests/encryption-fio.test.ts - NewFundsContent newFunds {"purse.alice", "1", "", "fio.reqobt", "", "", ""}; + NewFundsContent newFunds{"purse.alice", "1", "", "fio.reqobt", "", "", ""}; Data ser; newFunds.serialize(ser); EXPECT_EQ(hex(ser), "0b70757273652e616c6963650131000a66696f2e7265716f62740000000000000000"); @@ -250,9 +245,8 @@ TEST(FIOTransactionBuilder, expirySetDefault) { // May throw nlohmann::json::type_error void createTxWithChainParam(const ChainParams& paramIn, ChainParams& paramOut) { - string tx = TransactionBuilder::createAddPubAddress(addr6M, privKeyBA, "adam@fiotestnet", { - {"BTC", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v"}}, - paramIn, 0, "rewards@wallet", 1579729429); + string tx = TransactionBuilder::createAddPubAddress(addr6M, privKeyBA, "adam@fiotestnet", {{"BTC", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v"}}, + paramIn, 0, "rewards@wallet", 1579729429); // retrieve chain params from encoded tx; parse out packed tx try { nlohmann::json txJson = nlohmann::json::parse(tx); @@ -356,3 +350,5 @@ TEST(FIOTransactionBuilder, encodeString) { EXPECT_EQ(hex(data), "8201" + hex(text)); } } + +} // namespace TW::FIO::tests diff --git a/tests/Filecoin/AddressTests.cpp b/tests/Filecoin/AddressTests.cpp index db657eda357..be2bd2355b9 100644 --- a/tests/Filecoin/AddressTests.cpp +++ b/tests/Filecoin/AddressTests.cpp @@ -11,8 +11,8 @@ #include using namespace TW; -using namespace TW::Filecoin; +namespace TW::Filecoin::tests { // clang-format off struct address_test { @@ -97,3 +97,5 @@ TEST(FilecoinAddress, FromString) { ASSERT_EQ(hex(a.bytes), test.hex) << "Address(" << test.encoded << ")"; } } + +} diff --git a/tests/Filecoin/TWAnySignerTests.cpp b/tests/Filecoin/TWAnySignerTests.cpp index ee9c85f7f95..0f7c0ae4d5c 100644 --- a/tests/Filecoin/TWAnySignerTests.cpp +++ b/tests/Filecoin/TWAnySignerTests.cpp @@ -15,7 +15,8 @@ #include using namespace TW; -using namespace Filecoin; + +namespace TW::Filecoin::tests { TEST(TWAnySignerFilecoin, Sign) { Proto::SigningInput input; @@ -67,3 +68,5 @@ TEST(TWAnySignerFilecoin, SignJSON) { ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeFilecoin)); assertStringsEqual(result, R"({"Message":{"From":"f1z4a36sc7mfbv4z3qwutblp2flycdui3baffytbq","GasFeeCap":"700000000000000000000","GasLimit":1000,"GasPremium":"800000000000000000000","Nonce":2,"To":"f3um6uo3qt5of54xjbx3hsxbw5mbsc6auxzrvfxekn5bv3duewqyn2tg5rhrlx73qahzzpkhuj7a34iq7oifsq","Value":"600000000000000000000"},"Signature":{"Data":"jMRu+OZ/lfppgmqSfGsntFrRLWZnUg3ZYmJTTRLsVt4V1310vR3VKGJpaE6S4sNvDOE6sEgmN9YmfTkPVK2qMgE=","Type":1}})"); } + +} // namespace TW::Filecoin::tests diff --git a/tests/Harmony/AddressTests.cpp b/tests/Harmony/AddressTests.cpp index e5ed260abda..eac8744c266 100644 --- a/tests/Harmony/AddressTests.cpp +++ b/tests/Harmony/AddressTests.cpp @@ -11,7 +11,8 @@ #include using namespace TW; -using namespace TW::Harmony; + +namespace TW::Harmony::tests { TEST(HarmonyAddress, FromString) { Address sender; @@ -42,3 +43,5 @@ TEST(HarmonyAddress, FromPrivateKey) { const auto address = Address(publicKey); ASSERT_EQ(address.string(), "one1a50tun737ulcvwy0yvve0pvu5skq0kjargvhwe"); } + +} // namespace TW::Harmony::tests diff --git a/tests/Harmony/TWAnySignerTests.cpp b/tests/Harmony/TWAnySignerTests.cpp index 08415e5356a..5278c3ff18e 100644 --- a/tests/Harmony/TWAnySignerTests.cpp +++ b/tests/Harmony/TWAnySignerTests.cpp @@ -6,15 +6,16 @@ // file LICENSE at the root of the source code distribution tree. #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" #include "proto/Harmony.pb.h" #include "uint256.h" +#include "../interface/TWTestUtilities.h" #include #include using namespace TW; -using namespace Harmony; + +namespace TW::Harmony::tests { static auto TEST_RECEIVER = "one129r9pj3sk0re76f7zs3qz92rggmdgjhtwge62k"; @@ -72,3 +73,5 @@ TEST(TWAnySignerHarmony, SignJSON) { ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeHarmony)); assertStringsEqual(result, "f86a0180825208018094514650ca30b3c79f693e14220115434236d44aeb8906bfc8da5ee82200008028a084cc200aab11f5e1b2f7ece0d56ec67385ac50cefb6e3dc2a2f3e036ed575a5ca0643f18005b790cac8d8e7dc90e6147df0b83874b52db198864694ea28a79e6fc"); } + +} // namespace TW::Harmony::tests diff --git a/tests/Icon/AddressTests.cpp b/tests/Icon/AddressTests.cpp index f5fbc583a2c..a9ed8262e39 100644 --- a/tests/Icon/AddressTests.cpp +++ b/tests/Icon/AddressTests.cpp @@ -4,14 +4,15 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Icon/Address.h" #include "HexCoding.h" +#include "Icon/Address.h" #include "PrivateKey.h" #include using namespace TW; -using namespace TW::Icon; + +namespace TW::Icon::tests { TEST(IconAddress, Validation) { ASSERT_TRUE(Address::isValid("cx116f042497e5f34268b1b91e742680f84cf4e9f3")); @@ -37,3 +38,5 @@ TEST(IconAddress, FromPrivateKey) { ASSERT_EQ(address.string(), "hx98c0832ca5bd8e8bf355ca9491888aa9725c2c48"); } + +} // namespace TW::Icon::tests diff --git a/tests/Icon/TWAnySignerTests.cpp b/tests/Icon/TWAnySignerTests.cpp index a1b6e5ce289..ca9f6b070d3 100644 --- a/tests/Icon/TWAnySignerTests.cpp +++ b/tests/Icon/TWAnySignerTests.cpp @@ -5,17 +5,18 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" -#include #include "Data.h" #include "HexCoding.h" -#include "uint256.h" #include "proto/Icon.pb.h" +#include "uint256.h" +#include "../interface/TWTestUtilities.h" +#include #include using namespace TW; -using namespace TW::Icon; + +namespace TW::Icon::tests { TEST(TWAnySignerIcon, Sign) { auto key = parse_hex("2d42994b2f7735bbc93a3e64381864d06747e574aa94655c516f9ad0a74eed79"); @@ -46,3 +47,5 @@ TEST(TWAnySignerIcon, Sign) { auto expected = std::string("{\"from\":\"hxbe258ceb872e08851f1f59694dac2558708ece11\",\"nid\":\"0x1\",\"nonce\":\"0x1\",\"signature\":\"xR6wKs+IA+7E91bT8966jFKlK5mayutXCvayuSMCrx9KB7670CsWa0B7LQzgsxU0GLXaovlAT2MLs1XuDiSaZQE=\",\"stepLimit\":\"0x12345\",\"timestamp\":\"0x563a6cf330136\",\"to\":\"hx5bfdb090f43a808005ffc27c25b213145e80b7cd\",\"value\":\"0xde0b6b3a7640000\",\"version\":\"0x3\"}"); ASSERT_EQ(output.encoded(), expected); } + +} // namespace TW::Icon::tests diff --git a/tests/Litecoin/LitecoinAddressTests.cpp b/tests/Litecoin/LitecoinAddressTests.cpp index 15e454f8e09..6858723ce13 100644 --- a/tests/Litecoin/LitecoinAddressTests.cpp +++ b/tests/Litecoin/LitecoinAddressTests.cpp @@ -13,11 +13,12 @@ #include #include -#include #include +#include using namespace TW; -using namespace TW::Bitcoin; + +namespace TW::Bitcoin::tests { TEST(LitecoinAddress, deriveAddress_legacy) { const auto pubKey = PublicKey(parse_hex("03b49081a4d7ad24b20e209bc6fe10491aadb5607777baf0509a036cce96025db0"), TWPublicKeyTypeSECP256k1); @@ -36,3 +37,5 @@ TEST(LitecoinAddress, deriveAddress_segwit) { const auto address = SegwitAddress(pubKey, stringForHRP(TWCoinTypeHRP(TWCoinTypeLitecoin))); EXPECT_EQ(address.string(), addrStr); } + +} // namespace TW::Bitcoin::tests diff --git a/tests/Litecoin/TWLitecoinTests.cpp b/tests/Litecoin/TWLitecoinTests.cpp index 46dd87b280f..35daa1d0a8c 100644 --- a/tests/Litecoin/TWLitecoinTests.cpp +++ b/tests/Litecoin/TWLitecoinTests.cpp @@ -15,6 +15,8 @@ #include +namespace TW::Litecoin::tests { + TEST(Litecoin, LegacyAddress) { auto privateKey = WRAP(TWPrivateKey, TWPrivateKeyCreateWithData(DATA("a22ddec5c567b4488bb00f69b6146c50da2ee883e2c096db098726394d585730").get())); auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(privateKey.get(), true)); @@ -46,9 +48,8 @@ TEST(Litecoin, LockScriptForAddressM) { TEST(Litecoin, ExtendedKeys) { auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic( - STRING("ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal").get(), - STRING("TREZOR").get() - )); + STRING("ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal").get(), + STRING("TREZOR").get())); // .bip44 auto lptv = WRAPS(TWHDWalletGetExtendedPrivateKey(wallet.get(), TWPurposeBIP44, TWCoinTypeLitecoin, TWHDVersionLTPV)); @@ -99,3 +100,5 @@ TEST(Litecoin, LockScripts) { auto scriptData3 = WRAPD(TWBitcoinScriptData(script3.get())); assertHexEqual(scriptData3, "76a914e771c6695c5dd189ccc4ef00cd0f3db3096d79bd88ac"); } + +} // namespace TW::Litecoin::tests diff --git a/tests/NEO/AddressTests.cpp b/tests/NEO/AddressTests.cpp index fa6adb863c0..c17f9b8a5c9 100644 --- a/tests/NEO/AddressTests.cpp +++ b/tests/NEO/AddressTests.cpp @@ -4,16 +4,17 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "PublicKey.h" #include "HexCoding.h" #include "NEO/Address.h" #include "NEO/Signer.h" +#include "PublicKey.h" #include using namespace std; using namespace TW; -using namespace TW::NEO; + +namespace TW::NEO::tests { TEST(NEOAddress, FromPublicKey) { const auto publicKey = PublicKey(parse_hex("0222b2277d039d67f4197a638dd5a1d99c290b17aa8c4a16ccee5165fe612de66a"), TWPublicKeyTypeSECP256k1); @@ -55,7 +56,6 @@ TEST(NEOAddress, fromString) { EXPECT_THROW(new Address(errB58Str), std::invalid_argument); } - TEST(NEOAddress, Valid) { ASSERT_TRUE(Address::isValid("ANDfjwrUroaVtvBguDtrWKRMyxFwvVwnZD")); } @@ -71,3 +71,4 @@ TEST(NEOAddress, FromPrivateKey) { ASSERT_EQ(address.string(), "AQCSMB3oSDA1dHPn6GXN6KB4NHmdo1fX41"); } +} // namespace TW::NEO::tests diff --git a/tests/Nano/AddressTests.cpp b/tests/Nano/AddressTests.cpp index 8812a0c152b..2c3435a11ee 100644 --- a/tests/Nano/AddressTests.cpp +++ b/tests/Nano/AddressTests.cpp @@ -5,14 +5,15 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Nano/Address.h" #include "HexCoding.h" +#include "Nano/Address.h" #include using namespace std; using namespace TW; -using namespace TW::Nano; + +namespace TW::Nano::tests { TEST(NanoAddress, FromPublicKey) { { @@ -53,3 +54,5 @@ TEST(NanoAddress, isValid) { ASSERT_FALSE(Address::isValid(faultyChecksumAddress)); ASSERT_FALSE(Address::isValid(bitcoinAddress)); } + +} // namespace TW::Nano::tests diff --git a/tests/Nano/SignerTests.cpp b/tests/Nano/SignerTests.cpp index 30dd6845de7..966198c3bc0 100644 --- a/tests/Nano/SignerTests.cpp +++ b/tests/Nano/SignerTests.cpp @@ -5,13 +5,14 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Nano/Signer.h" #include "HexCoding.h" +#include "Nano/Signer.h" #include using namespace TW; -using namespace TW::Nano; + +namespace TW::Nano::tests { const std::string kPrivateKey{"173c40e97fe2afcd24187e74f6b603cb949a5365e72fbdd065a6b165e2189e34"}; const std::string kRepOfficial1{"xrb_3arg3asgtigae3xckabaaewkx3bzsh7nwz7jkmjos79ihyaxwphhm6qgjps4"}; @@ -205,3 +206,5 @@ TEST(NanoSigner, signInvalid7) { ASSERT_THROW(Signer signer(input), std::invalid_argument); } + +} // namespace TW::Nano::tests diff --git a/tests/Nano/TWAnySignerTests.cpp b/tests/Nano/TWAnySignerTests.cpp index 54638c40b5b..a348de09dae 100644 --- a/tests/Nano/TWAnySignerTests.cpp +++ b/tests/Nano/TWAnySignerTests.cpp @@ -12,7 +12,8 @@ #include using namespace TW; -using namespace TW::Nano; + +namespace TW::Nano::tests { TEST(TWAnySignerNano, sign) { const auto privateKey = parse_hex("173c40e97fe2afcd24187e74f6b603cb949a5365e72fbdd065a6b165e2189e34"); @@ -49,3 +50,5 @@ TEST(TWAnySignerNano, SignJSON) { ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeNano)); assertStringsEqual(result, R"({"account":"nano_1bhbsc9yuh15anq3owu1izw1nk7bhhqefrkhfo954fyt8dk1q911buk1kk4c","balance":"96242336390000000000000000000","link":"491fca2c69a84607d374aaf1f6acd3ce70744c5be0721b5ed394653e85233507","link_as_account":"nano_1kazsap8mc481zbqbcqjytpf9mmigj87qr5k5fhf97579t4k8fa94octjx6d","previous":"0000000000000000000000000000000000000000000000000000000000000000","representative":"nano_3arg3asgtigae3xckabaaewkx3bzsh7nwz7jkmjos79ihyaxwphhm6qgjps4","signature":"d247f6b90383b24e612569c75a12f11242f6e03b4914eadc7d941577dcf54a3a7cb7f0a4aba4246a40d9ebb5ee1e00b4a0a834ad5a1e7bef24e11f62b95a9e09","type":"state"})"); } + +} // namespace TW::Nano::tests diff --git a/tests/Nimiq/AddressTests.cpp b/tests/Nimiq/AddressTests.cpp index 2bc4cfa2403..b25fda815cb 100644 --- a/tests/Nimiq/AddressTests.cpp +++ b/tests/Nimiq/AddressTests.cpp @@ -12,7 +12,8 @@ #include using namespace TW; -using namespace TW::Nimiq; + +namespace TW::Nimiq::tests { TEST(NimiqAddress, IsValid) { // No address @@ -35,18 +36,15 @@ TEST(NimiqAddress, String) { // Address to string ASSERT_EQ( Address(parse_hex("5b3e9e5f32b89abafc3708765dc8f00216cefbb1")).string(), - "NQ61 BCY9 UPRJ P2DB MY1P 11T5 TJ7G 08BC VXVH" - ); + "NQ61 BCY9 UPRJ P2DB MY1P 11T5 TJ7G 08BC VXVH"); // Without spaces ASSERT_EQ( Address("NQ862H8FYGU5RM77QSN9LYLHC56ACYYR0MLA").string(), - "NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA" - ); + "NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA"); // With spaces ASSERT_EQ( Address("NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA").string(), - "NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA" - ); + "NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA"); } TEST(NimiqAddress, FromPublicKey) { @@ -55,3 +53,5 @@ TEST(NimiqAddress, FromPublicKey) { const auto address = Address(publicKey); ASSERT_EQ(address.string(), "NQ27 GBAY EVHP HK5X 6JHV JGFJ 5M3H BF4Y G7GD"); } + +} // namespace TW::Nimiq::tests diff --git a/tests/Oasis/AddressTests.cpp b/tests/Oasis/AddressTests.cpp index 4d5cb972282..ce1436525f5 100644 --- a/tests/Oasis/AddressTests.cpp +++ b/tests/Oasis/AddressTests.cpp @@ -6,13 +6,14 @@ #include "HexCoding.h" #include "Oasis/Address.h" -#include "PublicKey.h" #include "PrivateKey.h" +#include "PublicKey.h" #include #include using namespace TW; -using namespace TW::Oasis; + +namespace TW::Oasis::tests { TEST(OasisAddress, Valid) { ASSERT_TRUE(Address::isValid("oasis1qp0cnmkjl22gky6p6qeghjytt4v7dkxsrsmueweh")); @@ -26,8 +27,8 @@ TEST(OasisAddress, Invalid) { TEST(OasisAddress, ForceInvalid) { try { auto addressString = "oasis1qp0cnmkjl22gky6p6qeghjytt4v7dkxsrsmuewehj"; - auto address = Address( addressString ); - } catch( std::invalid_argument& e1 ) { + auto address = Address(addressString); + } catch (std::invalid_argument& e1) { return; } FAIL() << "This test should generate an exception as it an invalid address"; @@ -36,8 +37,8 @@ TEST(OasisAddress, ForceInvalid) { TEST(OasisAddress, FromWrongData) { try { auto dataString = "asdadfasdfsdfwrwrsadasdasdsad"; - auto address = Address( data( dataString ) ); - } catch( std::invalid_argument& e1 ) { + auto address = Address(data(dataString)); + } catch (std::invalid_argument& e1) { return; } FAIL() << "This test should generate an exception as it an invalid data"; @@ -59,7 +60,7 @@ TEST(OasisAddress, WrongPublicKeyType) { try { auto publicKey = PublicKey(parse_hex("aba52c0dcb80c2fe96ed4c3741af40c573a0500c0d73acda22795c37cb0f1739"), TWPublicKeyTypeED25519Cardano); auto address = Address(publicKey); - } catch( std::invalid_argument& e1 ) { + } catch (std::invalid_argument& e1) { return; } FAIL() << "TWPublicKeyTypeED25519Cardano should generate an exception as it an invalid publicKey type"; @@ -72,3 +73,5 @@ TEST(OasisAddress, FromString) { ASSERT_FALSE(Address::decode("oasis1hts399h023jqd7v6vgm6dxvcguwe4rgvqqgvq38ng", address)); } + +} // namespace TW::Oasis::tests diff --git a/tests/Oasis/SignerTests.cpp b/tests/Oasis/SignerTests.cpp index 9e8b454f8d7..2cf9ba958a4 100644 --- a/tests/Oasis/SignerTests.cpp +++ b/tests/Oasis/SignerTests.cpp @@ -4,16 +4,17 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Oasis/Signer.h" -#include "Oasis/Address.h" #include "HexCoding.h" +#include "Oasis/Address.h" +#include "Oasis/Signer.h" #include "PrivateKey.h" #include "PublicKey.h" #include using namespace TW; -using namespace TW::Oasis; + +namespace TW::Oasis::tests { TEST(OasisSigner, Sign) { auto input = Proto::SigningInput(); @@ -33,5 +34,7 @@ TEST(OasisSigner, Sign) { Proto::SigningOutput output = Signer::sign(input); - ASSERT_EQ(hex(output.encoded()),"a273756e747275737465645f7261775f76616c7565585ea4656e6f6e636500666d6574686f64707374616b696e672e5472616e7366657263666565a2636761730066616d6f756e74410064626f6479a262746f5500c73cc001463434915ba3f39751beb7c0905b45eb66616d6f756e744400989680697369676e6174757265a26a7075626c69635f6b6579582093d8f8a455f50527976a8aa87ebde38d5606efa86cb985d3fb466aff37000e3b697369676e61747572655840e331ce731ed819106586152b13cd98ecf3248a880bdc71174ee3d83f6d5f3f8ee8fc34c19b22032f2f1e3e06d382720125d7a517fba9295c813228cc2b63170b"); + ASSERT_EQ(hex(output.encoded()), "a273756e747275737465645f7261775f76616c7565585ea4656e6f6e636500666d6574686f64707374616b696e672e5472616e7366657263666565a2636761730066616d6f756e74410064626f6479a262746f5500c73cc001463434915ba3f39751beb7c0905b45eb66616d6f756e744400989680697369676e6174757265a26a7075626c69635f6b6579582093d8f8a455f50527976a8aa87ebde38d5606efa86cb985d3fb466aff37000e3b697369676e61747572655840e331ce731ed819106586152b13cd98ecf3248a880bdc71174ee3d83f6d5f3f8ee8fc34c19b22032f2f1e3e06d382720125d7a517fba9295c813228cc2b63170b"); } + +} // namespace TW::Oasis::tests diff --git a/tests/Ontology/TWAnySignerTests.cpp b/tests/Ontology/TWAnySignerTests.cpp index bb6786dc0ef..f9cfe0be93d 100644 --- a/tests/Ontology/TWAnySignerTests.cpp +++ b/tests/Ontology/TWAnySignerTests.cpp @@ -15,7 +15,8 @@ #include using namespace TW; -using namespace TW::Ontology; + +namespace TW::Ontology::tests { TEST(TWAnySingerOntology, OntBalanceOf) { // curl -H "Content-Type: application/json" -X POST -d '{"Action":"sendrawtransaction", @@ -188,3 +189,5 @@ TEST(TWAnySingerOntology, OngWithdraw) { "2403d9114f3fa3da0d5aec9dfa42948c2f50738d52470469a1a1eeac", rawTx); } + +} // namespace TW::Ontology::tests diff --git a/tests/Osmosis/AddressTests.cpp b/tests/Osmosis/AddressTests.cpp index ee7b98a56a8..26cd5b668f9 100644 --- a/tests/Osmosis/AddressTests.cpp +++ b/tests/Osmosis/AddressTests.cpp @@ -6,12 +6,15 @@ #include "Cosmos/Address.h" #include "HexCoding.h" -#include "PublicKey.h" #include "PrivateKey.h" +#include "PublicKey.h" #include #include using namespace TW; + +namespace TW::Osmosis::tests { + using namespace TW::Cosmos; TEST(OsmosisAddress, Valid) { @@ -43,3 +46,5 @@ TEST(OsmosisAddress, FromString) { EXPECT_EQ(address.string(), "osmo1mky69cn8ektwy0845vec9upsdphktxt0en97f5"); EXPECT_EQ(hex(address.getKeyHash()), "dd89a2e267cd96e23cf5a33382f030686f65996f"); } + +} // namespace TW::Osmosis::tests diff --git a/tests/Osmosis/SignerTests.cpp b/tests/Osmosis/SignerTests.cpp index f7f33163576..236de95c46c 100644 --- a/tests/Osmosis/SignerTests.cpp +++ b/tests/Osmosis/SignerTests.cpp @@ -6,15 +6,18 @@ #include "Cosmos/Address.h" #include "Cosmos/Signer.h" -#include "proto/Cosmos.pb.h" #include "HexCoding.h" #include "PrivateKey.h" #include "PublicKey.h" +#include "proto/Cosmos.pb.h" #include "../interface/TWTestUtilities.h" #include using namespace TW; + +namespace TW::Osmosis::tests { + using namespace TW::Cosmos; TEST(OsmosisSigner, SignTransfer_81B4) { @@ -57,3 +60,5 @@ TEST(OsmosisSigner, SignTransfer_81B4) { EXPECT_EQ(output.error(), ""); EXPECT_EQ(output.json(), ""); } + +} // namespace TW::Osmosis::tests diff --git a/tests/Osmosis/TWAnySignerTests.cpp b/tests/Osmosis/TWAnySignerTests.cpp index 13b560f0e8a..f599450333d 100644 --- a/tests/Osmosis/TWAnySignerTests.cpp +++ b/tests/Osmosis/TWAnySignerTests.cpp @@ -4,15 +4,18 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include -#include "HexCoding.h" #include "Cosmos/Address.h" +#include "HexCoding.h" #include "proto/Cosmos.pb.h" +#include #include "../interface/TWTestUtilities.h" #include using namespace TW; + +namespace TW::Osmosis::tests { + using namespace TW::Cosmos; TEST(TWAnySignerOsmosis, Sign) { @@ -54,3 +57,5 @@ TEST(TWAnySignerOsmosis, Sign) { EXPECT_EQ(output.json(), ""); EXPECT_EQ(output.error(), ""); } + +} // namespace TW::Osmosis::tests diff --git a/tests/PrivateKeyTests.cpp b/tests/PrivateKeyTests.cpp index e52ea08dfba..f969ce40c8e 100644 --- a/tests/PrivateKeyTests.cpp +++ b/tests/PrivateKeyTests.cpp @@ -4,16 +4,17 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include "Hash.h" +#include "HexCoding.h" #include "PrivateKey.h" #include "PublicKey.h" -#include "HexCoding.h" -#include "Hash.h" #include using namespace TW; using namespace std; +namespace TW::tests { TEST(PrivateKey, CreateValid) { Data privKeyData = parse_hex("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5"); @@ -73,8 +74,7 @@ TEST(PrivateKey, CreateExtendedInvalid) { parse_hex("bf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4"), parse_hex("1111111111111111111111111111111111111111111111111111111111111111"), parse_hex("1111111111111111111111111111111111111111111111111111111111111111"), - parse_hex("1111111111111111111111111111111111111111111111111111111111111111") - ); + parse_hex("1111111111111111111111111111111111111111111111111111111111111111")); EXPECT_EQ("EXCEPTION: Invalid private key or extended key data", res); } { @@ -84,8 +84,7 @@ TEST(PrivateKey, CreateExtendedInvalid) { parse_hex("bf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4"), parse_hex("1111111111111111111111111111111111111111111111111111111111111111"), parse_hex("1111111111111111111111111111111111111111111111111111111111111111"), - parse_hex("1111111111111111111111111111111111111111111111111111111111111111") - ); + parse_hex("1111111111111111111111111111111111111111111111111111111111111111")); EXPECT_EQ("EXCEPTION: Invalid private key or extended key data", res); } { @@ -95,8 +94,7 @@ TEST(PrivateKey, CreateExtendedInvalid) { parse_hex("deadbeed"), parse_hex("1111111111111111111111111111111111111111111111111111111111111111"), parse_hex("1111111111111111111111111111111111111111111111111111111111111111"), - parse_hex("1111111111111111111111111111111111111111111111111111111111111111") - ); + parse_hex("1111111111111111111111111111111111111111111111111111111111111111")); EXPECT_EQ("EXCEPTION: Invalid private key or extended key data", res); } { @@ -106,8 +104,7 @@ TEST(PrivateKey, CreateExtendedInvalid) { parse_hex("bf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4"), parse_hex("deadbeed"), parse_hex("1111111111111111111111111111111111111111111111111111111111111111"), - parse_hex("1111111111111111111111111111111111111111111111111111111111111111") - ); + parse_hex("1111111111111111111111111111111111111111111111111111111111111111")); EXPECT_EQ("EXCEPTION: Invalid private key or extended key data", res); } } @@ -125,29 +122,25 @@ TEST(PrivateKey, PublicKey) { const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519); EXPECT_EQ( "4870d56d074c50e891506d78faa4fb69ca039cc5f131eb491e166b975880e867", - hex(publicKey.bytes) - ); + hex(publicKey.bytes)); } { const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); EXPECT_EQ( "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1", - hex(publicKey.bytes) - ); + hex(publicKey.bytes)); } { const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended); EXPECT_EQ( "0499c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c166b489a4b7c491e7688e6ebea3a71fc3a1a48d60f98d5ce84c93b65e423fde91", - hex(publicKey.bytes) - ); + hex(publicKey.bytes)); } { const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeNIST256p1Extended); EXPECT_EQ( "046d786ab8fda678cf50f71d13641049a393b325063b8c0d4e5070de48a2caf9ab918b4fe46ccbf56701fb210d67d91c5779468f6b3fdc7a63692b9b62543f47ae", - hex(publicKey.bytes) - ); + hex(publicKey.bytes)); } } @@ -179,13 +172,12 @@ TEST(PrivateKey, GetType) { TEST(PrivateKey, PrivateKeyExtended) { // Non-extended: both keys are 32 bytes. auto privateKeyNonext = PrivateKey(parse_hex( - "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5" - )); + "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5")); EXPECT_EQ("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5", hex(privateKeyNonext.bytes)); auto publicKeyNonext = privateKeyNonext.getPublicKey(TWPublicKeyTypeED25519); EXPECT_EQ(32ul, publicKeyNonext.bytes.size()); - const auto fullkey = + const auto fullkey = "b0884d248cb301edd1b34cf626ba6d880bb3ae8fd91b4696446999dc4f0b5744" "309941d56938e943980d11643c535e046653ca6f498c014b88f2ad9fd6e71eff" "bf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4" @@ -203,7 +195,7 @@ TEST(PrivateKey, PrivateKeyExtended) { EXPECT_EQ("ed7f28be986cbe06819165f2ee41b403678a098961013cf4a2f3e9ea61fb6c1a", hex(privateKeyExt.secondChainCode())); auto publicKeyExt = privateKeyExt.getPublicKey(TWPublicKeyTypeED25519Cardano); - EXPECT_EQ(2*64ul, publicKeyExt.bytes.size()); + EXPECT_EQ(2 * 64ul, publicKeyExt.bytes.size()); // Try other constructor for extended key auto privateKeyExtOne = PrivateKey( @@ -212,16 +204,14 @@ TEST(PrivateKey, PrivateKeyExtended) { parse_hex("bf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4"), parse_hex("639aadd8b6499ae39b78018b79255fbd8f585cbda9cbb9e907a72af86afb7a05"), parse_hex("d41a57c2dec9a6a19d6bf3b1fa784f334f3a0048d25ccb7b78a7b44066f9ba7b"), - parse_hex("ed7f28be986cbe06819165f2ee41b403678a098961013cf4a2f3e9ea61fb6c1a") - ); + parse_hex("ed7f28be986cbe06819165f2ee41b403678a098961013cf4a2f3e9ea61fb6c1a")); EXPECT_EQ(fullkey, hex(privateKeyExt.bytes)); } TEST(PrivateKey, PrivateKeyExtendedError) { // TWPublicKeyTypeED25519Cardano pubkey with non-extended private: error auto privateKeyNonext = PrivateKey(parse_hex( - "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5" - )); + "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5")); try { auto publicKeyError = privateKeyNonext.getPublicKey(TWPublicKeyTypeED25519Cardano); } catch (invalid_argument& ex) { @@ -245,8 +235,7 @@ TEST(PrivateKey, getSharedKey) { EXPECT_EQ( "ef2cf705af8714b35c0855030f358f2bee356ff3579cea2607b2025d80133c3a", - hex(derivedKeyData) - ); + hex(derivedKeyData)); } /** @@ -266,12 +255,11 @@ TEST(PrivateKey, getSharedKeyWycherproof) { EXPECT_TRUE(publicKey.isCompressed()); const Data derivedKeyData = privateKey.getSharedKey(publicKey, TWCurveSECP256k1); - + // SHA-256 of encoded x-coordinate `02544dfae22af6af939042b1d85b71a1e49e9a5614123c4d6ad0c8af65baf87d65` EXPECT_EQ( "81165066322732362ca5d3f0991d7f1f7d0aad7ea533276496785d369e35159a", - hex(derivedKeyData) - ); + hex(derivedKeyData)); } TEST(PrivateKey, getSharedKeyBidirectional) { @@ -313,23 +301,20 @@ TEST(PrivateKey, SignSECP256k1) { EXPECT_EQ( "8720a46b5b3963790d94bcc61ad57ca02fd153584315bfa161ed3455e336ba624d68df010ed934b8792c5b6a57ba86c3da31d039f9612b44d1bf054132254de901", - hex(actual) - ); + hex(actual)); } TEST(PrivateKey, SignExtended) { const auto privateKeyExt = PrivateKey(parse_hex( "b0884d248cb301edd1b34cf626ba6d880bb3ae8fd91b4696446999dc4f0b5744309941d56938e943980d11643c535e046653ca6f498c014b88f2ad9fd6e71effbf36a8fa9f5e11eb7a852c41e185e3969d518e66e6893c81d3fc7227009952d4" - "639aadd8b6499ae39b78018b79255fbd8f585cbda9cbb9e907a72af86afb7a05d41a57c2dec9a6a19d6bf3b1fa784f334f3a0048d25ccb7b78a7b44066f9ba7bed7f28be986cbe06819165f2ee41b403678a098961013cf4a2f3e9ea61fb6c1a" - )); + "639aadd8b6499ae39b78018b79255fbd8f585cbda9cbb9e907a72af86afb7a05d41a57c2dec9a6a19d6bf3b1fa784f334f3a0048d25ccb7b78a7b44066f9ba7bed7f28be986cbe06819165f2ee41b403678a098961013cf4a2f3e9ea61fb6c1a")); Data messageData = TW::data("hello"); Data hash = Hash::keccak256(messageData); Data actual = privateKeyExt.sign(hash, TWCurveED25519ExtendedCardano); EXPECT_EQ( "375df53b6a4931dcf41e062b1c64288ed4ff3307f862d5c1b1c71964ce3b14c99422d0fdfeb2807e9900a26d491d5e8a874c24f98eec141ed694d7a433a90f08", - hex(actual) - ); + hex(actual)); } TEST(PrivateKey, SignSchnorr) { @@ -338,8 +323,7 @@ TEST(PrivateKey, SignSchnorr) { const Data digest = Hash::sha256(messageData); const auto signature = privateKey.signZilliqa(digest); EXPECT_EQ(hex(signature), - "b8118ccb99563fe014279c957b0a9d563c1666e00367e9896fe541765246964f64a53052513da4e6dc20fdaf69ef0d95b4ca51c87ad3478986cf053c2dd0b853" - ); + "b8118ccb99563fe014279c957b0a9d563c1666e00367e9896fe541765246964f64a53052513da4e6dc20fdaf69ef0d95b4ca51c87ad3478986cf053c2dd0b853"); } TEST(PrivateKey, SignNIST256p1) { @@ -351,8 +335,7 @@ TEST(PrivateKey, SignNIST256p1) { EXPECT_EQ( "8859e63a0c0cc2fc7f788d7e78406157b288faa6f76f76d37c4cd1534e8d83c468f9fd6ca7dde378df594625dcde98559389569e039282275e3d87c26e36447401", - hex(actual) - ); + hex(actual)); } int isCanonical([[maybe_unused]] uint8_t by, [[maybe_unused]] uint8_t sig[64]) { @@ -368,8 +351,7 @@ TEST(PrivateKey, SignCanonicalSECP256k1) { EXPECT_EQ( "208720a46b5b3963790d94bcc61ad57ca02fd153584315bfa161ed3455e336ba624d68df010ed934b8792c5b6a57ba86c3da31d039f9612b44d1bf054132254de9", - hex(actual) - ); + hex(actual)); } TEST(PrivateKey, SignShortDigest) { @@ -389,3 +371,5 @@ TEST(PrivateKey, SignShortDigest) { EXPECT_EQ(actual.size(), 0ul); } } + +} // namespace TW::tests diff --git a/tests/Ripple/TWAnySignerTests.cpp b/tests/Ripple/TWAnySignerTests.cpp index d7bb05fce48..6bf8bdf5986 100644 --- a/tests/Ripple/TWAnySignerTests.cpp +++ b/tests/Ripple/TWAnySignerTests.cpp @@ -13,7 +13,8 @@ #include using namespace TW; -using namespace TW::Ripple; + +namespace TW::Ripple::tests { TEST(TWAnySignerRipple, Sign) { auto key = parse_hex("ba005cd605d8a02e3d5dfd04234cef3a3ee4f76bfbad2722d1fb5af8e12e6764"); @@ -39,3 +40,5 @@ TEST(TWAnySignerRipple, Sign) { EXPECT_EQ(output.error(), Common::Proto::SigningError::Error_invalid_memo); EXPECT_EQ(output.encoded(), ""); } + +} // namespace TW::Ripple::tests diff --git a/tests/Ronin/TWAnySignerTests.cpp b/tests/Ronin/TWAnySignerTests.cpp index 49e6b5ddbc0..3edbfa75698 100644 --- a/tests/Ronin/TWAnySignerTests.cpp +++ b/tests/Ronin/TWAnySignerTests.cpp @@ -4,15 +4,18 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" -#include #include "HexCoding.h" -#include "uint256.h" #include "proto/Ethereum.pb.h" +#include "uint256.h" +#include "../interface/TWTestUtilities.h" +#include #include using namespace TW; + +namespace TW::Ronin::tests { + using namespace TW::Ethereum; TEST(TWAnySignerRonin, Sign) { @@ -43,3 +46,5 @@ TEST(TWAnySignerRonin, Sign) { ASSERT_EQ(hex(output.encoded()), expected); } + +} // namespace TW::Ronin::tests diff --git a/tests/Solana/AddressTests.cpp b/tests/Solana/AddressTests.cpp index 5af714c46c6..15f011299f9 100644 --- a/tests/Solana/AddressTests.cpp +++ b/tests/Solana/AddressTests.cpp @@ -4,17 +4,18 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Solana/Address.h" -#include "Solana/Program.h" #include "Base58.h" -#include "PrivateKey.h" #include "HexCoding.h" +#include "PrivateKey.h" +#include "Solana/Address.h" +#include "Solana/Program.h" #include using namespace std; using namespace TW; -using namespace TW::Solana; + +namespace TW::Solana::tests { TEST(SolanaAddress, FromPublicKey) { const auto addressString = "2gVkYWexTHR5Hb2aLeQN3tnngvWzisFKXDUPrgMHpdST"; @@ -51,9 +52,11 @@ TEST(SolanaAddress, isValidOnCurve) { TEST(SolanaAddress, defaultTokenAddress) { const Address serumToken = Address("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"); EXPECT_EQ(Address("HBYC51YrGFAZ8rM7Sj8e9uqKggpSrDYrinQDZzvMtqQp").defaultTokenAddress(serumToken).string(), - "6X4X1Ae24mkoWeCEpktevySVG9jzeCufut5vtUW3wFrD"); + "6X4X1Ae24mkoWeCEpktevySVG9jzeCufut5vtUW3wFrD"); EXPECT_EQ(Address("B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V").defaultTokenAddress(serumToken).string(), - "EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); + "EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); EXPECT_EQ(Address("Eg5jqooyG6ySaXKbQUu4Lpvu2SqUPZrNkM4zXs9iUDLJ").defaultTokenAddress(serumToken).string(), - "ANVCrmRw7Ww7rTFfMbrjApSPXEEcZpBa6YEiBdf98pAf"); -} \ No newline at end of file + "ANVCrmRw7Ww7rTFfMbrjApSPXEEcZpBa6YEiBdf98pAf"); +} + +} // namespace TW::Solana::tests diff --git a/tests/Solana/ProgramTests.cpp b/tests/Solana/ProgramTests.cpp index 1aecb102539..f943622e28b 100644 --- a/tests/Solana/ProgramTests.cpp +++ b/tests/Solana/ProgramTests.cpp @@ -4,16 +4,17 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Solana/Address.h" -#include "Solana/Program.h" #include "Base58.h" #include "PrivateKey.h" +#include "Solana/Address.h" +#include "Solana/Program.h" #include using namespace std; using namespace TW; -using namespace TW::Solana; + +namespace TW::Solana::tests { TEST(SolanaStakeProgram, addressFromValidatorSeed) { auto user = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); @@ -43,7 +44,7 @@ TEST(SolanaStakeProgram, addressFromRecentBlockhash) { TEST(SolanaTokenProgram, defaultTokenAddress) { const Address serumToken = Address("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"); EXPECT_EQ(TokenProgram::defaultTokenAddress(Address("HBYC51YrGFAZ8rM7Sj8e9uqKggpSrDYrinQDZzvMtqQp"), serumToken).string(), - "6X4X1Ae24mkoWeCEpktevySVG9jzeCufut5vtUW3wFrD"); + "6X4X1Ae24mkoWeCEpktevySVG9jzeCufut5vtUW3wFrD"); } TEST(SolanaTokenProgram, findProgramAddress) { @@ -67,8 +68,7 @@ TEST(SolanaTokenProgram, createProgramAddress) { Base58::bitcoin.decode("B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"), Base58::bitcoin.decode("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), Base58::bitcoin.decode("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"), - Data{255} - }; + Data{255}}; { Address address = TokenProgram::createProgramAddress(seeds4, Address("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")); EXPECT_EQ(address.string(), "EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); @@ -94,3 +94,5 @@ TEST(SolanaTokenProgram, createProgramAddress) { EXPECT_EQ(address.string(), "GUs5qLUfsEHkcMB9T38vjr18ypEhRuNWiePW2LoK4E3K"); } } + +} // namespace TW::Solana::tests diff --git a/tests/Stellar/AddressTests.cpp b/tests/Stellar/AddressTests.cpp index 9fc5dc06b19..9f55cc55058 100644 --- a/tests/Stellar/AddressTests.cpp +++ b/tests/Stellar/AddressTests.cpp @@ -4,16 +4,17 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Stellar/Address.h" #include "Bitcoin/Address.h" #include "HexCoding.h" #include "PrivateKey.h" +#include "Stellar/Address.h" #include using namespace std; using namespace TW; -using namespace TW::Stellar; + +namespace TW::Stellar::tests { TEST(StellarAddress, FromPublicKey) { const auto publicKey = PublicKey(parse_hex("0103E20EC6B4A39A629815AE02C0A1393B9225E3B890CAE45B59F42FA29BE9668D"), TWPublicKeyTypeED25519); @@ -35,3 +36,5 @@ TEST(StellarAddress, isValid) { ASSERT_TRUE(Address::isValid(stellarAddress)); ASSERT_FALSE(Address::isValid(bitcoinAddress)); } + +} // namespace TW::Stellar::tests diff --git a/tests/Stellar/TWAnySignerTests.cpp b/tests/Stellar/TWAnySignerTests.cpp index b05c73c459c..739f0926bca 100644 --- a/tests/Stellar/TWAnySignerTests.cpp +++ b/tests/Stellar/TWAnySignerTests.cpp @@ -15,7 +15,8 @@ #include using namespace TW; -using namespace TW::Stellar; + +namespace TW::Stellar::tests { TEST(TWAnySingerStellar, Sign_Payment) { auto key = parse_hex("59a313f46ef1c23a9e4f71cea10fc0c56a2a6bb8a4b9ea3d5348823e5a478722"); @@ -180,10 +181,12 @@ TEST(TWAnySingerStellar, Sign_Claim_Claimable_Balance_c1fb3c) { // curl -X POST -F "tx=AAAAAMpF..DQ==" "https://horizon.stellar.org/transactions" EXPECT_EQ(output.signature(), "AAAAAMpFJQVVMv16RJUPlzQUTlgZOHVurhw3igGacP1305F1AAAnEAH/8MgAAAAhAAAAAAAAAAAAAAABAAAAAAAAAA8AAAAAnHt5S3sVDz5Mbc+iYGcrvgwkizYBKREukn4PfuL5+vgAAAAAAAAAAXfTkXUAAABAWL7dKkR1JuPZGFbDTRDgGBHW/vLPMWNRkAew+wPfGiCnZhpJJDcyX197EDDZMsJ7ungPUyhczRaeQOwZKx4DDQ=="); - { // negative test: hash wrong size + { // negative test: hash wrong size const Data invalidBalanceIdHash = parse_hex("010203"); input.mutable_op_claim_claimable_balance()->set_balance_id(invalidBalanceIdHash.data(), invalidBalanceIdHash.size()); ANY_SIGN(input, TWCoinTypeStellar); EXPECT_EQ(output.signature(), "AAAAAXfTkXUAAABAFCywEfLs3q5Tv9eZCIcjhkJR0s8J4Us9G5YjVKUSaMoUz/AadC8dM2oQSLhpC5wjrNBi7hevg7jlkPx5/4AJCQ=="); } } + +} // namespace TW::Stellar::tests diff --git a/tests/THORChain/TWSwapTests.cpp b/tests/THORChain/TWSwapTests.cpp index 807a936e95c..d2af7e2a18e 100644 --- a/tests/THORChain/TWSwapTests.cpp +++ b/tests/THORChain/TWSwapTests.cpp @@ -4,15 +4,15 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include -#include "proto/THORChainSwap.pb.h" -#include "proto/Ethereum.pb.h" -#include "proto/Binance.pb.h" -#include "Bitcoin/SegwitAddress.h" #include "Bitcoin/Script.h" -#include -#include +#include "Bitcoin/SegwitAddress.h" #include "PrivateKey.h" +#include "proto/Binance.pb.h" +#include "proto/Ethereum.pb.h" +#include "proto/THORChainSwap.pb.h" +#include +#include +#include #include "HexCoding.h" #include "uint256.h" @@ -20,9 +20,11 @@ #include -using namespace TW::THORChainSwap; using namespace TW; +namespace TW::THORChainSwap::tests { + +// clang-format off const auto Address1Bnb = "bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx"; const auto Address1Btc = "bc1qpjult34k9spjfym8hss2jrwjgf0xjf40ze0pp8"; const auto Address1Eth = "0xb9f5771c27664bf2282d98e09d7f50cec7cb01a7"; @@ -68,7 +70,7 @@ TEST(TWTHORChainSwap, SwapBtcToEth) { EXPECT_EQ(outputProto.error().message(), ""); EXPECT_TRUE(outputProto.has_bitcoin()); Bitcoin::Proto::SigningInput txInput = outputProto.bitcoin(); - + // tx input: check some fields EXPECT_EQ(txInput.amount(), 1000000); EXPECT_EQ(txInput.to_address(), "bc1q6m9u2qsu8mh8y7v8rr2ywavtj8g5arzlyhcej7"); @@ -148,7 +150,7 @@ TEST(TWTHORChainSwap, SwapEthBnb) { EXPECT_EQ(outputProto.error().message(), ""); EXPECT_TRUE(outputProto.has_ethereum()); Ethereum::Proto::SigningInput txInput = outputProto.ethereum(); - + // sign tx input for signed full tx // set few fields before signing auto chainId = store(uint256_t(1)); @@ -202,7 +204,7 @@ TEST(TWTHORChainSwap, SwapBnbBtc) { EXPECT_EQ(outputProto.error().message(), ""); EXPECT_TRUE(outputProto.has_binance()); Binance::Proto::SigningInput txInput = outputProto.binance(); - + // set few fields before signing txInput.set_chain_id("Binance-Chain-Tigris"); txInput.set_private_key(TestKey1Bnb.data(), TestKey1Bnb.size()); @@ -223,3 +225,6 @@ TEST(TWTHORChainSwap, NegativeInvalidInput) { EXPECT_EQ(hex(outputData), "1a2508021221436f756c64206e6f7420646573657269616c697a6520696e7075742070726f746f"); EXPECT_EQ(hex(data(std::string("Could not deserialize input proto"))), "436f756c64206e6f7420646573657269616c697a6520696e7075742070726f746f"); } +// clang-format on + +} // namespace TW::ThorChainSwap::tests diff --git a/tests/Terra/SignerTests.cpp b/tests/Terra/SignerTests.cpp index eed38ba3adf..1196d7af458 100644 --- a/tests/Terra/SignerTests.cpp +++ b/tests/Terra/SignerTests.cpp @@ -348,7 +348,7 @@ TEST(TerraSigner, SignWasmTransferPayload) { const auto amount = store(uint256_t(250000), 0); proto.set_amount(amount.data(), amount.size()); - const auto payload = wasmExecuteTransferPayload(proto); + const auto payload = Protobuf::wasmExecuteTransferPayload(proto); assertJSONEqual(payload.dump(), R"( { diff --git a/tests/Terra/SignerTestsClassic.cpp b/tests/Terra/SignerTestsClassic.cpp index f77f59da050..a334919529d 100644 --- a/tests/Terra/SignerTestsClassic.cpp +++ b/tests/Terra/SignerTestsClassic.cpp @@ -442,7 +442,7 @@ TEST(TerraClassicSigner, SignWasmTerraTransferPayload) { const auto amount = store(uint256_t(250000), 0); proto.set_amount(amount.data(), amount.size()); - const auto payload = wasmTerraExecuteTransferPayload(proto); + const auto payload = Protobuf::wasmTerraExecuteTransferPayload(proto); assertJSONEqual(payload.dump(), R"( { diff --git a/tests/Tezos/AddressTests.cpp b/tests/Tezos/AddressTests.cpp index 9a9e5c090cf..38e121ce7df 100644 --- a/tests/Tezos/AddressTests.cpp +++ b/tests/Tezos/AddressTests.cpp @@ -4,20 +4,21 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Tezos/Address.h" #include "HDWallet.h" #include "HexCoding.h" #include "PrivateKey.h" +#include "Tezos/Address.h" #include "Tezos/Forging.h" #include +#include #include #include -#include using namespace TW; -using namespace TW::Tezos; + +namespace TW::Tezos::tests { TEST(TezosAddress, forge_tz1) { auto input = Address("tz1eZwq8b5cvE2bPKokatLkVMzkxz24z3Don"); @@ -41,10 +42,10 @@ TEST(TezosAddress, forge_tz3) { } TEST(TezosAddress, isInvalid) { - std::array invalidAddresses { - "NmH7tmeJUmHcncBDvpr7aJNEBk7rp5zYsB1qt", // Invalid prefix, valid checksum - "tz1eZwq8b5cvE2bPKokatLkVMzkxz24z3AAAA", // Valid prefix, invalid checksum - "1tzeZwq8b5cvE2bPKokatLkVMzkxz24zAAAAA" // Invalid prefix, invalid checksum + std::array invalidAddresses{ + "NmH7tmeJUmHcncBDvpr7aJNEBk7rp5zYsB1qt", // Invalid prefix, valid checksum + "tz1eZwq8b5cvE2bPKokatLkVMzkxz24z3AAAA", // Valid prefix, invalid checksum + "1tzeZwq8b5cvE2bPKokatLkVMzkxz24zAAAAA" // Invalid prefix, invalid checksum }; for (auto& address : invalidAddresses) { @@ -53,14 +54,13 @@ TEST(TezosAddress, isInvalid) { } TEST(TezosAddress, isValid) { - std::array validAddresses { + std::array validAddresses{ "tz1Yju7jmmsaUiG9qQLoYv35v5pHgnWoLWbt", "tz2PdGc7U5tiyqPgTSgqCDct94qd6ovQwP6u", - "tz3VEZ4k6a4Wx42iyev6i2aVAptTRLEAivNN" - }; + "tz3VEZ4k6a4Wx42iyev6i2aVAptTRLEAivNN"}; for (auto& address : validAddresses) { - ASSERT_TRUE(Address::isValid(address)); + ASSERT_TRUE(Address::isValid(address)); } } @@ -74,15 +74,17 @@ TEST(TezosAddress, deriveOriginatedAddress) { auto operationHash = "oo7VeTEPjEusPKnsHtKcGYbYa7i4RWpcEhUVo3Suugbbs6K62Ro"; auto operationIndex = 0; auto expected = "KT1WrtjtAYQSrUVvSNJPTZTebiUWoopQL5hw"; - + ASSERT_EQ(Address::deriveOriginatedAddress(operationHash, operationIndex), expected); } TEST(TezosAddress, PublicKeyInit) { - Data bytes {1, 254, 21, 124, 200, 1, 23, 39, 147, 108, 89, 47, 133, 108, 144, 113, 211, 156, 244, 172, 218, 223, 166, 215, 100, 53, 228, 97, 156, 157, 197, 111, 99,}; + Data bytes = parse_hex("01fe157cc8011727936c592f856c9071d39cf4acdadfa6d76435e4619c9dc56f63"); const auto publicKey = PublicKey(bytes, TWPublicKeyTypeED25519); auto address = Address(publicKey); auto expected = "tz1cG2jx3W4bZFeVGBjsTxUAG8tdpTXtE8PT"; ASSERT_EQ(address.string(), expected); } + +} // namespace TW::Tezos::tests diff --git a/tests/Tezos/SignerTests.cpp b/tests/Tezos/SignerTests.cpp index 987d3a573c8..92681344646 100644 --- a/tests/Tezos/SignerTests.cpp +++ b/tests/Tezos/SignerTests.cpp @@ -4,17 +4,18 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include "Base58.h" +#include "HexCoding.h" +#include "PrivateKey.h" #include "Tezos/BinaryCoding.h" #include "Tezos/OperationList.h" #include "Tezos/Signer.h" -#include "PrivateKey.h" -#include "Base58.h" -#include "HexCoding.h" #include using namespace TW; -using namespace TW::Tezos; + +namespace TW::Tezos::tests { TEST(TezosSigner, SignString) { Data bytesToSign = parse_hex("ffaa"); @@ -23,7 +24,7 @@ TEST(TezosSigner, SignString) { append(expected, bytesToSign); append(expected, expectedSignature); - auto key = PrivateKey(parse_hex("0x2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6f")); + auto key = PrivateKey(parse_hex("0x2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6f")); auto signedBytes = Signer().signData(key, bytesToSign); ASSERT_EQ(signedBytes, expected); @@ -89,3 +90,5 @@ TEST(TezosSigner, SignOperationList) { ASSERT_EQ(hex(signedBytes.begin(), signedBytes.end()), expectedSignedBytes); } + +} // namespace TW::Tezos::tests diff --git a/tests/Theta/TWAnySignerTests.cpp b/tests/Theta/TWAnySignerTests.cpp index 92d748c6ebc..6b9fbe87e6d 100644 --- a/tests/Theta/TWAnySignerTests.cpp +++ b/tests/Theta/TWAnySignerTests.cpp @@ -5,19 +5,20 @@ // file LICENSE at the root of the source code distribution tree. #include "HexCoding.h" -#include "uint256.h" #include "proto/Theta.pb.h" +#include "uint256.h" #include #include "../interface/TWTestUtilities.h" #include using namespace TW; -using namespace TW::Theta; + +namespace TW::Theta::tests { TEST(TWAnySignerTheta, Sign) { auto privateKey = parse_hex("93a90ea508331dfdf27fb79757d4250b4e84954927ba0073cd67454ac432c737"); - + Proto::SigningInput input; input.set_chain_id("privatenet"); input.set_to_address("0x9F1233798E905E173560071255140b4A8aBd3Ec6"); @@ -35,3 +36,5 @@ TEST(TWAnySignerTheta, Sign) { ASSERT_EQ(hex(output.encoded()), "02f887c78085e8d4a51000f863f861942e833968e5bb786ae419c4d13189fb081cc43babc70a85e8d4a5101401b8415190868498d587d074d57298f41853d0109d997f15ddf617f471eb8cbb7fff267cb8fe9134ccdef053ec7cabd18070325c9c436efe1abbacd14eb7561d3fc10501d9d8949f1233798e905e173560071255140b4a8abd3ec6c20a14"); } + +} // namespace TW::Thetha::tests diff --git a/tests/Waves/AddressTests.cpp b/tests/Waves/AddressTests.cpp index b5a8afe9232..1e99f576d1e 100644 --- a/tests/Waves/AddressTests.cpp +++ b/tests/Waves/AddressTests.cpp @@ -14,7 +14,8 @@ using namespace std; using namespace TW; -using namespace TW::Waves; + +namespace TW::Waves::tests { TEST(WavesAddress, SecureHash) { const auto secureHash = @@ -81,4 +82,6 @@ TEST(WavesAddress, Derive) { ASSERT_EQ(address1, "3PQupTC1yRiHneotFt79LF2pkN6GrGMwEy3"); ASSERT_EQ(address2, "3PEXw52bkS9XuLhttWoKyykZjXqEY8zeLxf"); -} \ No newline at end of file +} + +} // namespace TW::Waves::tests diff --git a/tests/Waves/LeaseTests.cpp b/tests/Waves/LeaseTests.cpp index 41de50d1980..53f6e192cbd 100644 --- a/tests/Waves/LeaseTests.cpp +++ b/tests/Waves/LeaseTests.cpp @@ -8,8 +8,8 @@ #include "PrivateKey.h" #include "PublicKey.h" #include "Waves/Address.h" -#include "proto/Waves.pb.h" #include "Waves/Transaction.h" +#include "proto/Waves.pb.h" #include #include @@ -18,23 +18,24 @@ using json = nlohmann::json; using namespace std; using namespace TW; -using namespace TW::Waves; + +namespace TW::Waves::tests { TEST(WavesLease, serialize) { const auto privateKey = - PrivateKey(parse_hex("9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); + PrivateKey(parse_hex("9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); auto input = Proto::SigningInput(); input.set_timestamp(int64_t(1526646497465)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - + auto& message = *input.mutable_lease_message(); message.set_amount(int64_t(100000000)); message.set_fee(int64_t(100000)); message.set_to("3P9DEDP5VbyXQyKtXDUt2crRPn5B7gs6ujc"); auto tx1 = Transaction( - input, - /* pub_key */ - parse_hex("425f57a8cb5439e4e912e66376f7041565d029ae4437dae1a3ebe15649d43461")); + input, + /* pub_key */ + parse_hex("425f57a8cb5439e4e912e66376f7041565d029ae4437dae1a3ebe15649d43461")); auto serialized1 = tx1.serializeToSign(); ASSERT_EQ(hex(serialized1), "080200425f57a8cb5439e4e912e66376f7041565d029ae4437dae1a3ebe15649d4346101574" "fdfcd1bfb19114bd2ac369e32013c70c6d03a4627879cbf0000000005f5e100000000000001" @@ -43,18 +44,18 @@ TEST(WavesLease, serialize) { TEST(WavesLease, CancelSerialize) { const auto privateKey = - PrivateKey(parse_hex("9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); + PrivateKey(parse_hex("9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); auto input = Proto::SigningInput(); input.set_timestamp(int64_t(1568831000826)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - + auto& message = *input.mutable_cancel_lease_message(); message.set_fee(int64_t(100000)); message.set_lease_id("44re3UEDw1QwPFP8dKzfuGHVMNBejUW9NbhxG6b4KJ1T"); auto tx1 = Transaction( - input, - /* pub_key */ - parse_hex("425f57a8cb5439e4e912e66376f7041565d029ae4437dae1a3ebe15649d43461")); + input, + /* pub_key */ + parse_hex("425f57a8cb5439e4e912e66376f7041565d029ae4437dae1a3ebe15649d43461")); auto serialized1 = tx1.serializeToSign(); ASSERT_EQ(hex(serialized1), "090257425f57a8cb5439e4e912e66376f7041565d029ae4437dae1a3ebe15649d" "4346100000000000186a00000016d459d50fa2d8fee08efc97f79bcd97a4d977c" @@ -62,54 +63,54 @@ TEST(WavesLease, CancelSerialize) { } TEST(WavesLease, jsonSerialize) { - const auto privateKey = PrivateKey(parse_hex( - "9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); - const auto publicKeyCurve25519 = - privateKey.getPublicKey(TWPublicKeyTypeCURVE25519); - auto input = Proto::SigningInput(); - input.set_timestamp(int64_t(1568973547102)); - input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - - auto& message = *input.mutable_lease_message(); - message.set_amount(int64_t(100000)); - message.set_fee(int64_t(100000)); - message.set_to("3P9DEDP5VbyXQyKtXDUt2crRPn5B7gs6ujc"); - auto tx1 = Transaction(input, - /* pub_key */ - parse_hex("559a50cb45a9a8e8d4f83295c354725990164d10bb505275d1a3086c08fb935d")); - - auto signature = Signer::sign(privateKey, tx1); - auto json = tx1.buildJson(signature); - - ASSERT_EQ(json["type"], TransactionType::lease); - ASSERT_EQ(json["version"], TransactionVersion::V2); - ASSERT_EQ(json["fee"], int64_t(100000)); - ASSERT_EQ(json["senderPublicKey"], - "6mA8eQjie53kd4jbZrwL3ZhMBqCX6nzit1k55tR2X7zU"); - ASSERT_EQ(json["timestamp"], int64_t(1568973547102)); - ASSERT_EQ(json["proofs"].dump(), - "[\"4opce9e99827upK3m3D3NicnvBqbMLtAJ4Jc8ksTLiScqBgjdqzr9JyXG" - "C1NAGZUbkqJvix9bNrBokrxtGruwmu3\"]"); - ASSERT_EQ(json["recipient"], "3P9DEDP5VbyXQyKtXDUt2crRPn5B7gs6ujc"); - ASSERT_EQ(json["amount"], int64_t(100000)); - ASSERT_EQ(json.dump(), - "{\"amount\":100000,\"fee\":100000,\"proofs\":[" - "\"4opce9e99827upK3m3D3NicnvBqbMLtAJ4Jc8ksTLiScqBgjdqzr9JyXGC1NAGZUbkqJ" - "vix9bNrBokrxtGruwmu3\"],\"recipient\":" - "\"3P9DEDP5VbyXQyKtXDUt2crRPn5B7gs6ujc\",\"senderPublicKey\":" - "\"6mA8eQjie53kd4jbZrwL3ZhMBqCX6nzit1k55tR2X7zU\",\"timestamp\":" - "1568973547102,\"type\":8,\"version\":2}"); + const auto privateKey = PrivateKey(parse_hex( + "9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); + const auto publicKeyCurve25519 = + privateKey.getPublicKey(TWPublicKeyTypeCURVE25519); + auto input = Proto::SigningInput(); + input.set_timestamp(int64_t(1568973547102)); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + + auto& message = *input.mutable_lease_message(); + message.set_amount(int64_t(100000)); + message.set_fee(int64_t(100000)); + message.set_to("3P9DEDP5VbyXQyKtXDUt2crRPn5B7gs6ujc"); + auto tx1 = Transaction(input, + /* pub_key */ + parse_hex("559a50cb45a9a8e8d4f83295c354725990164d10bb505275d1a3086c08fb935d")); + + auto signature = Signer::sign(privateKey, tx1); + auto json = tx1.buildJson(signature); + + ASSERT_EQ(json["type"], TransactionType::lease); + ASSERT_EQ(json["version"], TransactionVersion::V2); + ASSERT_EQ(json["fee"], int64_t(100000)); + ASSERT_EQ(json["senderPublicKey"], + "6mA8eQjie53kd4jbZrwL3ZhMBqCX6nzit1k55tR2X7zU"); + ASSERT_EQ(json["timestamp"], int64_t(1568973547102)); + ASSERT_EQ(json["proofs"].dump(), + "[\"4opce9e99827upK3m3D3NicnvBqbMLtAJ4Jc8ksTLiScqBgjdqzr9JyXG" + "C1NAGZUbkqJvix9bNrBokrxtGruwmu3\"]"); + ASSERT_EQ(json["recipient"], "3P9DEDP5VbyXQyKtXDUt2crRPn5B7gs6ujc"); + ASSERT_EQ(json["amount"], int64_t(100000)); + ASSERT_EQ(json.dump(), + "{\"amount\":100000,\"fee\":100000,\"proofs\":[" + "\"4opce9e99827upK3m3D3NicnvBqbMLtAJ4Jc8ksTLiScqBgjdqzr9JyXGC1NAGZUbkqJ" + "vix9bNrBokrxtGruwmu3\"],\"recipient\":" + "\"3P9DEDP5VbyXQyKtXDUt2crRPn5B7gs6ujc\",\"senderPublicKey\":" + "\"6mA8eQjie53kd4jbZrwL3ZhMBqCX6nzit1k55tR2X7zU\",\"timestamp\":" + "1568973547102,\"type\":8,\"version\":2}"); } TEST(WavesLease, jsonCancelSerialize) { const auto privateKey = PrivateKey(parse_hex( - "9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); + "9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); const auto publicKeyCurve25519 = - privateKey.getPublicKey(TWPublicKeyTypeCURVE25519); + privateKey.getPublicKey(TWPublicKeyTypeCURVE25519); auto input = Proto::SigningInput(); input.set_timestamp(int64_t(1568973547102)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - + auto& message = *input.mutable_cancel_lease_message(); message.set_lease_id("DKhmXrCsBwf6WVhGh8bYVBnjtAXGpk2K4Yd3CW4u1huG"); message.set_fee(int64_t(100000)); @@ -118,7 +119,7 @@ TEST(WavesLease, jsonCancelSerialize) { parse_hex("559a50cb45a9a8e8d4f83295c354725990164d10bb505275d1a3086c08fb935d")); auto signature = Signer::sign(privateKey, tx1); auto json = tx1.buildJson(signature); - + ASSERT_EQ(json["type"], TransactionType::cancelLease); ASSERT_EQ(json["version"], TransactionVersion::V2); ASSERT_EQ(json["fee"], int64_t(100000)); @@ -138,4 +139,4 @@ TEST(WavesLease, jsonCancelSerialize) { "1568973547102,\"type\":9,\"version\":2}"); } - +} // namespace TW::Waves::tests From c8fe172094dd49a8bf5dba3b67055fd3240e9e9c Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Thu, 4 Aug 2022 08:56:30 +0200 Subject: [PATCH 049/497] [Test] CoinAddressDerivationTests misses many coins (#2479) * Change CoinAddressDerivationTests to use switch * Sort by coin * Add missing 30 coins, join duplicates cases * apply clang-format Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- tests/CoinAddressDerivationTests.cpp | 293 +++++++++++++++++++++------ 1 file changed, 229 insertions(+), 64 deletions(-) diff --git a/tests/CoinAddressDerivationTests.cpp b/tests/CoinAddressDerivationTests.cpp index 319f0926431..270f29087a5 100644 --- a/tests/CoinAddressDerivationTests.cpp +++ b/tests/CoinAddressDerivationTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -18,69 +18,234 @@ TEST(Coin, DeriveAddress) { auto dummyKeyData = parse_hex("0x4646464646464646464646464646464646464646464646464646464646464646"); const auto privateKey = PrivateKey(dummyKeyData); const auto privateKeyExt = PrivateKey(dummyKeyData, dummyKeyData, dummyKeyData, dummyKeyData, dummyKeyData, dummyKeyData); - - EXPECT_EQ(TW::deriveAddress(TWCoinTypeAion, privateKey), "0xa0010b0ea04ba4d76ca6e5e9900bacf19bc4402eaec7e36ea7ddd8eed48f60f3"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeBinance, privateKey), "bnb1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0mlq0d0"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeBitcoin, privateKey), "bc1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z00ppggv"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeBitcoinCash, privateKey), "bitcoincash:qz7eyzytkl5z6cg6nw20hd62pyyp22mcfuardfd2vn"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeCallisto, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeCosmos, privateKey), "cosmos1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0emlrvp"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeDash, privateKey), "XsyCV5yojxF4y3bYeEiVYqarvRgsWFELZL"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeDecred, privateKey), "Dsp4u8xxTHSZU2ELWTQLQP77xJhgeWrTsGK"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeDigiByte, privateKey), "dgb1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z0c69ssz"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeECash, privateKey), "ecash:qz7eyzytkl5z6cg6nw20hd62pyyp22mcfuywezks2y"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeEthereum, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeEthereumClassic, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeGoChain, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeGroestlcoin, privateKey), "grs1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z0jsaf3d"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeICON, privateKey), "hx4728fc65c31728f0d3538b8783b5394b31a136b9"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeIoTeX, privateKey), "io1nk9x9ajk4rgkzhqjjn7hr6w0k0jg2kj0zgdt6h"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeLitecoin, privateKey), "ltc1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z0tamvsu"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeViacoin, privateKey), "via1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z09y9mn2"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeNimiq, privateKey), "NQ74 D40G N3M0 9EJD ET56 UPLR 02VC X6DU 8G1E"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeOntology, privateKey), "AeicEjZyiXKgUeSBbYQHxsU1X3V5Buori5"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypePOANetwork, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeXRP, privateKey), "rJHMeqKu8Ep7Fazx8MQG6JunaafBXz93YQ"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeStellar, privateKey), "GDXJHJHWN6GRNOAZXON6XH74ZX6NYFAS5B7642RSJQVJTIPA4ZYUQLEB"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeTezos, privateKey), "tz1gcEWswVU6dxfNQWbhTgaZrUrNUFwrsT4z"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeThunderToken, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeTomoChain, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeTron, privateKey), "TQLCsShbQNXMTVCjprY64qZmEA4rBarpQp"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeVeChain, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeWanchain, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeZcash, privateKey), "t1b9xfAk3kZp5Qk3rinDPq7zzLkJGHTChDS"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeFiro, privateKey), "aHzpPjmY132KseS4nkiQTbDahTEXqesY89"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeNano, privateKey), "nano_1qepdf4k95dhb5gsmhmq3iddqsxiafwkihunm7irn48jdiwdtnn6pe93k3f6"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeKin, privateKey), "GDXJHJHWN6GRNOAZXON6XH74ZX6NYFAS5B7642RSJQVJTIPA4ZYUQLEB"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeTheta, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeQtum, privateKey), "QdtLm8ccxhuJFF5zCgikpaghbM3thdaGsW"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeNULS, privateKey), "NULSd6HgfXT3m5JBGxeCZXHRQbb82FKgZGT8o"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeEOS, privateKey), "EOS5TrYnZP1RkDSUMzBY4GanCy6AP68kCMdkAb5EACkAwkdgRLShz"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeIoTeX, privateKey), "io1nk9x9ajk4rgkzhqjjn7hr6w0k0jg2kj0zgdt6h"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeDogecoin, privateKey), "DNRTC6GZ5evmM7BZWwPqF54fyDqUqULMyu"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeZilliqa, privateKey), "zil1j2cvtd7j9n7fnxfv2r3neucjw8tp4xz9sp07v4"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeRavencoin, privateKey), "RSZYjMDCP4q3t7NAFXPPnqEGrMZn971pdB"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeAeternity, privateKey), "ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeTerra, privateKey), "terra1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0ll9rwp"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeNebulas, privateKey), "n1XTciu9ZRYt3ni7SxNBmivk9Y6XpP6VrhT"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeMonacoin, privateKey), "MRBWtGEKHGCHhmyJ1L4CwaWQZJzM5DnVcs"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeFIO, privateKey), "FIO5TrYnZP1RkDSUMzBY4GanCy6AP68kCMdkAb5EACkAwkdgRLShz"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeAlgorand, privateKey), "52J2J5TPRULLQGN3TPVZ77GN7TOBIEXIP7XGUMSMFKM2DYHGOFEOGBP2T4"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeKusama, privateKey), "Hy8mqcexg5FMwMYnQvzrUvD723qMxDjMRU9HdNCnTsMAypY"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypePolkadot, privateKey), "16PpFrXrC6Ko3pYcyMAx6gPMp3mFFaxgyYMt4G5brkgNcSz8"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeKava, privateKey), "kava1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z09wt76x"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeCardano, privateKeyExt), "addr1qxzk4wqhh5qmzas4e26aghcvkz8feju6sa43nghfj5xxsly9d2up00gpk9mptj44630sevywnn9e4pmtrx3wn9gvdp7qjhvjl4"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeNEO, privateKeyExt), "AeicEjZyiXKgUeSBbYQHxsU1X3V5Buori5"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeFilecoin, privateKey), "f1qsx7qwiojh5duxbxhbqgnlyx5hmpcf7mcz5oxsy"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeNEAR, privateKey), "ee93a4f66f8d16b819bb9beb9ffccdfcdc1412e87fee6a324c2a99a1e0e67148"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeSolana, privateKey), "H4JcMPicKkHcxxDjkyyrLoQj7Kcibd9t815ak4UvTr9M"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeElrond, privateKey), "erd1a6f6fan035ttsxdmn04ellxdlnwpgyhg0lhx5vjv92v6rc8xw9yq83344f"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeOasis, privateKey), "oasis1qzw4h3wmyjtrttduqqrs8udggyy2emwdzqmuzwg4"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeTHORChain, privateKey), "thor1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0luxce7"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeAvalancheCChain, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeXDai, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeCelo, privateKey), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); - EXPECT_EQ(TW::deriveAddress(TWCoinTypeRonin, privateKey), "ronin:9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); + + const auto coins = TW::getCoinTypes(); + for (auto& c : coins) { + std::string address; + switch (c) { + default: + address = TW::deriveAddress(c, privateKey); + break; + + case TWCoinTypeCardano: + case TWCoinTypeNEO: + address = TW::deriveAddress(c, privateKeyExt); + break; + } + + switch (c) { + // Ethereum and ... + case TWCoinTypeEthereum: + // ... clones: + case TWCoinTypeArbitrum: + case TWCoinTypeAurora: + case TWCoinTypeAvalancheCChain: + case TWCoinTypeBoba: + case TWCoinTypeCallisto: + case TWCoinTypeCelo: + case TWCoinTypeCronosChain: + case TWCoinTypeECOChain: + case TWCoinTypeEthereumClassic: + case TWCoinTypeEvmos: + case TWCoinTypeFantom: + case TWCoinTypeGoChain: + case TWCoinTypeKavaEvm: + case TWCoinTypeKlaytn: + case TWCoinTypeKuCoinCommunityChain: + case TWCoinTypeMeter: + case TWCoinTypeMetis: + case TWCoinTypeMoonbeam: + case TWCoinTypeMoonriver: + case TWCoinTypeOptimism: + case TWCoinTypeOKXChain: + case TWCoinTypePOANetwork: + case TWCoinTypePolygon: + case TWCoinTypeSmartBitcoinCash: + case TWCoinTypeSmartChain: + case TWCoinTypeSmartChainLegacy: + case TWCoinTypeTheta: + case TWCoinTypeThunderToken: + case TWCoinTypeTomoChain: + case TWCoinTypeVeChain: + case TWCoinTypeWanchain: + case TWCoinTypeXDai: + EXPECT_EQ(address, "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); + break; + + case TWCoinTypeKin: + case TWCoinTypeStellar: + EXPECT_EQ(address, "GDXJHJHWN6GRNOAZXON6XH74ZX6NYFAS5B7642RSJQVJTIPA4ZYUQLEB"); + break; + + case TWCoinTypeNEO: + case TWCoinTypeOntology: + EXPECT_EQ(address, "AeicEjZyiXKgUeSBbYQHxsU1X3V5Buori5"); + break; + + case TWCoinTypeTerra: + case TWCoinTypeTerraV2: + EXPECT_EQ(address, "terra1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0ll9rwp"); + break; + + case TWCoinTypeZcash: + case TWCoinTypeZelcash: + EXPECT_EQ(address, "t1b9xfAk3kZp5Qk3rinDPq7zzLkJGHTChDS"); + break; + + case TWCoinTypeAeternity: + EXPECT_EQ(address, "ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw"); + break; + case TWCoinTypeAion: + EXPECT_EQ(address, "0xa0010b0ea04ba4d76ca6e5e9900bacf19bc4402eaec7e36ea7ddd8eed48f60f3"); + break; + case TWCoinTypeAlgorand: + EXPECT_EQ(address, "52J2J5TPRULLQGN3TPVZ77GN7TOBIEXIP7XGUMSMFKM2DYHGOFEOGBP2T4"); + break; + case TWCoinTypeBandChain: + EXPECT_EQ(address, "band1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0q5lp5f"); + break; + case TWCoinTypeBinance: + EXPECT_EQ(address, "bnb1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0mlq0d0"); + break; + case TWCoinTypeBitcoin: + EXPECT_EQ(address, "bc1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z00ppggv"); + break; + case TWCoinTypeBitcoinCash: + EXPECT_EQ(address, "bitcoincash:qz7eyzytkl5z6cg6nw20hd62pyyp22mcfuardfd2vn"); + break; + case TWCoinTypeBitcoinGold: + EXPECT_EQ(address, "btg1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z0eg8day"); + break; + case TWCoinTypeBluzelle: + EXPECT_EQ(address, "bluzelle1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0vrup2s"); + break; + case TWCoinTypeCardano: + EXPECT_EQ(address, "addr1qxzk4wqhh5qmzas4e26aghcvkz8feju6sa43nghfj5xxsly9d2up00gpk9mptj44630sevywnn9e4pmtrx3wn9gvdp7qjhvjl4"); + break; + case TWCoinTypeCosmos: + EXPECT_EQ(address, "cosmos1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0emlrvp"); + break; + case TWCoinTypeCryptoOrg: + EXPECT_EQ(address, "cro1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0pqh6ss"); + break; + case TWCoinTypeDash: + EXPECT_EQ(address, "XsyCV5yojxF4y3bYeEiVYqarvRgsWFELZL"); + break; + case TWCoinTypeDecred: + EXPECT_EQ(address, "Dsp4u8xxTHSZU2ELWTQLQP77xJhgeWrTsGK"); + break; + case TWCoinTypeDigiByte: + EXPECT_EQ(address, "dgb1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z0c69ssz"); + break; + case TWCoinTypeDogecoin: + EXPECT_EQ(address, "DNRTC6GZ5evmM7BZWwPqF54fyDqUqULMyu"); + break; + case TWCoinTypeECash: + EXPECT_EQ(address, "ecash:qz7eyzytkl5z6cg6nw20hd62pyyp22mcfuywezks2y"); + break; + case TWCoinTypeEOS: + EXPECT_EQ(address, "EOS5TrYnZP1RkDSUMzBY4GanCy6AP68kCMdkAb5EACkAwkdgRLShz"); + break; + case TWCoinTypeElrond: + EXPECT_EQ(address, "erd1a6f6fan035ttsxdmn04ellxdlnwpgyhg0lhx5vjv92v6rc8xw9yq83344f"); + break; + case TWCoinTypeFIO: + EXPECT_EQ(address, "FIO5TrYnZP1RkDSUMzBY4GanCy6AP68kCMdkAb5EACkAwkdgRLShz"); + break; + case TWCoinTypeFilecoin: + EXPECT_EQ(address, "f1qsx7qwiojh5duxbxhbqgnlyx5hmpcf7mcz5oxsy"); + break; + case TWCoinTypeFiro: + EXPECT_EQ(address, "aHzpPjmY132KseS4nkiQTbDahTEXqesY89"); + break; + case TWCoinTypeGroestlcoin: + EXPECT_EQ(address, "grs1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z0jsaf3d"); + break; + case TWCoinTypeHarmony: + EXPECT_EQ(address, "one1nk9x9ajk4rgkzhqjjn7hr6w0k0jg2kj0nmx3dt"); + break; + case TWCoinTypeICON: + EXPECT_EQ(address, "hx4728fc65c31728f0d3538b8783b5394b31a136b9"); + break; + case TWCoinTypeIoTeX: + EXPECT_EQ(address, "io1nk9x9ajk4rgkzhqjjn7hr6w0k0jg2kj0zgdt6h"); + break; + case TWCoinTypeKava: + EXPECT_EQ(address, "kava1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z09wt76x"); + break; + case TWCoinTypeKusama: + EXPECT_EQ(address, "Hy8mqcexg5FMwMYnQvzrUvD723qMxDjMRU9HdNCnTsMAypY"); + break; + case TWCoinTypeLitecoin: + EXPECT_EQ(address, "ltc1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z0tamvsu"); + break; + case TWCoinTypeMonacoin: + EXPECT_EQ(address, "MRBWtGEKHGCHhmyJ1L4CwaWQZJzM5DnVcs"); + break; + case TWCoinTypeNEAR: + EXPECT_EQ(address, "ee93a4f66f8d16b819bb9beb9ffccdfcdc1412e87fee6a324c2a99a1e0e67148"); + break; + case TWCoinTypeNULS: + EXPECT_EQ(address, "NULSd6HgfXT3m5JBGxeCZXHRQbb82FKgZGT8o"); + break; + case TWCoinTypeNano: + EXPECT_EQ(address, "nano_1qepdf4k95dhb5gsmhmq3iddqsxiafwkihunm7irn48jdiwdtnn6pe93k3f6"); + break; + case TWCoinTypeNativeEvmos: + EXPECT_EQ(address, "evmos1nk9x9ajk4rgkzhqjjn7hr6w0k0jg2kj07me7uu"); + break; + case TWCoinTypeNebulas: + EXPECT_EQ(address, "n1XTciu9ZRYt3ni7SxNBmivk9Y6XpP6VrhT"); + break; + case TWCoinTypeNimiq: + EXPECT_EQ(address, "NQ74 D40G N3M0 9EJD ET56 UPLR 02VC X6DU 8G1E"); + break; + case TWCoinTypeOasis: + EXPECT_EQ(address, "oasis1qzw4h3wmyjtrttduqqrs8udggyy2emwdzqmuzwg4"); + break; + case TWCoinTypeOsmosis: + EXPECT_EQ(address, "osmo1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z03qvn6n"); + break; + case TWCoinTypePolkadot: + EXPECT_EQ(address, "16PpFrXrC6Ko3pYcyMAx6gPMp3mFFaxgyYMt4G5brkgNcSz8"); + break; + case TWCoinTypeQtum: + EXPECT_EQ(address, "QdtLm8ccxhuJFF5zCgikpaghbM3thdaGsW"); + break; + case TWCoinTypeRavencoin: + EXPECT_EQ(address, "RSZYjMDCP4q3t7NAFXPPnqEGrMZn971pdB"); + break; + case TWCoinTypeRonin: + EXPECT_EQ(address, "ronin:9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); + break; + case TWCoinTypeSolana: + EXPECT_EQ(address, "H4JcMPicKkHcxxDjkyyrLoQj7Kcibd9t815ak4UvTr9M"); + break; + case TWCoinTypeTHORChain: + EXPECT_EQ(address, "thor1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0luxce7"); + break; + case TWCoinTypeTezos: + EXPECT_EQ(address, "tz1gcEWswVU6dxfNQWbhTgaZrUrNUFwrsT4z"); + break; + case TWCoinTypeTron: + EXPECT_EQ(address, "TQLCsShbQNXMTVCjprY64qZmEA4rBarpQp"); + break; + case TWCoinTypeViacoin: + EXPECT_EQ(address, "via1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z09y9mn2"); + break; + case TWCoinTypeWaves: + EXPECT_EQ(address, "3P2C786D6mBuvyf4WYr6K6Vch5uhi97nBHG"); + break; + case TWCoinTypeXRP: + EXPECT_EQ(address, "rJHMeqKu8Ep7Fazx8MQG6JunaafBXz93YQ"); + break; + case TWCoinTypeZilliqa: + EXPECT_EQ(address, "zil1j2cvtd7j9n7fnxfv2r3neucjw8tp4xz9sp07v4"); + break; + + // no default branch here, intentionally, to better notice any missing coins + } + } } int countThreadReady = 0; From e6435a99f8886e39500672e221047ff5169169fa Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Mon, 8 Aug 2022 22:15:17 +0900 Subject: [PATCH 050/497] [Test] Reuse global instance to remove max listener warning (#2482) --- samples/node/index.js | 31 ++++++++++++++++++-------- samples/node/package-lock.json | 14 ++++++------ samples/node/package.json | 3 ++- wasm/package.json | 2 +- wasm/tests/AES.test.ts | 11 ++------- wasm/tests/AnyAddress.test.ts | 5 ++--- wasm/tests/Base32.test.ts | 15 ++++--------- wasm/tests/Base64.test.ts | 14 ++++-------- wasm/tests/Blockchain/Ethereum.test.ts | 18 +++++---------- wasm/tests/CoinType.test.ts | 7 ++---- wasm/tests/HDWallet.test.ts | 12 ++-------- wasm/tests/HRP.test.ts | 5 ++--- wasm/tests/Hash.test.ts | 14 +++--------- wasm/tests/HexCoding.test.ts | 5 ++--- wasm/tests/Mnemonic.test.ts | 13 +++-------- wasm/tests/PBKDF2.test.ts | 5 ++--- wasm/tests/StoredKey.test.ts | 5 ++--- wasm/tests/setup.test.ts | 6 +++++ 18 files changed, 74 insertions(+), 111 deletions(-) create mode 100644 wasm/tests/setup.test.ts diff --git a/samples/node/index.js b/samples/node/index.js index 1c666a4687d..dde4541ff59 100755 --- a/samples/node/index.js +++ b/samples/node/index.js @@ -1,13 +1,26 @@ #!/usr/bin/env node -const { initWasm, TW } = require('@trustwallet/wallet-core'); +const { initWasm, TW } = require("@trustwallet/wallet-core"); -(async function() { - const start = new Date().getTime(); - console.log(`Initializing...`); - const { CoinType, HexCoding } = await initWasm(); - console.log(`Done in ${new Date().getTime() - start} ms`); - console.log(HexCoding.decode("0xce2fd7544e0b2cc94692d4a704debef7bcb61328")); - console.log(CoinType.ethereum.value); - console.log(TW.Ethereum); +(async function () { + const start = new Date().getTime(); + console.log(`Initializing Wasm...`); + const { CoinType, HexCoding, HDWallet, AnyAddress } = await initWasm(); + console.log(`Done in ${new Date().getTime() - start} ms`); + + const wallet = HDWallet.create(256, ""); + const key = wallet.getKeyForCoin(CoinType.ethereum); + const pubKey = key.getPublicKeySecp256k1(false); + const address = AnyAddress.createWithPublicKey(pubKey, CoinType.ethereum); + + console.log(`Create wallet: ${wallet.mnemonic()}`); + console.log(`Get Ethereum public key: ${HexCoding.encode(pubKey.data())}`); + console.log(`Get Ethereum address: ${address.description()}`); + console.log(`CoinType.ethereum.value = ${CoinType.ethereum.value}`); + console.log("Ethereum protobuf models: \n", TW.Ethereum); + + wallet.delete(); + key.delete(); + pubKey.delete(); + address.delete(); })(); diff --git a/samples/node/package-lock.json b/samples/node/package-lock.json index 319d198c9f5..54e7d733d5e 100644 --- a/samples/node/package-lock.json +++ b/samples/node/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@trustwallet/wallet-core": "^2.9.5" + "@trustwallet/wallet-core": "3.0.1" } }, "node_modules/@protobufjs/aspromise": { @@ -67,9 +67,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@trustwallet/wallet-core": { - "version": "2.9.5", - "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-2.9.5.tgz", - "integrity": "sha512-pb0huJUP34DqyxWslTrTW1SX0CZzpSINVonykwVvCk2Lc1pCJvbUPvrH+tMAkBGb5ytMuceuQ/KcvJ6KzmudBw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.1.tgz", + "integrity": "sha512-WrZwWO85ja4SKyCftJQqj/XWqcLmrP6qJ42YuU9FSzdJp68IdOICckGj5INaW0DE+3O85bPNO+zTmBTBKRZr7g==", "dependencies": { "protobufjs": ">=6.11.3" } @@ -171,9 +171,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "@trustwallet/wallet-core": { - "version": "2.9.5", - "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-2.9.5.tgz", - "integrity": "sha512-pb0huJUP34DqyxWslTrTW1SX0CZzpSINVonykwVvCk2Lc1pCJvbUPvrH+tMAkBGb5ytMuceuQ/KcvJ6KzmudBw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.1.tgz", + "integrity": "sha512-WrZwWO85ja4SKyCftJQqj/XWqcLmrP6qJ42YuU9FSzdJp68IdOICckGj5INaW0DE+3O85bPNO+zTmBTBKRZr7g==", "requires": { "protobufjs": ">=6.11.3" } diff --git a/samples/node/package.json b/samples/node/package.json index 38dbfdc1ca6..f0578390b78 100644 --- a/samples/node/package.json +++ b/samples/node/package.json @@ -4,11 +4,12 @@ "description": "", "main": "index.js", "scripts": { + "start": "node index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { - "@trustwallet/wallet-core": "^2.9.5" + "@trustwallet/wallet-core": "3.0.1" } } diff --git a/wasm/package.json b/wasm/package.json index 5397d3b48dd..2b7fd5c5361 100644 --- a/wasm/package.json +++ b/wasm/package.json @@ -5,7 +5,7 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { - "test": "mocha", + "test": "mocha --trace-warnings", "generate": "npm run codegen:js && npm run codegen:ts", "codegen:js": "pbjs -t static-module '../src/proto/*.proto' --no-delimited --force-long -o generated/core_proto.js", "codegen:js-browser": "pbjs -t static-module '../src/proto/*.proto' -w closure --no-delimited --force-long -o ../samples/wasm/core_proto.js", diff --git a/wasm/tests/AES.test.ts b/wasm/tests/AES.test.ts index 1b176113c3f..9a44fb1b337 100644 --- a/wasm/tests/AES.test.ts +++ b/wasm/tests/AES.test.ts @@ -7,18 +7,11 @@ import "mocha"; import { assert } from "chai"; import { Buffer } from "buffer"; -import { initWasm, WalletCore } from "../dist"; describe("AES", () => { - let core: WalletCore; - - before(async () => { - core = await initWasm(); - }); - it("test decrypting", () => { - const { AES, HexCoding, AESPaddingMode } = core; + const { AES, HexCoding, AESPaddingMode } = globalThis.core; const key = HexCoding.decode( "5caa3a74154cee16bd1b570a1330be46e086474ac2f4720530662ef1a469662c" @@ -36,7 +29,7 @@ describe("AES", () => { }); it("test encrypting", () => { - const { AES, HexCoding, AESPaddingMode } = core; + const { AES, HexCoding, AESPaddingMode } = globalThis.core; const key = HexCoding.decode( "bbc82a01ebdb14698faee4a9e5038de72c995a9f6bcdb21903d62408b0c5ca96" diff --git a/wasm/tests/AnyAddress.test.ts b/wasm/tests/AnyAddress.test.ts index 4429091bf7e..20171c3bd21 100644 --- a/wasm/tests/AnyAddress.test.ts +++ b/wasm/tests/AnyAddress.test.ts @@ -6,11 +6,10 @@ import "mocha"; import { assert } from "chai"; -import { initWasm } from "../dist"; describe("AnyAddress", () => { - it("test validating Solana address", async () => { - const { AnyAddress, HexCoding, CoinType } = await initWasm(); + it("test validating Solana address", () => { + const { AnyAddress, HexCoding, CoinType } = globalThis.core; var address = AnyAddress.createWithString( "7v91N7iZ9mNicL8WfG6cgSCKyRXydQjLh6UYBWwm6y1Q", diff --git a/wasm/tests/Base32.test.ts b/wasm/tests/Base32.test.ts index 8abe7caf6f2..36915d1d41b 100644 --- a/wasm/tests/Base32.test.ts +++ b/wasm/tests/Base32.test.ts @@ -6,18 +6,11 @@ import { assert } from "chai"; import { Buffer } from "buffer"; -import { initWasm, WalletCore } from "../dist"; describe("Base32", () => { - let core: WalletCore; - - before(async () => { - core = await initWasm(); - }); - it("test decrypting", () => { - const { Base32 } = core; + const { Base32 } = globalThis.core; const decoded = Base32.decode("JBSWY3DPK5XXE3DE"); @@ -25,7 +18,7 @@ describe("Base32", () => { }); it("test decrypting with alphabet", () => { - const { Base32 } = core; + const { Base32 } = globalThis.core; const decoded = Base32.decodeWithAlphabet( "g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i", @@ -39,7 +32,7 @@ describe("Base32", () => { }); it("test encrypting", () => { - const { Base32 } = core; + const { Base32 } = globalThis.core; const encoded = Base32.encode(Buffer.from("HelloWorld")); @@ -47,7 +40,7 @@ describe("Base32", () => { }); it("test encrypting with alphabet", () => { - const { Base32 } = core; + const { Base32 } = globalThis.core; const encoded = Base32.encodeWithAlphabet( Buffer.from("7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"), diff --git a/wasm/tests/Base64.test.ts b/wasm/tests/Base64.test.ts index 12d9dc11388..b2f6297627b 100644 --- a/wasm/tests/Base64.test.ts +++ b/wasm/tests/Base64.test.ts @@ -6,17 +6,11 @@ import { assert } from "chai"; import { Buffer } from "buffer"; -import { initWasm, WalletCore } from "../dist"; describe("Base64", () => { - let core: WalletCore; - - before(async () => { - core = await initWasm(); - }); it("test decoding", () => { - const { Base64 } = core; + const { Base64 } = globalThis.core; const decoded = Base64.decode("SGVsbG9Xb3JsZA=="); @@ -24,7 +18,7 @@ describe("Base64", () => { }); it("test encoding", () => { - const { Base64 } = core; + const { Base64 } = globalThis.core; const encoded = Base64.encode(Buffer.from("HelloWorld")); @@ -32,7 +26,7 @@ describe("Base64", () => { }); it("test encoding (URL-safe)", () => { - const { Base64 } = core; + const { Base64 } = globalThis.core; const encoded = Base64.encodeUrl(Buffer.from("==?=")); @@ -40,7 +34,7 @@ describe("Base64", () => { }); it("test decoding (URL-safe)", () => { - const { Base64 } = core; + const { Base64 } = globalThis.core; const decoded = Base64.decodeUrl("PT0_PQ=="); assert.equal(Buffer.from(decoded).toString(), "==?="); diff --git a/wasm/tests/Blockchain/Ethereum.test.ts b/wasm/tests/Blockchain/Ethereum.test.ts index 5b6e17b0005..660b6e43afc 100644 --- a/wasm/tests/Blockchain/Ethereum.test.ts +++ b/wasm/tests/Blockchain/Ethereum.test.ts @@ -7,18 +7,12 @@ import "mocha"; import { assert } from "chai"; import { Buffer } from "buffer"; -import { TW, initWasm, WalletCore } from "../../dist"; +import { TW } from "../../dist"; describe("Ethereum", () => { - let core: WalletCore; - - before(async () => { - core = await initWasm(); - }); - it("test address", () => { - const { PrivateKey, HexCoding, AnyAddress, CoinType, Curve } = core; + const { PrivateKey, HexCoding, AnyAddress, CoinType, Curve } = globalThis.core; const data = HexCoding.decode("727f677b390c151caf9c206fd77f77918f56904b5504243db9b21e51182c4c06"); @@ -42,7 +36,7 @@ describe("Ethereum", () => { }); it("test signing transfer tx", () => { - const { HexCoding, AnySigner, CoinType } = core; + const { HexCoding, AnySigner, CoinType } = globalThis.core;; const input = TW.Ethereum.Proto.SigningInput.create({ toAddress: "0x3535353535353535353535353535353535353535", chainId: Buffer.from("01", "hex"), @@ -74,7 +68,7 @@ describe("Ethereum", () => { }); it("test signing eip1559 erc20 transfer tx", () => { - const { HexCoding, AnySigner, CoinType } = core; + const { HexCoding, AnySigner, CoinType } = globalThis.core;; const input = TW.Ethereum.Proto.SigningInput.create({ toAddress: "0x6b175474e89094c44da98b954eedeac495271d0f", @@ -105,7 +99,7 @@ describe("Ethereum", () => { }); it("test signing personal message", () => { - const { EthereumAbi, HexCoding, Hash, PrivateKey, Curve } = core; + const { HexCoding, Hash, PrivateKey, Curve } = globalThis.core;; const message = Buffer.from("Some data"); const prefix = Buffer.from("\x19Ethereum Signed Message:\n" + message.length); const hash = Hash.keccak256(Buffer.concat([prefix, message])); @@ -122,7 +116,7 @@ describe("Ethereum", () => { }); it("test signing EIP712 message", () => { - const { EthereumAbi, HexCoding, Hash, PrivateKey, Curve } = core; + const { EthereumAbi, HexCoding, Hash, PrivateKey, Curve } = globalThis.core;; const key = PrivateKey.createWithData(Hash.keccak256(Buffer.from("cow"))); const message = { diff --git a/wasm/tests/CoinType.test.ts b/wasm/tests/CoinType.test.ts index 4c98365aa1b..d18fdf4c60e 100644 --- a/wasm/tests/CoinType.test.ts +++ b/wasm/tests/CoinType.test.ts @@ -6,12 +6,10 @@ import "mocha"; import { assert } from "chai"; -import { initWasm } from "../dist"; describe("CoinType", () => { - - it("test raw value", async () => { - const { CoinType } = await initWasm();; + it("test raw value", () => { + const { CoinType } = globalThis.core; assert.equal(CoinType.bitcoin.value, 0); assert.equal(CoinType.litecoin.value, 2); @@ -20,6 +18,5 @@ describe("CoinType", () => { assert.equal(CoinType.binance.value, 714); assert.equal(CoinType.cosmos.value, 118); assert.equal(CoinType.solana.value, 501); - }); }); diff --git a/wasm/tests/HDWallet.test.ts b/wasm/tests/HDWallet.test.ts index 0270e539b5c..567517cc74d 100644 --- a/wasm/tests/HDWallet.test.ts +++ b/wasm/tests/HDWallet.test.ts @@ -6,19 +6,11 @@ import "mocha"; import { assert } from "chai"; -import { initWasm, WalletCore } from "../dist"; -import { Buffer } from "buffer"; describe("HDWallet", () => { - let core: WalletCore; - - before(async () => { - core = await initWasm(); - }); - it("test creating 24 words", () => { - const { HDWallet, Mnemonic } = core; + const { HDWallet, Mnemonic } = globalThis.core; var wallet = HDWallet.create(256, "password"); const mnemonic = wallet.mnemonic(); @@ -30,7 +22,7 @@ describe("HDWallet", () => { }); it("test deriving Ethereum address", () => { - const { HDWallet, CoinType } = core; + const { HDWallet, CoinType } = globalThis.core; var wallet = HDWallet.createWithMnemonic("ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal", "TREZOR"); const address = wallet.getAddressForCoin(CoinType.ethereum); diff --git a/wasm/tests/HRP.test.ts b/wasm/tests/HRP.test.ts index cd27ba37dcf..99d596e5f98 100644 --- a/wasm/tests/HRP.test.ts +++ b/wasm/tests/HRP.test.ts @@ -6,11 +6,10 @@ import "mocha"; import { assert } from "chai"; -import { initWasm } from "../dist"; describe("HRP", () => { - it("test string value", async () => { - const { HRP, describeHRP } = await initWasm(); + it("test string value", () => { + const { HRP, describeHRP } = globalThis.core; assert.equal(describeHRP(HRP.bitcoin), "bc"); assert.equal(describeHRP(HRP.binance), "bnb"); diff --git a/wasm/tests/Hash.test.ts b/wasm/tests/Hash.test.ts index d882c77848b..47c26e87e81 100644 --- a/wasm/tests/Hash.test.ts +++ b/wasm/tests/Hash.test.ts @@ -7,18 +7,10 @@ import "mocha"; import { assert } from "chai"; import { Buffer } from "buffer"; -import { initWasm, WalletCore } from "../dist"; describe("Hash", () => { - - let core: WalletCore; - - before(async () => { - core = await initWasm(); - }); - it("test keccak256", () => { - const { Hash, HexCoding } = core; + const { Hash, HexCoding } = globalThis.core; const sha3Hash = Hash.keccak256(Buffer.from("Test keccak-256")); @@ -29,7 +21,7 @@ describe("Hash", () => { }); it("test sha256", () => { - const { Hash, HexCoding } = core; + const { Hash, HexCoding } = globalThis.core; const sha256Hash = Hash.sha256(Buffer.from("Test hash")); assert.equal( @@ -39,7 +31,7 @@ describe("Hash", () => { }); it("test sha512_256", () => { - const { Hash, HexCoding } = core; + const { Hash, HexCoding } = globalThis.core; const hash = Hash.sha512_256(Buffer.from("hello")); assert.equal( diff --git a/wasm/tests/HexCoding.test.ts b/wasm/tests/HexCoding.test.ts index 4b131831379..0bacf5d67ce 100644 --- a/wasm/tests/HexCoding.test.ts +++ b/wasm/tests/HexCoding.test.ts @@ -6,11 +6,10 @@ import "mocha"; import { assert } from "chai"; -import { initWasm } from "../dist"; describe("HexCoding", () => { - it("test encoding / decoding hex string", async () => { - const { HexCoding } = await initWasm(); + it("test encoding / decoding hex string", () => { + const { HexCoding } = globalThis.core; const expected = new Uint8Array([0x52, 0x8]); const decoded = HexCoding.decode("0x5208"); diff --git a/wasm/tests/Mnemonic.test.ts b/wasm/tests/Mnemonic.test.ts index 9d0282eeebf..690c614aa95 100644 --- a/wasm/tests/Mnemonic.test.ts +++ b/wasm/tests/Mnemonic.test.ts @@ -6,18 +6,11 @@ import "mocha"; import { assert } from "chai"; -import { initWasm, WalletCore } from "../dist"; describe("Mnemonic", () => { - let core: WalletCore; - - before(async () => { - core = await initWasm(); - }); - it("test isValid", () => { - const { Mnemonic } = core; + const { Mnemonic } = globalThis.core; assert.isTrue( Mnemonic.isValid( @@ -32,7 +25,7 @@ describe("Mnemonic", () => { }); it("test isValidWord", () => { - const { Mnemonic } = core; + const { Mnemonic } = globalThis.core; assert.isTrue(Mnemonic.isValidWord("credit")); @@ -42,7 +35,7 @@ describe("Mnemonic", () => { }); it("test suggest", () => { - const { Mnemonic } = core; + const { Mnemonic } = globalThis.core; assert.equal(Mnemonic.suggest("air"), "air airport"); assert.equal(Mnemonic.suggest("rob"), "robot robust"); diff --git a/wasm/tests/PBKDF2.test.ts b/wasm/tests/PBKDF2.test.ts index 06024ee559d..138ff504963 100644 --- a/wasm/tests/PBKDF2.test.ts +++ b/wasm/tests/PBKDF2.test.ts @@ -7,11 +7,10 @@ import "mocha"; import { assert } from "chai"; import { Buffer } from "buffer"; -import { initWasm } from "../dist"; describe("PBKDF2", () => { - it("test sha256 hmac", async () => { - const { PBKDF2, HexCoding } = await initWasm(); + it("test sha256 hmac", () => { + const { PBKDF2, HexCoding } = globalThis.core; const password = Buffer.from("password"); const salt = Buffer.from("salt"); diff --git a/wasm/tests/StoredKey.test.ts b/wasm/tests/StoredKey.test.ts index d085dff9dc1..a24f8d8479f 100644 --- a/wasm/tests/StoredKey.test.ts +++ b/wasm/tests/StoredKey.test.ts @@ -6,12 +6,11 @@ import "mocha"; import { assert } from "chai"; -import { initWasm } from "../dist"; import { Buffer } from "buffer"; describe("StoredKey", () => { - it("test importing mnemonic", async () => { - const { StoredKey, CoinType } = await initWasm(); + it("test importing mnemonic", () => { + const { StoredKey, CoinType } = globalThis.core; const mnemonic = "team engine square letter hero song dizzy scrub tornado fabric divert saddle"; const password = Buffer.from("password"); diff --git a/wasm/tests/setup.test.ts b/wasm/tests/setup.test.ts new file mode 100644 index 00000000000..80215470759 --- /dev/null +++ b/wasm/tests/setup.test.ts @@ -0,0 +1,6 @@ +import "mocha"; +import { initWasm } from "../dist"; + +before(async () => { + globalThis.core = await initWasm(); +}); From 66889d0bcc62df599b414606e2a5587599f2ae66 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Tue, 9 Aug 2022 11:27:08 +0200 Subject: [PATCH 051/497] Scripts: separate out full build script from bootstrap.sh (#2484) * Scripts: separate out full build script from bootstrap.sh --- bootstrap.sh | 26 +++++--------------------- tools/build-and-test | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 21 deletions(-) create mode 100755 tools/build-and-test diff --git a/bootstrap.sh b/bootstrap.sh index e32cccfe915..1dba588dd30 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,28 +1,12 @@ #!/usr/bin/env bash +# +# Initializes the workspace with dependencies, then performs full build # Fail if any commands fails set -e -echo "#### Initializing... ####" +echo "#### Initializing workspace with dependencies ... ####" tools/install-dependencies -echo "#### Generating files... ####" -tools/generate-files - -echo "#### Building... ####" -cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -make -Cbuild -j12 tests TrezorCryptoTests - -if [ -x "$(command -v clang-tidy)" ]; then - echo "#### Linting... ####" - tools/lint -fi - -echo "#### Testing... ####" -export CK_TIMEOUT_MULTIPLIER=4 -build/trezor-crypto/crypto/tests/TrezorCryptoTests - -ROOT="`dirname \"$0\"`" -TESTS_ROOT="`(cd \"$ROOT/tests\" && pwd)`" -build/tests/tests "$TESTS_ROOT" +echo "#### Building and running tests ... ####" +tools/build-and-test diff --git a/tools/build-and-test b/tools/build-and-test new file mode 100755 index 00000000000..9c1bebb0dff --- /dev/null +++ b/tools/build-and-test @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# +# Perform full build and runs the tests. +# Prerequisite: workspace with dependencies installed, see bootstrap.sh + +# Fail if any commands fails +set -e + +echo "#### Generating files... ####" +tools/generate-files + +echo "#### Building... ####" +cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ +make -Cbuild -j12 tests TrezorCryptoTests + +if [ -x "$(command -v clang-tidy)" ]; then + echo "#### Linting... ####" + tools/lint +fi + +echo "#### Running trezor-crypto tests... ####" +export CK_TIMEOUT_MULTIPLIER=4 +build/trezor-crypto/crypto/tests/TrezorCryptoTests + +echo "#### Running unit tests... ####" +ROOT="`dirname \"$0\"`/.." +TESTS_ROOT="`(cd \"$ROOT/tests\" && pwd)`" +FILTER="*" +build/tests/tests "$TESTS_ROOT" --gtest_filter="$FILTER" From d1e40d2cbed146776874cfc13241650661b2b513 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 10 Aug 2022 14:43:21 +0200 Subject: [PATCH 052/497] [Ethereum] Support fixed array in ABI (#2474) * wip(param_array_fix): add ParamArrayFix basis * wip(param_array_fix): add encoding * feat(ethabi): add setValueJson for ParamArrayFix * style(ethabi): clang format off for region * feat(ethabi): clean fix array code * more style fixes * longer timeout for AnyAddress test * fix(review): fix review comments * fix: review comments Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- src/Ethereum/ABI/Array.cpp | 36 +++++++ src/Ethereum/ABI/Array.h | 38 ++++++- tests/Ethereum/AbiStructTests.cpp | 18 ++++ tests/Ethereum/AbiTests.cpp | 173 ++++++++++++++++++++---------- wasm/tests/AnyAddress.test.ts | 2 +- 5 files changed, 208 insertions(+), 59 deletions(-) diff --git a/src/Ethereum/ABI/Array.cpp b/src/Ethereum/ABI/Array.cpp index 60cd194c1b2..90071786336 100644 --- a/src/Ethereum/ABI/Array.cpp +++ b/src/Ethereum/ABI/Array.cpp @@ -133,4 +133,40 @@ std::string ParamArray::getExtraTypes(std::vector& ignoreList) cons return (proto != nullptr) ? proto->getExtraTypes(ignoreList) : ""; } +void ParamArrayFix::encode(Data& data) const { + this->_params.encode(data); +} + +bool ParamArrayFix::decode(const Data& encoded, size_t& offset_inout) { + return this->_params.decode(encoded, offset_inout); +} + +bool ParamArrayFix::setValueJson(const std::string& value) { + auto valuesJson = json::parse(value, nullptr, false); + if (valuesJson.is_discarded() || !valuesJson.is_array() || _params.getCount() != valuesJson.size()) { + return false; + } + + std::size_t idx{0}; + for (auto&& e : valuesJson) { + std::string eString = e.is_string() ? e.get() : e.dump(); + _params.getParamUnsafe(idx)->setValueJson(eString); + ++idx; + } + return true; +} + +void ParamArrayFix::addParams(const Params& params) { + auto addParamFunctor = [this](auto&& param) { + if (param == nullptr) { + throw std::runtime_error("param can't be nullptr"); + } + if (_params.getCount() >= 1 && param->getType() != _params.getParamUnsafe(0)->getType()) { + throw std::runtime_error("params need to be the same type"); + } // do not add different types + _params.addParam(param); + }; + std::for_each(begin(params), end(params), addParamFunctor); +} + } // namespace TW::Ethereum::ABI diff --git a/src/Ethereum/ABI/Array.h b/src/Ethereum/ABI/Array.h index c4a8c8e80dd..08138aad6a2 100644 --- a/src/Ethereum/ABI/Array.h +++ b/src/Ethereum/ABI/Array.h @@ -15,8 +15,7 @@ namespace TW::Ethereum::ABI { /// Dynamic array of the same types, "[]" /// Normally has at least one element. Empty array can have prototype set so its type is known. /// Empty with no prototype is possible, but should be avoided. -class ParamArray: public ParamCollection -{ +class ParamArray : public ParamCollection { private: ParamSet _params; std::shared_ptr _proto; // an optional prototype element, determines the array type, useful in empty array case @@ -27,8 +26,10 @@ class ParamArray: public ParamCollection public: ParamArray() = default; - ParamArray(const std::shared_ptr& param1) : ParamCollection() { addParam(param1); } - ParamArray(const std::vector>& params) : ParamCollection() { setVal(params); } + ParamArray(const std::shared_ptr& param1) + : ParamCollection() { addParam(param1); } + ParamArray(const std::vector>& params) + : ParamCollection() { setVal(params); } void setVal(const std::vector>& params) { addParams(params); } std::vector> const& getVal() const { return _params.getParams(); } int addParam(const std::shared_ptr& param); @@ -46,4 +47,33 @@ class ParamArray: public ParamCollection virtual std::string getExtraTypes(std::vector& ignoreList) const; }; +/// Fixed-size array of the same type e.g, "type[4]" +class ParamArrayFix final : public ParamCollection { +public: + //! Public Definitions + using Params = std::vector>; + + //! Public constructor + explicit ParamArrayFix(const Params& params) noexcept(false) + : ParamCollection() { + this->addParams(params); + } + + //! Public member methods + [[nodiscard]] std::size_t getCount() const final { return _params.getCount(); } + [[nodiscard]] size_t getSize() const final { return _params.getSize(); } + [[nodiscard]] bool isDynamic() const final { return false; } + [[nodiscard]] std::string getType() const final { return _params.getParamUnsafe(0)->getType() + "[" + std::to_string(_params.getCount()) + "]"; } + void encode(Data& data) const final; + bool decode(const Data& encoded, size_t& offset_inout) final; + bool setValueJson(const std::string& value) final; + +private: + //! Private member functions + void addParams(const Params& params) noexcept(false); + + //! Private member fields + ParamSet _params; +}; + } // namespace TW::Ethereum::ABI diff --git a/tests/Ethereum/AbiStructTests.cpp b/tests/Ethereum/AbiStructTests.cpp index be9b6dabd91..7db3e83333b 100644 --- a/tests/Ethereum/AbiStructTests.cpp +++ b/tests/Ethereum/AbiStructTests.cpp @@ -892,6 +892,24 @@ TEST(EthereumAbiStruct, ParamHashStruct) { EXPECT_TRUE(p->setValueJson("0x0000000000000000000000000000000123456789")); EXPECT_EQ(hex(p->hashStruct()), "0000000000000000000000000000000000000000000000000000000123456789"); } + { + using collection = std::vector>; + auto p = std::make_shared(collection{std::make_shared(), std::make_shared(), std::make_shared()}); + EXPECT_TRUE(p->setValueJson("[1,0,1]")); + EXPECT_EQ(hex(p->hashStruct()), "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); + } + { + using collection = std::vector>; + auto p = std::make_shared(collection{std::make_shared(), std::make_shared(), std::make_shared()}); + EXPECT_TRUE(p->setValueJson("[13,14,15]")); + EXPECT_EQ(hex(p->hashStruct()), "000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f"); + + // Coverage + EXPECT_FALSE(p->setValueJson("NotValidJson")); + EXPECT_FALSE(p->setValueJson("{}")); + EXPECT_FALSE(p->setValueJson("[1,2,3,4]")); + EXPECT_FALSE(p->setValueJson("[1,2]")); + } { auto p = std::make_shared(std::make_shared()); EXPECT_TRUE(p->setValueJson("[13,14,15]")); diff --git a/tests/Ethereum/AbiTests.cpp b/tests/Ethereum/AbiTests.cpp index 7dbc0b708b6..712364de657 100644 --- a/tests/Ethereum/AbiTests.cpp +++ b/tests/Ethereum/AbiTests.cpp @@ -13,7 +13,6 @@ using namespace TW; using namespace TW::Ethereum::ABI; - ///// Parameter types TEST(EthereumAbi, ParamTypeNames) { @@ -435,7 +434,7 @@ TEST(EthereumAbi, ParamByteArray) { EXPECT_EQ(2 * 32ul, param.getSize()); EXPECT_EQ( "000000000000000000000000000000000000000000000000000000000000000a" - "3132333435363738393000000000000000000000000000000000000000000000", + "3132333435363738393000000000000000000000000000000000000000000000", hex(encoded)); EXPECT_EQ(2 * 32ul, encoded.size()); EXPECT_EQ(2 * 32ul, param.getSize()); @@ -462,7 +461,7 @@ TEST(EthereumAbi, ParamByteArrayFix) { EXPECT_EQ(32ul, encoded.size()); EXPECT_EQ(32ul, param.getSize()); EXPECT_EQ( - "3132333435363738393000000000000000000000000000000000000000000000", + "3132333435363738393000000000000000000000000000000000000000000000", hex(encoded)); size_t offset = 0; EXPECT_TRUE(param.decode(encoded, offset)); @@ -526,6 +525,41 @@ TEST(EthereumAbi, ParamArrayEmpty) { EXPECT_EQ("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", hex(param.hashStruct())); } +TEST(EthereumAbi, ParamFixedArrayAddress) { + { + auto param = ParamArrayFix({std::make_shared(Data(parse_hex("f784682c82526e245f50975190ef0fff4e4fc077")))}); + EXPECT_EQ(param.getType(), "address[1]"); + EXPECT_EQ(param.getCount(), 1ul); + EXPECT_EQ(param.getSize(), 32ul); + EXPECT_FALSE(param.isDynamic()); + Data encoded; + param.encode(encoded); + EXPECT_EQ(hex(encoded), "000000000000000000000000f784682c82526e245f50975190ef0fff4e4fc077"); + std::size_t offset{0}; + EXPECT_TRUE(param.decode(encoded, offset)); + } + { + auto param = ParamArrayFix({std::make_shared(Data(parse_hex("f784682c82526e245f50975190ef0fff4e4fc077"))), + std::make_shared(Data(parse_hex("2e00cd222cb42b616d86d037cc494e8ab7f5c9a3")))}); + EXPECT_EQ(param.getType(), "address[2]"); + EXPECT_EQ(param.getCount(), 2ul); + Data encoded; + param.encode(encoded); + EXPECT_EQ(hex(encoded), "000000000000000000000000f784682c82526e245f50975190ef0fff4e4fc0770000000000000000000000002e00cd222cb42b616d86d037cc494e8ab7f5c9a3"); + std::size_t offset{0}; + EXPECT_TRUE(param.decode(encoded, offset)); + } + { + // nullptr + EXPECT_THROW(ParamArrayFix({nullptr}), std::runtime_error); + // Should be the same type + EXPECT_THROW( + ParamArrayFix({std::make_shared(Data(parse_hex("f784682c82526e245f50975190ef0fff4e4fc077"))), + std::make_shared("Foo")}), + std::runtime_error); + } +} + TEST(EthereumAbi, ParamArrayAddress) { { auto param = ParamArray(); @@ -558,7 +592,7 @@ TEST(EthereumAbi, ParamArrayAddress) { EXPECT_EQ(2ul, param.getCount()); EXPECT_EQ(2ul, param.getVal().size()); EXPECT_EQ( - "2e00cd222cb42b616d86d037cc494e8ab7f5c9a3", + "2e00cd222cb42b616d86d037cc494e8ab7f5c9a3", hex((std::dynamic_pointer_cast(param.getVal()[1]))->getData())); } } @@ -585,7 +619,7 @@ TEST(EthereumAbi, ParamArrayBytesContract) { EXPECT_EQ(4ul, param.getCount()); EXPECT_EQ(4ul, param.getVal().size()); - EXPECT_EQ("bytes[]", param.getType()); + EXPECT_EQ("bytes[]", param.getType()); EXPECT_TRUE(param.isDynamic()); Data encoded; @@ -607,7 +641,7 @@ TEST(EthereumAbi, ParamTupleStatic) { Data encoded; param.encode(encoded); EXPECT_EQ("0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000007b", hex(encoded)); - { // decode + { // decode size_t offset = 0; auto param2 = ParamTuple(); param2.addParam(std::make_shared()); @@ -652,7 +686,8 @@ TEST(EthereumAbi, ParamTupleDynamic) { "0000000000000000000000000000000000000000000000000000000000000014" // len "446f6e27742074727573742c2076657269667921000000000000000000000000" "000000000000000000000000000000000000000000000000000000000000000a" // len - "0001020304050607080900000000000000000000000000000000000000000000", hex(encoded)); + "0001020304050607080900000000000000000000000000000000000000000000", + hex(encoded)); } } @@ -673,14 +708,14 @@ TEST(EthereumAbi, EncodeVectorByte) { p.encode(encoded); EXPECT_EQ( "000000000000000000000000000000000000000000000000000000000000000a" - "3132333435363738393000000000000000000000000000000000000000000000", hex(encoded)); + "3132333435363738393000000000000000000000000000000000000000000000", + hex(encoded)); } TEST(EthereumAbi, EncodeArrayByte) { auto p = ParamArray(std::vector>{ std::make_shared(parse_hex("1011")), - std::make_shared(parse_hex("102222")) - }); + std::make_shared(parse_hex("102222"))}); EXPECT_EQ("bytes[]", p.getType()); Data encoded; p.encode(encoded); @@ -692,8 +727,7 @@ TEST(EthereumAbi, EncodeArrayByte) { "1011000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000000003" "1022220000000000000000000000000000000000000000000000000000000000", - hex(encoded) - ); + hex(encoded)); EXPECT_EQ((1 + 2 + 2 * 2) * 32ul, encoded.size()); EXPECT_EQ((1 + 2 + 2 * 2) * 32ul, p.getSize()); } @@ -814,8 +848,7 @@ TEST(EthereumAbi, DecodeArrayOfByteArray) { "0000000000000000000000000000000000000000000000000000000000000002" "1011000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000000003" - "1022200000000000000000000000000000000000000000000000000000000000" - ); + "1022200000000000000000000000000000000000000000000000000000000000"); size_t offset = 0; Data decoded; auto param = ParamArray(); @@ -831,10 +864,10 @@ TEST(EthereumAbi, DecodeArrayOfByteArray) { ///// Parameters encode & decode TEST(EthereumAbi, EncodeParamsSimple) { - auto p = Parameters(std::vector>{ + auto p = Parameters(std::vector>{ std::make_shared(16u), std::make_shared(17u), - std::make_shared(true) }); + std::make_shared(true)}); EXPECT_EQ("(uint256,uint256,bool)", p.getType()); Data encoded; p.encode(encoded); @@ -850,16 +883,14 @@ TEST(EthereumAbi, EncodeParamsSimple) { TEST(EthereumAbi, EncodeParamsMixed) { auto p = Parameters(std::vector>{ - std::make_shared(69u), + std::make_shared(69u), std::make_shared(std::vector>{ std::make_shared(1), std::make_shared(2), - std::make_shared(3) - }), + std::make_shared(3)}), std::make_shared(true), std::make_shared("Hello"), - std::make_shared(Data{0x64, 0x61, 0x76, 0x65}) - }); + std::make_shared(Data{0x64, 0x61, 0x76, 0x65})}); EXPECT_EQ("(uint256,uint256[],bool,string,bytes)", p.getType()); Data encoded; p.encode(encoded); @@ -907,8 +938,7 @@ TEST(EthereumAbi, DecodeParamsSimple) { auto p = Parameters(std::vector>{ std::make_shared(0), std::make_shared(0), - std::make_shared(false) - }); + std::make_shared(false)}); EXPECT_EQ("(uint256,uint256,bool)", p.getType()); size_t offset = 0; bool res = p.decode(encoded, offset); @@ -934,8 +964,9 @@ TEST(EthereumAbi, DecodeParamsMixed) { append(encoded, parse_hex("48656c6c6f000000000000000000000000000000000000000000000000000000")); append(encoded, parse_hex("0000000000000000000000000000000000000000000000000000000000000004")); append(encoded, parse_hex("6461766500000000000000000000000000000000000000000000000000000000")); + // clang-format off auto p = Parameters(std::vector>{ - std::make_shared(), + std::make_shared(), std::make_shared(std::vector>{ std::make_shared(), std::make_shared(), @@ -945,6 +976,7 @@ TEST(EthereumAbi, DecodeParamsMixed) { std::make_shared(), std::make_shared() }); + // clang-format on EXPECT_EQ("(uint256,uint256[],bool,string,bytes)", p.getType()); size_t offset = 0; bool res = p.decode(encoded, offset); @@ -961,21 +993,24 @@ TEST(EthereumAbi, DecodeParamsMixed) { ///// Function encode & decode TEST(EthereumAbi, EncodeSignature) { + // clang-format off auto func = Function("baz", std::vector>{ std::make_shared(69u), std::make_shared(true) }); + // clang-format on EXPECT_EQ("baz(uint256,bool)", func.getType()); Data encoded; func.encode(encoded); EXPECT_EQ(encoded.size(), 32 * 2 + 4ul); EXPECT_EQ(hex(encoded.begin(), encoded.begin() + 4), "72ed38b6"); - EXPECT_EQ(hex(encoded.begin() + 4, encoded.begin() + 36 ), "0000000000000000000000000000000000000000000000000000000000000045"); - EXPECT_EQ(hex(encoded.begin() + 36, encoded.begin() + 68 ), "0000000000000000000000000000000000000000000000000000000000000001"); + EXPECT_EQ(hex(encoded.begin() + 4, encoded.begin() + 36), "0000000000000000000000000000000000000000000000000000000000000045"); + EXPECT_EQ(hex(encoded.begin() + 36, encoded.begin() + 68), "0000000000000000000000000000000000000000000000000000000000000001"); } TEST(EthereumAbi, EncodeFunctionWithDynamicArgumentsCase1) { + // clang-format off auto func = Function("sam", std::vector>{ std::make_shared(Data{0x64, 0x61, 0x76, 0x65}), std::make_shared(true), @@ -985,15 +1020,16 @@ TEST(EthereumAbi, EncodeFunctionWithDynamicArgumentsCase1) { std::make_shared(3) }) }); + // clang-format on EXPECT_EQ("sam(bytes,bool,uint256[])", func.getType()); Data encoded; func.encode(encoded); EXPECT_EQ(encoded.size(), 32 * 9 + 4ul); - EXPECT_EQ(hex(encoded.begin() + 0, encoded.begin() + 4 ), "a5643bf2"); - EXPECT_EQ(hex(encoded.begin() + 4, encoded.begin() + 36 ), "0000000000000000000000000000000000000000000000000000000000000060"); - EXPECT_EQ(hex(encoded.begin() + 36, encoded.begin() + 68 ), "0000000000000000000000000000000000000000000000000000000000000001"); - EXPECT_EQ(hex(encoded.begin() + 68, encoded.begin() + 100), "00000000000000000000000000000000000000000000000000000000000000a0"); + EXPECT_EQ(hex(encoded.begin() + 0, encoded.begin() + 4), "a5643bf2"); + EXPECT_EQ(hex(encoded.begin() + 4, encoded.begin() + 36), "0000000000000000000000000000000000000000000000000000000000000060"); + EXPECT_EQ(hex(encoded.begin() + 36, encoded.begin() + 68), "0000000000000000000000000000000000000000000000000000000000000001"); + EXPECT_EQ(hex(encoded.begin() + 68, encoded.begin() + 100), "00000000000000000000000000000000000000000000000000000000000000a0"); EXPECT_EQ(hex(encoded.begin() + 100, encoded.begin() + 132), "0000000000000000000000000000000000000000000000000000000000000004"); EXPECT_EQ(hex(encoded.begin() + 132, encoded.begin() + 164), "6461766500000000000000000000000000000000000000000000000000000000"); EXPECT_EQ(hex(encoded.begin() + 164, encoded.begin() + 196), "0000000000000000000000000000000000000000000000000000000000000003"); @@ -1003,24 +1039,25 @@ TEST(EthereumAbi, EncodeFunctionWithDynamicArgumentsCase1) { } TEST(EthereumAbi, EncodeFunctionWithDynamicArgumentsCase2) { + // clang-format off auto func = Function("f", std::vector>{ std::make_shared(0x123), std::make_shared(std::vector>{ std::make_shared(0x456), - std::make_shared(0x789) - }), + std::make_shared(0x789)}), std::make_shared(10, std::vector{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30}), std::make_shared("Hello, world!") }); + // clamp-format on EXPECT_EQ("f(uint256,uint32[],bytes10,string)", func.getType()); Data encoded; func.encode(encoded); EXPECT_EQ(encoded.size(), 32 * 9 + 4ul); - EXPECT_EQ(hex(encoded.begin() + 0, encoded.begin() + 4 ), "47b941bf"); - EXPECT_EQ(hex(encoded.begin() + 4, encoded.begin() + 36 ), "0000000000000000000000000000000000000000000000000000000000000123"); - EXPECT_EQ(hex(encoded.begin() + 36, encoded.begin() + 68 ), "0000000000000000000000000000000000000000000000000000000000000080"); - EXPECT_EQ(hex(encoded.begin() + 68, encoded.begin() + 100), "3132333435363738393000000000000000000000000000000000000000000000"); + EXPECT_EQ(hex(encoded.begin() + 0, encoded.begin() + 4), "47b941bf"); + EXPECT_EQ(hex(encoded.begin() + 4, encoded.begin() + 36), "0000000000000000000000000000000000000000000000000000000000000123"); + EXPECT_EQ(hex(encoded.begin() + 36, encoded.begin() + 68), "0000000000000000000000000000000000000000000000000000000000000080"); + EXPECT_EQ(hex(encoded.begin() + 68, encoded.begin() + 100), "3132333435363738393000000000000000000000000000000000000000000000"); EXPECT_EQ(hex(encoded.begin() + 100, encoded.begin() + 132), "00000000000000000000000000000000000000000000000000000000000000e0"); EXPECT_EQ(hex(encoded.begin() + 132, encoded.begin() + 164), "0000000000000000000000000000000000000000000000000000000000000002"); EXPECT_EQ(hex(encoded.begin() + 164, encoded.begin() + 196), "0000000000000000000000000000000000000000000000000000000000000456"); @@ -1033,10 +1070,12 @@ TEST(EthereumAbi, DecodeFunctionOutputCase1) { Data encoded; append(encoded, parse_hex("0000000000000000000000000000000000000000000000000000000000000045")); + // clang-format off auto func = Function("readout", std::vector>{ std::make_shared(parse_hex("f784682c82526e245f50975190ef0fff4e4fc077")), std::make_shared(1000) }); + // clang-format on func.addOutParam(std::make_shared()); EXPECT_EQ("readout(address,uint64)", func.getType()); @@ -1055,23 +1094,23 @@ TEST(EthereumAbi, DecodeFunctionOutputCase1) { } TEST(EthereumAbi, DecodeFunctionOutputCase2) { + // clang-format off auto func = Function("getAmountsOut", std::vector>{ std::make_shared(100), std::make_shared(std::make_shared(parse_hex("000000000000000000000000f784682c82526e245f50975190ef0fff4e4fc077"))) }); + // clang-format on func.addOutParam(std::make_shared(std::vector>{ std::make_shared(66), - std::make_shared(67) - })); + std::make_shared(67)})); EXPECT_EQ("getAmountsOut(uint256,address[])", func.getType()); Data encoded; append(encoded, parse_hex( - "0000000000000000000000000000000000000000000000000000000000000020" - "0000000000000000000000000000000000000000000000000000000000000002" - "0000000000000000000000000000000000000000000000000000000000000004" - "0000000000000000000000000000000000000000000000000000000000000005" - )); + "0000000000000000000000000000000000000000000000000000000000000020" + "0000000000000000000000000000000000000000000000000000000000000002" + "0000000000000000000000000000000000000000000000000000000000000004" + "0000000000000000000000000000000000000000000000000000000000000005")); size_t offset = 0; bool res = func.decodeOutput(encoded, offset); EXPECT_TRUE(res); @@ -1090,9 +1129,11 @@ TEST(EthereumAbi, DecodeInputSignature) { append(encoded, parse_hex("72ed38b6")); append(encoded, parse_hex("0000000000000000000000000000000000000000000000000000000000000045")); append(encoded, parse_hex("0000000000000000000000000000000000000000000000000000000000000001")); + // clang-format off auto func = Function("baz", std::vector>{ std::make_shared(), std::make_shared() }); + // clang-format on EXPECT_EQ("baz(uint256,bool)", func.getType()); size_t offset = 0; bool res = func.decodeInput(encoded, offset); @@ -1118,6 +1159,7 @@ TEST(EthereumAbi, DecodeFunctionInputWithDynamicArgumentsCase1) { append(encoded, parse_hex("0000000000000000000000000000000000000000000000000000000000000002")); append(encoded, parse_hex("0000000000000000000000000000000000000000000000000000000000000003")); + // clang-format off auto func = Function("sam", std::vector>{ std::make_shared(Data{0x64, 0x61, 0x76, 0x65}), std::make_shared(true), @@ -1127,6 +1169,7 @@ TEST(EthereumAbi, DecodeFunctionInputWithDynamicArgumentsCase1) { std::make_shared(3) }) }); + // clang-format on EXPECT_EQ("sam(bytes,bool,uint256[])", func.getType()); size_t offset = 0; @@ -1159,15 +1202,16 @@ TEST(EthereumAbi, DecodeFunctionInputWithDynamicArgumentsCase2) { append(encoded, parse_hex("000000000000000000000000000000000000000000000000000000000000000d")); append(encoded, parse_hex("48656c6c6f2c20776f726c642100000000000000000000000000000000000000")); + // clang-format off auto func = Function("f", std::vector>{ std::make_shared(0x123), std::make_shared(std::vector>{ std::make_shared(0x456), - std::make_shared(0x789) - }), + std::make_shared(0x789)}), std::make_shared(10, std::vector{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30}), std::make_shared("Hello, world!") }); + // clang-format on EXPECT_EQ("f(uint256,uint32[],bytes10,string)", func.getType()); size_t offset = 0; @@ -1213,6 +1257,7 @@ TEST(EthereumAbi, DecodeFunctionContractMulticall) { "000000000000000000000000000000000000000000000000000000000000000000"); ASSERT_EQ(4 + 928ul, encoded.size()); + // clang-format off auto func = Function("multicall", std::vector>{ std::make_shared(std::vector>{ std::make_shared(Data()), @@ -1221,6 +1266,7 @@ TEST(EthereumAbi, DecodeFunctionContractMulticall) { std::make_shared(Data()) }), }); + // clang-format on EXPECT_EQ("multicall(bytes[])", func.getType()); size_t offset = 0; @@ -1297,12 +1343,12 @@ TEST(EthereumAbi, ParamFactoryGetArrayValue) { ASSERT_EQ(vals.size(), 1ul); EXPECT_EQ(vals[0], "0"); } - { // wrong type, not array + { // wrong type, not array auto pArray = std::make_shared(std::make_shared()); const auto vals = ParamFactory::getArrayValue(pArray, "bool"); EXPECT_EQ(vals.size(), 0ul); } - { // wrong param, not array + { // wrong param, not array auto pArray = std::make_shared(); const auto vals = ParamFactory::getArrayValue(pArray, "uint8[]"); EXPECT_EQ(vals.size(), 0ul); @@ -1506,12 +1552,31 @@ TEST(EthereumAbi, ParamFactorySetGetValue) { TEST(EthereumAbi, ParamFactoryGetValue) { const std::vector types = { - "uint8", "uint16", "uint32", "uint64", "uint128", "uint168", "uint256", - "int8", "int16", "int32", "int64", "int128", "int168", "int256", - "bool", "string", "bytes", "bytes168", "address", - "uint8[]", "address[]", "bool[]", "bytes[]", + "uint8", + "uint16", + "uint32", + "uint64", + "uint128", + "uint168", + "uint256", + "int8", + "int16", + "int32", + "int64", + "int128", + "int168", + "int256", + "bool", + "string", + "bytes", + "bytes168", + "address", + "uint8[]", + "address[]", + "bool[]", + "bytes[]", }; - for (auto t: types) { + for (auto t : types) { std::shared_ptr p = ParamFactory::make(t); EXPECT_EQ(t, p->getType()); @@ -1549,7 +1614,7 @@ TEST(EthereumAbi, ParamSetMethods) { { auto p = ParamSet(std::vector>{ std::make_shared(16u), - std::make_shared(true) }); + std::make_shared(true)}); EXPECT_EQ(p.getCount(), 2ul); EXPECT_EQ(p.addParam(std::shared_ptr(nullptr)), -1); @@ -1572,7 +1637,7 @@ TEST(EthereumAbi, ParamSetMethods) { TEST(EthereumAbi, ParametersMethods) { auto p = Parameters(std::vector>{ std::make_shared(16u), - std::make_shared(true) }); + std::make_shared(true)}); EXPECT_TRUE(p.isDynamic()); EXPECT_EQ(p.getCount(), 2ul); EXPECT_FALSE(p.setValueJson("value")); diff --git a/wasm/tests/AnyAddress.test.ts b/wasm/tests/AnyAddress.test.ts index 20171c3bd21..8d0de564223 100644 --- a/wasm/tests/AnyAddress.test.ts +++ b/wasm/tests/AnyAddress.test.ts @@ -26,5 +26,5 @@ describe("AnyAddress", () => { assert.equal(HexCoding.encode(data), "0x66c2f508c9c555cacc9fb26d88e88dd54e210bb5a8bce5687f60d7e75c4cd07f"); address.delete(); - }); + }).timeout(5000); }); From c6680476f27e7525a10d65b97c5e32f6676cfe1f Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Wed, 10 Aug 2022 17:20:38 +0200 Subject: [PATCH 053/497] [Cardano] Use two-level packing for tokens; Cbor maps must have unique key (#2476) * Cbor map uses map internally * Test update * Use two-level packing for tokens * Update Oasis tests results, order only * Add direct unit tests * Minor improvements, review * Update swift and kotlin test results * Minor namespace, review --- .../blockchains/cardano/TestCardanoSigning.kt | 4 +- .../app/blockchains/oasis/TestOasisSigner.kt | 2 +- src/Cardano/Transaction.cpp | 59 +++++++++++++------ src/Cardano/Transaction.h | 6 ++ src/Cbor.cpp | 14 ++--- src/Cbor.h | 10 +++- swift/Tests/Blockchains/CardanoTests.swift | 4 +- swift/Tests/Blockchains/OasisTests.swift | 2 +- tests/Cardano/SigningTests.cpp | 10 ++-- tests/Cardano/TransactionTests.cpp | 16 +++++ tests/Oasis/SignerTests.cpp | 2 +- tests/Oasis/TWAnySignerTests.cpp | 2 +- 12 files changed, 93 insertions(+), 38 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigning.kt index 3fb60658ea2..0917f91f828 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigning.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigning.kt @@ -147,9 +147,9 @@ class TestCardanoSigning { val encoded = output.encoded assertEquals(Numeric.toHexString(encoded.toByteArray()), - "0x83a40082825820f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76701825820f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76702018282583901558dd902616f5cd01edcc62870cb4748c45403f1228218bee5b628b526f0ca9e7a2c04d548fbd6ce86f358be139fe680652536437d1d6fd5821a00160a5ba1581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a14653554e4441451a01312d00825839018d98bea0414243dc84070f96265577e7e6cf702d62e871016885034ecc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468821a0080a574a2581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a144435542591a004c4b40581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a14653554e4441451a03a2bbd9021a0002af5e031a032dcd55a100818258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df290584000feb412442f8851faa59742eb2c37f3994b0d143a424367143490cf828246991e504fa8eac61c403bfa7634bd1f0adc44f3f54f6a474856701e2cbb15fb5b04f6"); + "0x83a40082825820f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76701825820f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76702018282583901558dd902616f5cd01edcc62870cb4748c45403f1228218bee5b628b526f0ca9e7a2c04d548fbd6ce86f358be139fe680652536437d1d6fd5821a00160a5ba1581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a14653554e4441451a01312d00825839018d98bea0414243dc84070f96265577e7e6cf702d62e871016885034ecc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468821a0080aac9a1581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a244435542591a004c4b404653554e4441451a03a2bbd9021a0002aa09031a032dcd55a100818258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df2905840d90dcfbd190cbe59c42094e59eeb49b3de9d80a85b786cc311f932c5c9302d1c8c6c577b22aa70ff7955c139c700ea918f8cb425c3ba43a27980e1d238e4e908f6"); val txid = output.txId - assertEquals(Numeric.toHexString(txid.toByteArray()), "0xdacb3a0c5b3b7fa36b49f25a0a59b941ab8a21f0db5770e9e6982ff120122649"); + assertEquals(Numeric.toHexString(txid.toByteArray()), "0x201c537693b005b64a0f0528e366ec67a84be0119ed4363b547f141f2a7770c2"); } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/oasis/TestOasisSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/oasis/TestOasisSigner.kt index 536201188ca..f9962ebb13c 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/oasis/TestOasisSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/oasis/TestOasisSigner.kt @@ -45,7 +45,7 @@ class TestOasisSigner { val output = AnySigner.sign(signingInput.build(), OASIS, SigningOutput.parser()) assertEquals( - "0xa273756e747275737465645f7261775f76616c7565585ea4656e6f6e636500666d6574686f64707374616b696e672e5472616e7366657263666565a2636761730066616d6f756e74410064626f6479a262746f5500c73cc001463434915ba3f39751beb7c0905b45eb66616d6f756e744400989680697369676e6174757265a26a7075626c69635f6b6579582093d8f8a455f50527976a8aa87ebde38d5606efa86cb985d3fb466aff37000e3b697369676e61747572655840e331ce731ed819106586152b13cd98ecf3248a880bdc71174ee3d83f6d5f3f8ee8fc34c19b22032f2f1e3e06d382720125d7a517fba9295c813228cc2b63170b", + "0xa2697369676e6174757265a2697369676e617475726558406e51c18c9b2015c9b49414b3307336597f51ff331873d214ce2db81c9651a34d99529ccaa294a39ccd01c6b0bc2c2239d87c624e5ba4840cf99ac8f9283e240c6a7075626c69635f6b6579582093d8f8a455f50527976a8aa87ebde38d5606efa86cb985d3fb466aff37000e3b73756e747275737465645f7261775f76616c7565585ea463666565a2636761730066616d6f756e74410064626f6479a262746f5500c73cc001463434915ba3f39751beb7c0905b45eb66616d6f756e744400989680656e6f6e636500666d6574686f64707374616b696e672e5472616e73666572", Numeric.toHexString(output.encoded.toByteArray()) ) } diff --git a/src/Cardano/Transaction.cpp b/src/Cardano/Transaction.cpp index bfc3d21c2f8..905c4980c25 100644 --- a/src/Cardano/Transaction.cpp +++ b/src/Cardano/Transaction.cpp @@ -67,6 +67,24 @@ uint256_t TokenBundle::getAmount(const std::string& key) const { return findkey->second.amount; } +unordered_set TokenBundle::getPolicyIds() const { + unordered_set policyIds; + std::transform(bundle.cbegin(), bundle.cend(), + std::inserter(policyIds, policyIds.begin()), + [](auto&& cur){ return cur.second.policyId; }); + return policyIds; +} + +vector TokenBundle::getByPolicyId(const string& policyId) const { + vector filtered; + for (const auto& t: bundle) { + if (t.second.policyId == policyId) { + filtered.push_back(t.second); + } + } + return filtered; +} + uint64_t roundupBytesToWords(uint64_t b) { return ((b + 7) / 8); } const uint64_t TokenBundle::MinUtxoValue = 1000000; @@ -127,8 +145,8 @@ Proto::TxInput TxInput::toProto() const { txInput.mutable_out_point()->set_output_index(outputIndex); txInput.set_address(address.data(), address.size()); txInput.set_amount(amount); - for (auto iter = tokenBundle.bundle.begin(); iter != tokenBundle.bundle.end(); ++iter) { - *txInput.add_token_amount() = iter->second.toProto(); + for (const auto& token: tokenBundle.bundle) { + *txInput.add_token_amount() = token.second.toProto(); } return txInput; } @@ -163,14 +181,14 @@ Proto::TransactionPlan TransactionPlan::toProto() const { plan.set_amount(amount); plan.set_fee(fee); plan.set_change(change); - for (const auto& t: availableTokens.bundle) { - *plan.add_available_tokens() = t.second.toProto(); + for (const auto& token: availableTokens.bundle) { + *plan.add_available_tokens() = token.second.toProto(); } - for (const auto& t: outputTokens.bundle) { - *plan.add_output_tokens() = t.second.toProto(); + for (const auto& token: outputTokens.bundle) { + *plan.add_output_tokens() = token.second.toProto(); } - for (const auto& t: changeTokens.bundle) { - *plan.add_change_tokens() = t.second.toProto(); + for (const auto& token: changeTokens.bundle) { + *plan.add_change_tokens() = token.second.toProto(); } for (const auto& u: utxos) { *plan.add_utxos() = u.toProto(); @@ -196,15 +214,22 @@ Cbor::Encode cborizeOutputAmounts(const Amount& amount, const TokenBundle& token return Cbor::Encode::uint(amount); } // native and token amounts - std::vector> tokensMap; - for (auto iter = tokenBundle.bundle.begin(); iter != tokenBundle.bundle.end(); ++iter) { - tokensMap.push_back(make_pair( - Cbor::Encode::bytes(parse_hex(iter->second.policyId)), - Cbor::Encode::map({make_pair( - Cbor::Encode::bytes(data(iter->second.assetName)), - Cbor::Encode::uint(uint64_t(iter->second.amount)) // 64 bits - )}) - )); + // tokens: organized in two levels: by policyId and by assetName + const auto policyIds = tokenBundle.getPolicyIds(); + map tokensMap; + for (const auto& policy: policyIds) { + const auto& subTokens = tokenBundle.getByPolicyId(policy); + map subTokensMap; + for (const auto& token: subTokens) { + subTokensMap.emplace( + Cbor::Encode::bytes(data(token.assetName)), + Cbor::Encode::uint(uint64_t(token.amount)) // 64 bits + ); + } + tokensMap.emplace( + Cbor::Encode::bytes(parse_hex(policy)), + Cbor::Encode::map(subTokensMap) + ); } return Cbor::Encode::array({ Cbor::Encode::uint(amount), diff --git a/src/Cardano/Transaction.h b/src/Cardano/Transaction.h index 98e591c9cf6..1a090932a45 100644 --- a/src/Cardano/Transaction.h +++ b/src/Cardano/Transaction.h @@ -15,6 +15,7 @@ #include #include +#include namespace TW::Cardano { @@ -31,6 +32,7 @@ class TokenAmount { static TokenAmount fromProto(const Proto::TokenAmount& proto); Proto::TokenAmount toProto() const; + /// Key used in TokenBundle std::string key() const { return policyId + "_" + assetName; } }; @@ -47,6 +49,10 @@ class TokenBundle { void add(const TokenAmount& ta); uint256_t getAmount(const std::string& key) const; size_t size() const { return bundle.size(); } + /// Get the unique policyIds, can be the same number as the elements, or less (in case a policyId appears more than once, with different asset names). + std::unordered_set getPolicyIds() const; + /// Filter by policyIds + std::vector getByPolicyId(const std::string& policyId) const; // The minimum ADA amount needed for an ADA-only UTXO static const uint64_t MinUtxoValue; diff --git a/src/Cbor.cpp b/src/Cbor.cpp index 788d82e6c24..719c173ec83 100644 --- a/src/Cbor.cpp +++ b/src/Cbor.cpp @@ -52,15 +52,15 @@ Encode Encode::array(const vector& elems) { return e; } -Encode Encode::map(const vector>& elems) { - Encode e; +Encode Encode::map(const std::map& elems) { + Encode enc; auto n = elems.size(); - e.appendValue(Decode::MT_map, n); - for (auto i = 0ul; i < n; ++i) { - e.append(elems[i].first.encoded()); - e.append(elems[i].second.encoded()); + enc.appendValue(Decode::MT_map, n); + for (const auto& e: elems) { + enc.append(e.first.encoded()); + enc.append(e.second.encoded()); } - return e; + return enc; } Encode Encode::tag(uint64_t value, const Encode& elem) { diff --git a/src/Cbor.h b/src/Cbor.h index 6b9aa3950c7..06ab9f3feca 100644 --- a/src/Cbor.h +++ b/src/Cbor.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include namespace TW::Cbor { @@ -38,7 +40,7 @@ class Encode { /// encode an array of elements (of different types) static Encode array(const std::vector& elems); /// encode a map - static Encode map(const std::vector>& elems); + static Encode map(const std::map& elems); /// encode a tag and following element static Encode tag(uint64_t value, const Encode& elem); /// encode a null value (special) @@ -54,6 +56,7 @@ class Encode { /// Create from raw content, must be valid CBOR data, may throw static Encode fromRaw(const TW::Data& rawData); + const Data& getDataInternal() const { return _data; } private: Encode() {} @@ -70,6 +73,11 @@ class Encode { int openIndefCount = 0; }; +/// Comparator, needed for map keys +inline bool operator<(const Encode& lhs, const Encode& rhs) { + return lhs.getDataInternal() < rhs.getDataInternal(); +} + /// CBOR Decoder and container for data for decoding. Contains reference to read-only CBOR data. /// See CborTests.cpp for usage. class Decode { diff --git a/swift/Tests/Blockchains/CardanoTests.swift b/swift/Tests/Blockchains/CardanoTests.swift index 9a99cb186dd..4a2b6103949 100644 --- a/swift/Tests/Blockchains/CardanoTests.swift +++ b/swift/Tests/Blockchains/CardanoTests.swift @@ -127,9 +127,9 @@ class CardanoTests: XCTestCase { let encoded = output.encoded XCTAssertEqual(encoded.hexString, - "83a40082825820f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76701825820f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76702018282583901558dd902616f5cd01edcc62870cb4748c45403f1228218bee5b628b526f0ca9e7a2c04d548fbd6ce86f358be139fe680652536437d1d6fd5821a00160a5ba1581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a14653554e4441451a01312d00825839018d98bea0414243dc84070f96265577e7e6cf702d62e871016885034ecc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468821a0080a574a2581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a144435542591a004c4b40581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a14653554e4441451a03a2bbd9021a0002af5e031a032dcd55a100818258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df290584000feb412442f8851faa59742eb2c37f3994b0d143a424367143490cf828246991e504fa8eac61c403bfa7634bd1f0adc44f3f54f6a474856701e2cbb15fb5b04f6") + "83a40082825820f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76701825820f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76702018282583901558dd902616f5cd01edcc62870cb4748c45403f1228218bee5b628b526f0ca9e7a2c04d548fbd6ce86f358be139fe680652536437d1d6fd5821a00160a5ba1581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a14653554e4441451a01312d00825839018d98bea0414243dc84070f96265577e7e6cf702d62e871016885034ecc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468821a0080aac9a1581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a244435542591a004c4b404653554e4441451a03a2bbd9021a0002aa09031a032dcd55a100818258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df2905840d90dcfbd190cbe59c42094e59eeb49b3de9d80a85b786cc311f932c5c9302d1c8c6c577b22aa70ff7955c139c700ea918f8cb425c3ba43a27980e1d238e4e908f6") let txid = output.txID - XCTAssertEqual(txid.hexString, "dacb3a0c5b3b7fa36b49f25a0a59b941ab8a21f0db5770e9e6982ff120122649") + XCTAssertEqual(txid.hexString, "201c537693b005b64a0f0528e366ec67a84be0119ed4363b547f141f2a7770c2") } } diff --git a/swift/Tests/Blockchains/OasisTests.swift b/swift/Tests/Blockchains/OasisTests.swift index fc9f4df1bd7..03ad91930f7 100644 --- a/swift/Tests/Blockchains/OasisTests.swift +++ b/swift/Tests/Blockchains/OasisTests.swift @@ -36,6 +36,6 @@ class OasisTests: XCTestCase { let output: OasisSigningOutput = AnySigner.sign(input: input, coin: .oasis) - XCTAssertEqual(output.encoded.hexString, "a273756e747275737465645f7261775f76616c7565585ea4656e6f6e636500666d6574686f64707374616b696e672e5472616e7366657263666565a2636761730066616d6f756e74410064626f6479a262746f5500c73cc001463434915ba3f39751beb7c0905b45eb66616d6f756e744400989680697369676e6174757265a26a7075626c69635f6b6579582093d8f8a455f50527976a8aa87ebde38d5606efa86cb985d3fb466aff37000e3b697369676e61747572655840e331ce731ed819106586152b13cd98ecf3248a880bdc71174ee3d83f6d5f3f8ee8fc34c19b22032f2f1e3e06d382720125d7a517fba9295c813228cc2b63170b") + XCTAssertEqual(output.encoded.hexString, "a2697369676e6174757265a2697369676e617475726558406e51c18c9b2015c9b49414b3307336597f51ff331873d214ce2db81c9651a34d99529ccaa294a39ccd01c6b0bc2c2239d87c624e5ba4840cf99ac8f9283e240c6a7075626c69635f6b6579582093d8f8a455f50527976a8aa87ebde38d5606efa86cb985d3fb466aff37000e3b73756e747275737465645f7261775f76616c7565585ea463666565a2636761730066616d6f756e74410064626f6479a262746f5500c73cc001463434915ba3f39751beb7c0905b45eb66616d6f756e744400989680656e6f6e636500666d6574686f64707374616b696e672e5472616e73666572") } } diff --git a/tests/Cardano/SigningTests.cpp b/tests/Cardano/SigningTests.cpp index aec7cba248d..d731747b081 100644 --- a/tests/Cardano/SigningTests.cpp +++ b/tests/Cardano/SigningTests.cpp @@ -538,8 +538,8 @@ TEST(CardanoSigning, SignTransferToken) { EXPECT_EQ(plan.availableAmount, 10051373ul); EXPECT_EQ(plan.amount, 1444443ul); - EXPECT_EQ(plan.fee, 175966ul); - EXPECT_EQ(plan.change, 8430964ul); + EXPECT_EQ(plan.fee, 174601ul); + EXPECT_EQ(plan.change, 8432329ul); EXPECT_EQ(plan.utxos.size(), 2ul); EXPECT_EQ(plan.availableTokens.size(), 2ul); EXPECT_EQ(plan.availableTokens.getAmount("9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77_CUBY"), 5000000); @@ -557,16 +557,16 @@ TEST(CardanoSigning, SignTransferToken) { EXPECT_EQ(output.error(), Common::Proto::OK); const auto encoded = data(output.encoded()); - EXPECT_EQ(hex(encoded), "83a40082825820f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76701825820f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76702018282583901558dd902616f5cd01edcc62870cb4748c45403f1228218bee5b628b526f0ca9e7a2c04d548fbd6ce86f358be139fe680652536437d1d6fd5821a00160a5ba1581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a14653554e4441451a01312d00825839018d98bea0414243dc84070f96265577e7e6cf702d62e871016885034ecc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468821a0080a574a2581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a144435542591a004c4b40581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a14653554e4441451a03a2bbd9021a0002af5e031a032dcd55a100818258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df290584000feb412442f8851faa59742eb2c37f3994b0d143a424367143490cf828246991e504fa8eac61c403bfa7634bd1f0adc44f3f54f6a474856701e2cbb15fb5b04f6"); + EXPECT_EQ(hex(encoded), "83a40082825820f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76701825820f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e76702018282583901558dd902616f5cd01edcc62870cb4748c45403f1228218bee5b628b526f0ca9e7a2c04d548fbd6ce86f358be139fe680652536437d1d6fd5821a00160a5ba1581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a14653554e4441451a01312d00825839018d98bea0414243dc84070f96265577e7e6cf702d62e871016885034ecc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468821a0080aac9a1581c9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77a244435542591a004c4b404653554e4441451a03a2bbd9021a0002aa09031a032dcd55a100818258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df2905840d90dcfbd190cbe59c42094e59eeb49b3de9d80a85b786cc311f932c5c9302d1c8c6c577b22aa70ff7955c139c700ea918f8cb425c3ba43a27980e1d238e4e908f6"); const auto txid = data(output.tx_id()); - EXPECT_EQ(hex(txid), "dacb3a0c5b3b7fa36b49f25a0a59b941ab8a21f0db5770e9e6982ff120122649"); + EXPECT_EQ(hex(txid), "201c537693b005b64a0f0528e366ec67a84be0119ed4363b547f141f2a7770c2"); { // also test proto toProto / fromProto const Proto::TransactionPlan planProto = Signer::plan(input); const auto plan2 = TransactionPlan::fromProto(planProto); EXPECT_EQ(plan2.amount, 1444443ul); - EXPECT_EQ(plan2.change, 8430964ul); + EXPECT_EQ(plan2.change, 8432329ul); } } diff --git a/tests/Cardano/TransactionTests.cpp b/tests/Cardano/TransactionTests.cpp index 7f43daf0660..eaedb19f822 100644 --- a/tests/Cardano/TransactionTests.cpp +++ b/tests/Cardano/TransactionTests.cpp @@ -96,6 +96,22 @@ TEST(CardanoTransaction, minAdaAmount) { EXPECT_EQ(TokenBundle::minAdaAmountHelper(60, 60, 60*32), 21222201ul); // 60 policyId, 60 32-char asset names } +TEST(CardanoTransaction, getPolicyIDs) { + const auto policyId1 = "012345678901234567890POLICY1"; + const auto policyId2 = "012345678901234567890POLICY2"; + const auto tb = TokenBundle({ + TokenAmount(policyId1, "TOK1", 10), + TokenAmount(policyId2, "TOK2", 20), + TokenAmount(policyId2, "TOK3", 30), // duplicate policyId + }); + ASSERT_EQ(tb.getPolicyIds().size(), 2ul); + EXPECT_TRUE(tb.getPolicyIds().contains(policyId1)); + EXPECT_TRUE(tb.getPolicyIds().contains(policyId2)); + + EXPECT_EQ(tb.getByPolicyId(policyId1).size(), 1ul); + EXPECT_EQ(tb.getByPolicyId(policyId2).size(), 2ul); +} + TEST(TWCardanoTransaction, minAdaAmount) { { // ADA-only const auto bundleProto = TokenBundle().toProto(); diff --git a/tests/Oasis/SignerTests.cpp b/tests/Oasis/SignerTests.cpp index 2cf9ba958a4..b4cc6ee2a6b 100644 --- a/tests/Oasis/SignerTests.cpp +++ b/tests/Oasis/SignerTests.cpp @@ -34,7 +34,7 @@ TEST(OasisSigner, Sign) { Proto::SigningOutput output = Signer::sign(input); - ASSERT_EQ(hex(output.encoded()), "a273756e747275737465645f7261775f76616c7565585ea4656e6f6e636500666d6574686f64707374616b696e672e5472616e7366657263666565a2636761730066616d6f756e74410064626f6479a262746f5500c73cc001463434915ba3f39751beb7c0905b45eb66616d6f756e744400989680697369676e6174757265a26a7075626c69635f6b6579582093d8f8a455f50527976a8aa87ebde38d5606efa86cb985d3fb466aff37000e3b697369676e61747572655840e331ce731ed819106586152b13cd98ecf3248a880bdc71174ee3d83f6d5f3f8ee8fc34c19b22032f2f1e3e06d382720125d7a517fba9295c813228cc2b63170b"); + ASSERT_EQ(hex(output.encoded()), "a2697369676e6174757265a2697369676e617475726558406e51c18c9b2015c9b49414b3307336597f51ff331873d214ce2db81c9651a34d99529ccaa294a39ccd01c6b0bc2c2239d87c624e5ba4840cf99ac8f9283e240c6a7075626c69635f6b6579582093d8f8a455f50527976a8aa87ebde38d5606efa86cb985d3fb466aff37000e3b73756e747275737465645f7261775f76616c7565585ea463666565a2636761730066616d6f756e74410064626f6479a262746f5500c73cc001463434915ba3f39751beb7c0905b45eb66616d6f756e744400989680656e6f6e636500666d6574686f64707374616b696e672e5472616e73666572"); } } // namespace TW::Oasis::tests diff --git a/tests/Oasis/TWAnySignerTests.cpp b/tests/Oasis/TWAnySignerTests.cpp index 0cae4b34bcd..c76d46256e1 100644 --- a/tests/Oasis/TWAnySignerTests.cpp +++ b/tests/Oasis/TWAnySignerTests.cpp @@ -32,6 +32,6 @@ TEST(TWAnySignerOasis, Sign) { ANY_SIGN(input, TWCoinTypeOasis); - EXPECT_EQ("a273756e747275737465645f7261775f76616c7565585ea4656e6f6e636500666d6574686f64707374616b696e672e5472616e7366657263666565a2636761730066616d6f756e74410064626f6479a262746f5500c73cc001463434915ba3f39751beb7c0905b45eb66616d6f756e744400989680697369676e6174757265a26a7075626c69635f6b6579582093d8f8a455f50527976a8aa87ebde38d5606efa86cb985d3fb466aff37000e3b697369676e61747572655840e331ce731ed819106586152b13cd98ecf3248a880bdc71174ee3d83f6d5f3f8ee8fc34c19b22032f2f1e3e06d382720125d7a517fba9295c813228cc2b63170b", + EXPECT_EQ("a2697369676e6174757265a2697369676e617475726558406e51c18c9b2015c9b49414b3307336597f51ff331873d214ce2db81c9651a34d99529ccaa294a39ccd01c6b0bc2c2239d87c624e5ba4840cf99ac8f9283e240c6a7075626c69635f6b6579582093d8f8a455f50527976a8aa87ebde38d5606efa86cb985d3fb466aff37000e3b73756e747275737465645f7261775f76616c7565585ea463666565a2636761730066616d6f756e74410064626f6479a262746f5500c73cc001463434915ba3f39751beb7c0905b45eb66616d6f756e744400989680656e6f6e636500666d6574686f64707374616b696e672e5472616e73666572", hex(output.encoded())); } From 2e85869951262607f7e929e38dc289c2c37351fd Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Wed, 10 Aug 2022 16:27:44 +0100 Subject: [PATCH 054/497] [Codegen] Support generating coin test by id (#2485) * [Codegen] Support generating coin test by id Also, disable overwriting existing tests by default. Adds 2 cmd options: --coin-id and --no-skip-existing * [Codegen] Minor fixes --- codegen/bin/cointests | 25 +++++++++++++++++++++++-- codegen/bin/newcoin | 2 +- codegen/lib/coin_test_gen.rb | 8 +++++--- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/codegen/bin/cointests b/codegen/bin/cointests index b30fc1e91af..9c223fedf73 100755 --- a/codegen/bin/cointests +++ b/codegen/bin/cointests @@ -2,12 +2,20 @@ # Sript for creating/updating CoinType unit tests, based on the registry.json file # It is intended as a one-time or occasional generation, not every time! (that way the tests would have zero added value) -# Usage: codegen/bin/cointests +# Usage: codegen/bin/cointests [--coin-id coinid] [--no-skip-existing] # Files are generated to: tests//TWCoinTypeTests.cpp require 'erb' require 'fileutils' require 'json' +require 'optparse' + +options = { :no_skip_existing => false } +OptionParser.new do |opt| + opt.banner = "Usage: codegen/bin/cointests [options]" + opt.on('--coin-id ') { |o| options[:coin_id] = o.downcase } + opt.on('--no-skip-existing') { options[:no_skip_existing] = true } +end.parse! CurrentDir = File.dirname(__FILE__) $LOAD_PATH.unshift(File.join(CurrentDir, '..', 'lib')) @@ -68,6 +76,19 @@ erbs = [ coin_test_gen = CoinTestGen.new() templateFile = 'TWCoinTypeTests.cpp.erb' +foundCoinId = false coins.each do |coin| - coin_test_gen.generate_coin_test_file(coin, templateFile) + if options[:coin_id].nil? or coin['id'] == options[:coin_id] + coin_test_gen.generate_coin_test_file(coin, templateFile, options[:no_skip_existing]) + foundCoinId = true + end end + +if not options[:coin_id].nil? and not foundCoinId + puts "Not found specified coin-id " + options[:coin_id] + supportedIds = [] + coins.each do |coin| + supportedIds << coin['id'] + end + puts "Supported coin-ids: " + supportedIds.join(", ") +end diff --git a/codegen/bin/newcoin b/codegen/bin/newcoin index e88e688cf35..40d67e0bc26 100755 --- a/codegen/bin/newcoin +++ b/codegen/bin/newcoin @@ -142,6 +142,6 @@ generate_file("newcoin/AddressTests.kt.erb", "android/app/src/androidTest/java/c generate_file("newcoin/SignerTests.kt.erb", "android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/#{format_name_lowercase(coin)}", "Test#{name}Signer.kt", coin) generate_file("newcoin/Tests.swift.erb", "swift/Tests/Blockchains", "#{name}Tests.swift", coin) -coin_test_gen.generate_coin_test_file(coin, 'TWCoinTypeTests.cpp.erb') +coin_test_gen.generate_coin_test_file(coin, 'TWCoinTypeTests.cpp.erb', true) puts "please tools/generate-files to generate Swift/Java/Protobuf files" diff --git a/codegen/lib/coin_test_gen.rb b/codegen/lib/coin_test_gen.rb index 2583e549a1b..58c7d6955d7 100755 --- a/codegen/lib/coin_test_gen.rb +++ b/codegen/lib/coin_test_gen.rb @@ -56,7 +56,7 @@ def explorer_sample_account(c) end end - def generate_coin_test_file(coin, templateFile) + def generate_coin_test_file(coin, templateFile, overwriteExisting = true) path = File.expand_path(templateFile, File.join(File.dirname(__FILE__), '..', 'lib', 'templates')) template = ERB.new(File.read(path), nil, '-') result = template.result(binding) @@ -65,7 +65,9 @@ def generate_coin_test_file(coin, templateFile) file = 'TWCoinTypeTests.cpp' FileUtils.mkdir_p folder path = File.join(folder, file) - File.write(path, result) - puts "Generated file " + path + if not File.exist?(path) or overwriteExisting + File.write(path, result) + puts "Generated file " + path + end end end From f9dd6f69398b006170fa35eb2538f6c723409d9f Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 16 Aug 2022 15:53:54 +0900 Subject: [PATCH 055/497] [Test] More namespace fixes for unity build (#2497) * More namespace fixes for unity build * feat(unity_build): fix more namespace in src interface (#2501) * Moving tests into namespace Co-authored-by: Sztergbaum Roman --- src/Nimiq/Signer.cpp | 5 +- src/Polkadot/Signer.cpp | 5 +- src/Stellar/Entry.cpp | 9 +- src/Tezos/Address.cpp | 11 +- src/Tezos/BinaryCoding.cpp | 4 +- src/Tezos/BinaryCoding.h | 4 +- src/Tezos/Entry.cpp | 11 +- src/Theta/Signer.cpp | 8 +- src/Tron/Address.cpp | 4 +- src/VeChain/Entry.cpp | 7 +- src/Waves/Address.cpp | 5 +- src/Waves/Entry.cpp | 1 - src/Zcash/Entry.cpp | 10 +- src/Zcash/Signer.cpp | 5 +- src/interface/TWBitcoinAddress.cpp | 14 +- src/interface/TWBitcoinScript.cpp | 14 +- src/interface/TWCardano.cpp | 5 +- src/interface/TWEthereumAbi.cpp | 14 +- src/interface/TWEthereumAbiFunction.cpp | 195 +++++++++--------- src/interface/TWEthereumAbiValue.cpp | 20 +- src/interface/TWFIOAccount.cpp | 9 +- src/interface/TWNEARAccount.cpp | 7 +- src/interface/TWRippleXAddress.cpp | 7 +- src/interface/TWSegwitAddress.cpp | 7 +- src/interface/TWStoredKey.cpp | 14 +- tests/Harmony/TWHarmonyStakingTests.cpp | 15 +- tests/Nimiq/TWAnySignerTests.cpp | 5 +- tests/Oasis/TWAnySignerTests.cpp | 5 +- tests/Ontology/AccountTests.cpp | 6 +- tests/Ripple/TransactionTests.cpp | 6 +- tests/Solana/SignerTests.cpp | 8 +- tests/Terra/SignerTests.cpp | 4 +- tests/Tezos/OperationListTests.cpp | 71 +++---- tests/Tezos/TWAnySignerTests.cpp | 4 +- tests/Waves/SignerTests.cpp | 5 +- tests/operators/equality_comparable_tests.cpp | 4 +- 36 files changed, 274 insertions(+), 254 deletions(-) diff --git a/src/Nimiq/Signer.cpp b/src/Nimiq/Signer.cpp index 2d3201e2892..5433b88aa86 100644 --- a/src/Nimiq/Signer.cpp +++ b/src/Nimiq/Signer.cpp @@ -9,8 +9,7 @@ #include -using namespace TW; -using namespace TW::Nimiq; +namespace TW::Nimiq { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); @@ -39,3 +38,5 @@ void Signer::sign(const PrivateKey& privateKey, Transaction& transaction) const auto signature = privateKey.sign(preImage, TWCurveED25519); std::copy(signature.begin(), signature.end(), transaction.signature.begin()); } + +} // namespace TW::Nimiq diff --git a/src/Polkadot/Signer.cpp b/src/Polkadot/Signer.cpp index c7f708adcc7..b5f083a522b 100644 --- a/src/Polkadot/Signer.cpp +++ b/src/Polkadot/Signer.cpp @@ -9,8 +9,7 @@ #include "../Hash.h" #include "../PrivateKey.h" -using namespace TW; -using namespace TW::Polkadot; +namespace TW::Polkadot { static constexpr size_t hashTreshold = 256; @@ -30,3 +29,5 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { protoOutput.set_encoded(encoded.data(), encoded.size()); return protoOutput; } + +} // namespace TW::Polkadot diff --git a/src/Stellar/Entry.cpp b/src/Stellar/Entry.cpp index 87730c3cf18..a2412dcb5dd 100644 --- a/src/Stellar/Entry.cpp +++ b/src/Stellar/Entry.cpp @@ -9,19 +9,20 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Stellar; -using namespace std; +namespace TW::Stellar { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Stellar diff --git a/src/Tezos/Address.cpp b/src/Tezos/Address.cpp index 046bab28ce6..62caf255523 100644 --- a/src/Tezos/Address.cpp +++ b/src/Tezos/Address.cpp @@ -15,13 +15,12 @@ #include -using namespace TW; -using namespace TW::Tezos; +namespace TW::Tezos { /// Address prefixes. -const std::array tz1Prefix{6, 161, 159}; -const std::array tz2Prefix{6, 161, 161}; -const std::array tz3Prefix{6, 161, 164}; +const std::array tz1Prefix{6, 161, 159}; +const std::array tz2Prefix{6, 161, 161}; +const std::array tz3Prefix{6, 161, 164}; bool Address::isValid(const std::string& string) { const auto decoded = Base58::bitcoin.decodeCheck(string); @@ -67,3 +66,5 @@ Data Address::forge() const { std::string s = string(); return forgePublicKeyHash(s); } + +} // namespace TW::Tezos diff --git a/src/Tezos/BinaryCoding.cpp b/src/Tezos/BinaryCoding.cpp index a6824af9994..b00b8c3bd6e 100644 --- a/src/Tezos/BinaryCoding.cpp +++ b/src/Tezos/BinaryCoding.cpp @@ -13,7 +13,7 @@ #include #include -using namespace TW; +namespace TW::Tezos { std::string base58ToHex(const std::string& string, size_t prefixLength) { const auto decoded = Base58::bitcoin.decodeCheck(string); @@ -48,3 +48,5 @@ PrivateKey parsePrivateKey(const std::string& privateKey) { append(pk, Data(decoded.begin() + prefix_size, decoded.end())); return PrivateKey(pk); } + +} // namespace TW::Tezos diff --git a/src/Tezos/BinaryCoding.h b/src/Tezos/BinaryCoding.h index eb570166302..736f28edbbc 100644 --- a/src/Tezos/BinaryCoding.h +++ b/src/Tezos/BinaryCoding.h @@ -12,8 +12,10 @@ #include -using namespace TW; +namespace TW::Tezos { PublicKey parsePublicKey(const std::string& publicKey); PrivateKey parsePrivateKey(const std::string& privateKey); std::string base58ToHex(const std::string& data, size_t prefixLength); + +} // namespace TW::Tezos diff --git a/src/Tezos/Entry.cpp b/src/Tezos/Entry.cpp index 48b0568247c..1006c26b5c2 100644 --- a/src/Tezos/Entry.cpp +++ b/src/Tezos/Entry.cpp @@ -9,16 +9,15 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Tezos; -using namespace std; +namespace TW::Tezos { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } @@ -26,6 +25,8 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D signTemplate(dataIn, dataOut); } -string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { +std::string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } + +} // namespace TW::Tezos diff --git a/src/Theta/Signer.cpp b/src/Theta/Signer.cpp index e2bc16b1188..c50c74f264e 100755 --- a/src/Theta/Signer.cpp +++ b/src/Theta/Signer.cpp @@ -9,9 +9,9 @@ #include "../Ethereum/RLP.h" #include "../Hash.h" -using namespace TW; -using namespace TW::Theta; -using RLP = Ethereum::RLP; +using RLP = TW::Ethereum::RLP; + +namespace TW::Theta { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto pkFrom = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); @@ -66,3 +66,5 @@ Data Signer::sign(const PrivateKey& privateKey, const Transaction& transaction) auto signature = privateKey.sign(hash, TWCurveSECP256k1); return signature; } + +} // namespace TW::Theta diff --git a/src/Tron/Address.cpp b/src/Tron/Address.cpp index 7fdac65b817..a67ea8fd1c2 100644 --- a/src/Tron/Address.cpp +++ b/src/Tron/Address.cpp @@ -12,7 +12,7 @@ #include #include -using namespace TW::Tron; +namespace TW::Tron { bool Address::isValid(const std::string& string) { const auto decoded = Base58::bitcoin.decodeCheck(string); @@ -36,3 +36,5 @@ Address::Address(const PublicKey& publicKey) { bytes[0] = prefix; std::copy(keyhash.end() - size + 1, keyhash.end(), bytes.begin() + 1); } + +} // namespace TW::Tron diff --git a/src/VeChain/Entry.cpp b/src/VeChain/Entry.cpp index c3c30c7f0ea..0a01f790321 100644 --- a/src/VeChain/Entry.cpp +++ b/src/VeChain/Entry.cpp @@ -9,9 +9,10 @@ #include "Ethereum/Address.h" #include "Signer.h" -using namespace TW::VeChain; -using namespace std; - +namespace TW::VeChain { + void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::VeChain diff --git a/src/Waves/Address.cpp b/src/Waves/Address.cpp index f95c9de7c58..2e8ce6f05bc 100644 --- a/src/Waves/Address.cpp +++ b/src/Waves/Address.cpp @@ -15,8 +15,7 @@ #include #include -using namespace TW; -using namespace TW::Waves; +namespace TW::Waves { template Data Address::secureHash(const T &data) { @@ -82,3 +81,5 @@ Address::Address(const PublicKey &publicKey) { std::string Address::string() const { return Base58::bitcoin.encode(bytes); } + +} // namespace TW::Waves diff --git a/src/Waves/Entry.cpp b/src/Waves/Entry.cpp index 1886c93248b..9635e2d30cd 100644 --- a/src/Waves/Entry.cpp +++ b/src/Waves/Entry.cpp @@ -9,7 +9,6 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Waves; using namespace std; namespace TW::Waves { diff --git a/src/Zcash/Entry.cpp b/src/Zcash/Entry.cpp index 9d5e39a1ca8..ff5f1ac21ce 100644 --- a/src/Zcash/Entry.cpp +++ b/src/Zcash/Entry.cpp @@ -9,15 +9,13 @@ #include "Signer.h" #include "TAddress.h" -using namespace TW::Zcash; -using namespace TW; -using namespace std; +namespace TW::Zcash { -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const string& address, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] TW::byte p2sh, [[maybe_unused]] const char* hrp) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const std::string& address, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] TW::byte p2sh, [[maybe_unused]] const char* hrp) const { return TAddress::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, [[maybe_unused]] const char* hrp) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, [[maybe_unused]] const char* hrp) const { return TAddress(publicKey, p2pkh).string(); } @@ -33,3 +31,5 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D void Entry::plan([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { planTemplate(dataIn, dataOut); } + +} // namespace TW::Zcash diff --git a/src/Zcash/Signer.cpp b/src/Zcash/Signer.cpp index 9387f58a8b7..37db9183ee8 100644 --- a/src/Zcash/Signer.cpp +++ b/src/Zcash/Signer.cpp @@ -11,8 +11,7 @@ #include "Transaction.h" #include "TransactionBuilder.h" -using namespace TW; -using namespace TW::Zcash; +namespace TW::Zcash { TransactionPlan Signer::plan(const SigningInput& input) noexcept { auto plan = Bitcoin::TransactionSigner::plan(input); @@ -38,3 +37,5 @@ SigningOutput Signer::sign(const SigningInput& input) noexcept { } return output; } + +} // namespace TW::Zcash diff --git a/src/interface/TWBitcoinAddress.cpp b/src/interface/TWBitcoinAddress.cpp index 8df8de2a37f..cefd940e992 100644 --- a/src/interface/TWBitcoinAddress.cpp +++ b/src/interface/TWBitcoinAddress.cpp @@ -13,25 +13,23 @@ #include -using namespace TW::Bitcoin; - bool TWBitcoinAddressEqual(struct TWBitcoinAddress *_Nonnull lhs, struct TWBitcoinAddress *_Nonnull rhs) { return lhs->impl == rhs->impl; } bool TWBitcoinAddressIsValid(TWData *_Nonnull data) { - return TWDataSize(data) == Address::size; + return TWDataSize(data) == TW::Bitcoin::Address::size; } bool TWBitcoinAddressIsValidString(TWString *_Nonnull string) { auto& s = *reinterpret_cast(string); - return Address::isValid(s); + return TW::Bitcoin::Address::isValid(s); } struct TWBitcoinAddress *_Nullable TWBitcoinAddressCreateWithString(TWString *_Nonnull string) { auto& s = *reinterpret_cast(string); try { - return new TWBitcoinAddress{ Address(s) }; + return new TWBitcoinAddress{ TW::Bitcoin::Address(s) }; } catch (...) { return nullptr; } @@ -40,7 +38,7 @@ struct TWBitcoinAddress *_Nullable TWBitcoinAddressCreateWithString(TWString *_N struct TWBitcoinAddress *_Nullable TWBitcoinAddressCreateWithData(TWData *_Nonnull data) { const auto& d = *reinterpret_cast(data); try { - return new TWBitcoinAddress{ Address(d) }; + return new TWBitcoinAddress{ TW::Bitcoin::Address(d) }; } catch (...) { return nullptr; } @@ -48,7 +46,7 @@ struct TWBitcoinAddress *_Nullable TWBitcoinAddressCreateWithData(TWData *_Nonnu struct TWBitcoinAddress *_Nullable TWBitcoinAddressCreateWithPublicKey(struct TWPublicKey *_Nonnull publicKey, uint8_t prefix) { try { - return new TWBitcoinAddress{ Address(publicKey->impl, prefix) }; + return new TWBitcoinAddress{ TW::Bitcoin::Address(publicKey->impl, prefix) }; } catch (...) { return nullptr; } @@ -67,5 +65,5 @@ uint8_t TWBitcoinAddressPrefix(struct TWBitcoinAddress *_Nonnull address) { } TWData *_Nonnull TWBitcoinAddressKeyhash(struct TWBitcoinAddress *_Nonnull address) { - return TWDataCreateWithBytes(address->impl.bytes.data() + 1, Address::size - 1); + return TWDataCreateWithBytes(address->impl.bytes.data() + 1, TW::Bitcoin::Address::size - 1); } diff --git a/src/interface/TWBitcoinScript.cpp b/src/interface/TWBitcoinScript.cpp index f17cbf01bed..fb0fb321147 100644 --- a/src/interface/TWBitcoinScript.cpp +++ b/src/interface/TWBitcoinScript.cpp @@ -11,8 +11,6 @@ #include -using namespace TW::Bitcoin; - struct TWBitcoinScript *_Nonnull TWBitcoinScriptCreate() { auto* script = new TWBitcoinScript{}; return script; @@ -122,37 +120,37 @@ TWData *TWBitcoinScriptEncode(const struct TWBitcoinScript *script) { struct TWBitcoinScript *TWBitcoinScriptBuildPayToPublicKey(TWData *pubkey) { auto* v = reinterpret_cast*>(pubkey); - auto script = Script::buildPayToPublicKey(*v); + auto script = TW::Bitcoin::Script::buildPayToPublicKey(*v); return new TWBitcoinScript{ .impl = script }; } struct TWBitcoinScript *TWBitcoinScriptBuildPayToPublicKeyHash(TWData *hash) { auto* v = reinterpret_cast*>(hash); - auto script = Script::buildPayToPublicKeyHash(*v); + auto script = TW::Bitcoin::Script::buildPayToPublicKeyHash(*v); return new TWBitcoinScript{ .impl = script }; } struct TWBitcoinScript *TWBitcoinScriptBuildPayToScriptHash(TWData *scriptHash) { auto* v = reinterpret_cast*>(scriptHash); - auto script = Script::buildPayToScriptHash(*v); + auto script = TW::Bitcoin::Script::buildPayToScriptHash(*v); return new TWBitcoinScript{ .impl = script }; } struct TWBitcoinScript *TWBitcoinScriptBuildPayToWitnessPubkeyHash(TWData *hash) { auto* v = reinterpret_cast*>(hash); - auto script = Script::buildPayToWitnessPublicKeyHash(*v); + auto script = TW::Bitcoin::Script::buildPayToWitnessPublicKeyHash(*v); return new TWBitcoinScript{ .impl = script }; } struct TWBitcoinScript *TWBitcoinScriptBuildPayToWitnessScriptHash(TWData *scriptHash) { auto* v = reinterpret_cast*>(scriptHash); - auto script = Script::buildPayToWitnessScriptHash(*v); + auto script = TW::Bitcoin::Script::buildPayToWitnessScriptHash(*v); return new TWBitcoinScript{ .impl = script }; } struct TWBitcoinScript *_Nonnull TWBitcoinScriptLockScriptForAddress(TWString *_Nonnull address, enum TWCoinType coin) { auto* s = reinterpret_cast(address); - auto script = Script::lockScriptForAddress(*s, coin); + auto script = TW::Bitcoin::Script::lockScriptForAddress(*s, coin); return new TWBitcoinScript{ .impl = script }; } diff --git a/src/interface/TWCardano.cpp b/src/interface/TWCardano.cpp index abe0e869be0..07ed706207a 100644 --- a/src/interface/TWCardano.cpp +++ b/src/interface/TWCardano.cpp @@ -9,14 +9,13 @@ #include "Cardano/Transaction.h" #include "proto/Cardano.pb.h" -using namespace TW::Cardano; using namespace TW; uint64_t TWCardanoMinAdaAmount(TWData *_Nonnull tokenBundle) { const Data* bundleData = static_cast(tokenBundle); - Proto::TokenBundle bundleProto; + TW::Cardano::Proto::TokenBundle bundleProto; if (bundleData && bundleProto.ParseFromArray(bundleData->data(), (int)bundleData->size())) { - return TokenBundle::fromProto(bundleProto).minAdaAmount(); + return TW::Cardano::TokenBundle::fromProto(bundleProto).minAdaAmount(); } return 0; } diff --git a/src/interface/TWEthereumAbi.cpp b/src/interface/TWEthereumAbi.cpp index 513d243df14..2ea781199eb 100644 --- a/src/interface/TWEthereumAbi.cpp +++ b/src/interface/TWEthereumAbi.cpp @@ -17,14 +17,12 @@ #include #include -using namespace TW::Ethereum::ABI; -using namespace TW::Ethereum; using namespace TW; - +namespace EthAbi = TW::Ethereum::ABI; TWData* _Nonnull TWEthereumAbiEncode(struct TWEthereumAbiFunction* _Nonnull func_in) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; Data encoded; function.encode(encoded); @@ -34,7 +32,7 @@ TWData* _Nonnull TWEthereumAbiEncode(struct TWEthereumAbiFunction* _Nonnull func bool TWEthereumAbiDecodeOutput(struct TWEthereumAbiFunction* _Nonnull func_in, TWData* _Nonnull encoded) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; assert(encoded != nullptr); Data encData = data(TWDataBytes(encoded), TWDataSize(encoded)); @@ -45,9 +43,9 @@ bool TWEthereumAbiDecodeOutput(struct TWEthereumAbiFunction* _Nonnull func_in, TWString* _Nullable TWEthereumAbiDecodeCall(TWData* _Nonnull callData, TWString* _Nonnull abiString) { const Data& call = *(reinterpret_cast(callData)); const auto& jsonString = *reinterpret_cast(abiString); - try { + try { auto abi = nlohmann::json::parse(jsonString); - auto string = decodeCall(call, abi); + auto string = EthAbi::decodeCall(call, abi); if (!string.has_value()) { return nullptr; } @@ -61,7 +59,7 @@ TWString* _Nullable TWEthereumAbiDecodeCall(TWData* _Nonnull callData, TWString* TWData* _Nonnull TWEthereumAbiEncodeTyped(TWString* _Nonnull messageJson) { Data data; try { - data = ParamStruct::hashStructJson(TWStringUTF8Bytes(messageJson)); + data = EthAbi::ParamStruct::hashStructJson(TWStringUTF8Bytes(messageJson)); } catch (...) {} // return empty return TWDataCreateWithBytes(data.data(), data.size()); } diff --git a/src/interface/TWEthereumAbiFunction.cpp b/src/interface/TWEthereumAbiFunction.cpp index 93b451c2a51..3951b949f5b 100644 --- a/src/interface/TWEthereumAbiFunction.cpp +++ b/src/interface/TWEthereumAbiFunction.cpp @@ -16,11 +16,10 @@ #include using namespace TW; -using namespace TW::Ethereum; -using namespace TW::Ethereum::ABI; +namespace EthAbi = TW::Ethereum::ABI; struct TWEthereumAbiFunction *_Nonnull TWEthereumAbiFunctionCreateWithString(TWString *_Nonnull name) { - auto func = Function(TWStringUTF8Bytes(name)); + auto func = EthAbi::Function(TWStringUTF8Bytes(name)); return new TWEthereumAbiFunction{ func }; } @@ -40,173 +39,173 @@ TWString *_Nonnull TWEthereumAbiFunctionGetType(struct TWEthereumAbiFunction *_N int TWEthereumAbiFunctionAddParamUInt8(struct TWEthereumAbiFunction *_Nonnull func_in, uint8_t val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - auto param = std::make_shared(val); + auto param = std::make_shared(val); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamUInt16(struct TWEthereumAbiFunction *_Nonnull func_in, uint16_t val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - auto param = std::make_shared(val); + auto param = std::make_shared(val); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamUInt32(struct TWEthereumAbiFunction *_Nonnull func_in, uint32_t val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - auto param = std::make_shared(val); + auto param = std::make_shared(val); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamUInt64(struct TWEthereumAbiFunction *_Nonnull func_in, uint64_t val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - auto param = std::make_shared(val); + auto param = std::make_shared(val); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamUInt256(struct TWEthereumAbiFunction *_Nonnull func_in, TWData *_Nonnull val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; uint256_t val2 = load(*static_cast(val)); - auto param = std::make_shared(val2); + auto param = std::make_shared(val2); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamUIntN(struct TWEthereumAbiFunction *_Nonnull func_in, int bits, TWData *_Nonnull val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; uint256_t val2 = load(*static_cast(val)); - auto param = std::make_shared(bits, val2); + auto param = std::make_shared(bits, val2); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamInt8(struct TWEthereumAbiFunction *_Nonnull func_in, int8_t val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - auto param = std::make_shared(val); + auto param = std::make_shared(val); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamInt16(struct TWEthereumAbiFunction *_Nonnull func_in, int16_t val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - auto param = std::make_shared(val); + auto param = std::make_shared(val); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamInt32(struct TWEthereumAbiFunction *_Nonnull func_in, int32_t val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - auto param = std::make_shared(val); + auto param = std::make_shared(val); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamInt64(struct TWEthereumAbiFunction *_Nonnull func_in, int64_t val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - auto param = std::make_shared(val); + auto param = std::make_shared(val); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamInt256(struct TWEthereumAbiFunction *_Nonnull func_in, TWData *_Nonnull val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; assert(val != nullptr); - int256_t val2 = ValueEncoder::int256FromUint256(load(*static_cast(val))); - auto param = std::make_shared(val2); + int256_t val2 = EthAbi::ValueEncoder::int256FromUint256(load(*static_cast(val))); + auto param = std::make_shared(val2); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamIntN(struct TWEthereumAbiFunction *_Nonnull func_in, int bits, TWData *_Nonnull val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; assert(val != nullptr); - int256_t val2 = ValueEncoder::int256FromUint256(load(*static_cast(val))); - auto param = std::make_shared(bits, val2); + int256_t val2 = EthAbi::ValueEncoder::int256FromUint256(load(*static_cast(val))); + auto param = std::make_shared(bits, val2); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamBool(struct TWEthereumAbiFunction *_Nonnull func_in, bool val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - auto param = std::make_shared(val); + auto param = std::make_shared(val); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamString(struct TWEthereumAbiFunction *_Nonnull func_in, TWString *_Nonnull val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; assert(val != nullptr); - auto param = std::make_shared(TWStringUTF8Bytes(val)); + auto param = std::make_shared(TWStringUTF8Bytes(val)); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamAddress(struct TWEthereumAbiFunction *_Nonnull func_in, TWData *_Nonnull val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; assert(val != nullptr); Data data = TW::data(TWDataBytes(val), TWDataSize(val)); - auto param = std::make_shared(data); + auto param = std::make_shared(data); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamBytes(struct TWEthereumAbiFunction *_Nonnull func_in, TWData *_Nonnull val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; Data data = TW::data(TWDataBytes(val), TWDataSize(val)); - auto param = std::make_shared(data); + auto param = std::make_shared(data); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamBytesFix(struct TWEthereumAbiFunction *_Nonnull func_in, size_t count, TWData *_Nonnull val, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; Data data = TW::data(TWDataBytes(val), TWDataSize(val)); - auto param = std::make_shared(count, data); + auto param = std::make_shared(count, data); auto idx = function.addParam(param, isOutput); return idx; } int TWEthereumAbiFunctionAddParamArray(struct TWEthereumAbiFunction *_Nonnull func_in, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - auto param = std::make_shared(); + auto param = std::make_shared(); auto idx = function.addParam(param, isOutput); return idx; } @@ -215,13 +214,13 @@ int TWEthereumAbiFunctionAddParamArray(struct TWEthereumAbiFunction *_Nonnull fu uint8_t TWEthereumAbiFunctionGetParamUInt8(struct TWEthereumAbiFunction *_Nonnull func_in, int idx, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - std::shared_ptr param; + std::shared_ptr param; if (!function.getParam(idx, param, isOutput)) { return 0; } - auto param2 = std::dynamic_pointer_cast(param); + auto param2 = std::dynamic_pointer_cast(param); if (param2 == nullptr) { return 0; } @@ -230,13 +229,13 @@ uint8_t TWEthereumAbiFunctionGetParamUInt8(struct TWEthereumAbiFunction *_Nonnul uint64_t TWEthereumAbiFunctionGetParamUInt64(struct TWEthereumAbiFunction *_Nonnull func_in, int idx, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - std::shared_ptr param; + std::shared_ptr param; if (!function.getParam(idx, param, isOutput)) { return 0; } - auto param2 = std::dynamic_pointer_cast(param); + auto param2 = std::dynamic_pointer_cast(param); if (param2 == nullptr) { return 0; } @@ -245,15 +244,15 @@ uint64_t TWEthereumAbiFunctionGetParamUInt64(struct TWEthereumAbiFunction *_Nonn TWData *_Nonnull TWEthereumAbiFunctionGetParamUInt256(struct TWEthereumAbiFunction *_Nonnull func_in, int idx, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; uint256_t val256 = 0; - std::shared_ptr param; + std::shared_ptr param; if (!function.getParam(idx, param, isOutput)) { TW::Data valData = TW::store(val256); return TWDataCreateWithData(&valData); } - auto param2 = std::dynamic_pointer_cast(param); + auto param2 = std::dynamic_pointer_cast(param); if (param2 == nullptr) { TW::Data valData = TW::store(val256); return TWDataCreateWithData(&valData); @@ -265,13 +264,13 @@ TWData *_Nonnull TWEthereumAbiFunctionGetParamUInt256(struct TWEthereumAbiFuncti bool TWEthereumAbiFunctionGetParamBool(struct TWEthereumAbiFunction *_Nonnull func_in, int idx, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - std::shared_ptr param; + std::shared_ptr param; if (!function.getParam(idx, param, isOutput)) { return false; } - auto param2 = std::dynamic_pointer_cast(param); + auto param2 = std::dynamic_pointer_cast(param); if (param2 == nullptr) { return false; } @@ -280,14 +279,14 @@ bool TWEthereumAbiFunctionGetParamBool(struct TWEthereumAbiFunction *_Nonnull fu TWString *_Nonnull TWEthereumAbiFunctionGetParamString(struct TWEthereumAbiFunction *_Nonnull func_in, int idx, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; std::string valStr; - std::shared_ptr param; + std::shared_ptr param; if (!function.getParam(idx, param, isOutput)) { return TWStringCreateWithUTF8Bytes(valStr.c_str()); } - auto param2 = std::dynamic_pointer_cast(param); + auto param2 = std::dynamic_pointer_cast(param); if (param2 == nullptr) { return TWStringCreateWithUTF8Bytes(valStr.c_str()); } @@ -297,14 +296,14 @@ TWString *_Nonnull TWEthereumAbiFunctionGetParamString(struct TWEthereumAbiFunct TWData *_Nonnull TWEthereumAbiFunctionGetParamAddress(struct TWEthereumAbiFunction *_Nonnull func_in, int idx, bool isOutput) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; Data valData; - std::shared_ptr param; + std::shared_ptr param; if (!function.getParam(idx, param, isOutput)) { return TWDataCreateWithData(&valData); } - auto param2 = std::dynamic_pointer_cast(param); + auto param2 = std::dynamic_pointer_cast(param); if (param2 == nullptr) { return TWDataCreateWithData(&valData); } @@ -314,12 +313,12 @@ TWData *_Nonnull TWEthereumAbiFunctionGetParamAddress(struct TWEthereumAbiFuncti ///// AddInArrayParam -int addInArrayParam(Function& function, int arrayIdx, const std::shared_ptr& childParam) { - std::shared_ptr param; +int addInArrayParam(EthAbi::Function& function, int arrayIdx, const std::shared_ptr& childParam) { + std::shared_ptr param; if (!function.getInParam(arrayIdx, param)) { return -1; } - std::shared_ptr paramArr = std::dynamic_pointer_cast(param); + std::shared_ptr paramArr = std::dynamic_pointer_cast(param); if (paramArr == nullptr) { return -1; // not an array } @@ -328,130 +327,130 @@ int addInArrayParam(Function& function, int arrayIdx, const std::shared_ptrimpl; + EthAbi::Function& function = func_in->impl; - return addInArrayParam(function, arrayIdx, std::make_shared(val)); + return addInArrayParam(function, arrayIdx, std::make_shared(val)); } int TWEthereumAbiFunctionAddInArrayParamUInt16(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, uint16_t val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - return addInArrayParam(function, arrayIdx, std::make_shared(val)); + return addInArrayParam(function, arrayIdx, std::make_shared(val)); } int TWEthereumAbiFunctionAddInArrayParamUInt32(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, uint32_t val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - return addInArrayParam(function, arrayIdx, std::make_shared(val)); + return addInArrayParam(function, arrayIdx, std::make_shared(val)); } int TWEthereumAbiFunctionAddInArrayParamUInt64(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, uint64_t val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - return addInArrayParam(function, arrayIdx, std::make_shared(val)); + return addInArrayParam(function, arrayIdx, std::make_shared(val)); } int TWEthereumAbiFunctionAddInArrayParamUInt256(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, TWData *_Nonnull val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; uint256_t val2 = load(*static_cast(val)); - return addInArrayParam(function, arrayIdx, std::make_shared(val2)); + return addInArrayParam(function, arrayIdx, std::make_shared(val2)); } int TWEthereumAbiFunctionAddInArrayParamUIntN(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, int bits, TWData *_Nonnull val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; uint256_t val2 = load(*static_cast(val)); - return addInArrayParam(function, arrayIdx, std::make_shared(bits, val2)); + return addInArrayParam(function, arrayIdx, std::make_shared(bits, val2)); } int TWEthereumAbiFunctionAddInArrayParamInt8(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, int8_t val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - return addInArrayParam(function, arrayIdx, std::make_shared(val)); + return addInArrayParam(function, arrayIdx, std::make_shared(val)); } int TWEthereumAbiFunctionAddInArrayParamInt16(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, int16_t val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - return addInArrayParam(function, arrayIdx, std::make_shared(val)); + return addInArrayParam(function, arrayIdx, std::make_shared(val)); } int TWEthereumAbiFunctionAddInArrayParamInt32(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, int32_t val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - return addInArrayParam(function, arrayIdx, std::make_shared(val)); + return addInArrayParam(function, arrayIdx, std::make_shared(val)); } int TWEthereumAbiFunctionAddInArrayParamInt64(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, int64_t val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - return addInArrayParam(function, arrayIdx, std::make_shared(val)); + return addInArrayParam(function, arrayIdx, std::make_shared(val)); } int TWEthereumAbiFunctionAddInArrayParamInt256(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, TWData *_Nonnull val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; assert(val != nullptr); - int256_t val2 = ValueEncoder::int256FromUint256(load(*static_cast(val))); - return addInArrayParam(function, arrayIdx, std::make_shared(val2)); + int256_t val2 = EthAbi::ValueEncoder::int256FromUint256(load(*static_cast(val))); + return addInArrayParam(function, arrayIdx, std::make_shared(val2)); } int TWEthereumAbiFunctionAddInArrayParamIntN(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, int bits, TWData *_Nonnull val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; assert(val != nullptr); - int256_t val2 = ValueEncoder::int256FromUint256(load(*static_cast(val))); - return addInArrayParam(function, arrayIdx, std::make_shared(bits, val2)); + int256_t val2 = EthAbi::ValueEncoder::int256FromUint256(load(*static_cast(val))); + return addInArrayParam(function, arrayIdx, std::make_shared(bits, val2)); } int TWEthereumAbiFunctionAddInArrayParamBool(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, bool val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; - return addInArrayParam(function, arrayIdx, std::make_shared(val)); + return addInArrayParam(function, arrayIdx, std::make_shared(val)); } int TWEthereumAbiFunctionAddInArrayParamString(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, TWString *_Nonnull val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; assert(val != nullptr); - return addInArrayParam(function, arrayIdx, std::make_shared(TWStringUTF8Bytes(val))); + return addInArrayParam(function, arrayIdx, std::make_shared(TWStringUTF8Bytes(val))); } int TWEthereumAbiFunctionAddInArrayParamAddress(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, TWData *_Nonnull val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; assert(val != nullptr); Data data = TW::data(TWDataBytes(val), TWDataSize(val)); - return addInArrayParam(function, arrayIdx, std::make_shared(data)); + return addInArrayParam(function, arrayIdx, std::make_shared(data)); } int TWEthereumAbiFunctionAddInArrayParamBytes(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, TWData *_Nonnull val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; Data data = TW::data(TWDataBytes(val), TWDataSize(val)); - return addInArrayParam(function, arrayIdx, std::make_shared(data)); + return addInArrayParam(function, arrayIdx, std::make_shared(data)); } int TWEthereumAbiFunctionAddInArrayParamBytesFix(struct TWEthereumAbiFunction *_Nonnull func_in, int arrayIdx, size_t count, TWData *_Nonnull val) { assert(func_in != nullptr); - Function& function = func_in->impl; + EthAbi::Function& function = func_in->impl; Data data = TW::data(TWDataBytes(val), TWDataSize(val)); - return addInArrayParam(function, arrayIdx, std::make_shared(count, data)); + return addInArrayParam(function, arrayIdx, std::make_shared(count, data)); } diff --git a/src/interface/TWEthereumAbiValue.cpp b/src/interface/TWEthereumAbiValue.cpp index 7a6843f23b0..a3dc02612af 100644 --- a/src/interface/TWEthereumAbiValue.cpp +++ b/src/interface/TWEthereumAbiValue.cpp @@ -10,63 +10,63 @@ #include #include -using namespace TW::Ethereum; using namespace TW; +namespace EthAbi = TW::Ethereum::ABI; TWData* _Nonnull TWEthereumAbiValueEncodeBool(bool value) { Data data; - ABI::ValueEncoder::encodeBool(value, data); + EthAbi::ValueEncoder::encodeBool(value, data); return TWDataCreateWithBytes(data.data(), data.size()); } TWData* _Nonnull TWEthereumAbiValueEncodeInt32(int32_t value) { Data data; - ABI::ValueEncoder::encodeInt32(value, data); + EthAbi::ValueEncoder::encodeInt32(value, data); return TWDataCreateWithBytes(data.data(), data.size()); } TWData* _Nonnull TWEthereumAbiValueEncodeUInt32(uint32_t value) { Data data; - ABI::ValueEncoder::encodeUInt32(value, data); + EthAbi::ValueEncoder::encodeUInt32(value, data); return TWDataCreateWithBytes(data.data(), data.size()); } TWData* _Nonnull TWEthereumAbiValueEncodeInt256(TWData* _Nonnull value) { Data data; int256_t value256 = static_cast(TW::load(*reinterpret_cast(value))); - ABI::ValueEncoder::encodeInt256(value256, data); + EthAbi::ValueEncoder::encodeInt256(value256, data); return TWDataCreateWithBytes(data.data(), data.size()); } TWData* _Nonnull TWEthereumAbiValueEncodeUInt256(TWData* _Nonnull value) { Data data; uint256_t value256 = TW::load(*reinterpret_cast(value)); - ABI::ValueEncoder::encodeUInt256(value256, data); + EthAbi::ValueEncoder::encodeUInt256(value256, data); return TWDataCreateWithBytes(data.data(), data.size()); } TWData* _Nonnull TWEthereumAbiValueEncodeAddress(TWData* _Nonnull value) { Data data; - ABI::ValueEncoder::encodeAddress(*reinterpret_cast(value), data); + EthAbi::ValueEncoder::encodeAddress(*reinterpret_cast(value), data); return TWDataCreateWithBytes(data.data(), data.size()); } TWData* _Nonnull TWEthereumAbiValueEncodeString(TWString* _Nonnull value) { Data data; - ABI::ValueEncoder::encodeString(TWStringUTF8Bytes(value), data); + EthAbi::ValueEncoder::encodeString(TWStringUTF8Bytes(value), data); return TWDataCreateWithBytes(data.data(), data.size()); } TWData* _Nonnull TWEthereumAbiValueEncodeBytes(TWData* _Nonnull value) { Data data; - ABI::ValueEncoder::encodeBytes(*reinterpret_cast(value), data); + EthAbi::ValueEncoder::encodeBytes(*reinterpret_cast(value), data); return TWDataCreateWithBytes(data.data(), data.size()); } TWData* _Nonnull TWEthereumAbiValueEncodeBytesDyn(TWData* _Nonnull value) { Data data; - ABI::ValueEncoder::encodeBytesDyn(*reinterpret_cast(value), data); + EthAbi::ValueEncoder::encodeBytesDyn(*reinterpret_cast(value), data); return TWDataCreateWithBytes(data.data(), data.size()); } diff --git a/src/interface/TWFIOAccount.cpp b/src/interface/TWFIOAccount.cpp index b600d82b493..4cdd419aa71 100644 --- a/src/interface/TWFIOAccount.cpp +++ b/src/interface/TWFIOAccount.cpp @@ -12,7 +12,6 @@ #include using namespace TW; -using namespace TW::FIO; struct TWFIOAccount { std::string description; @@ -20,11 +19,11 @@ struct TWFIOAccount { struct TWFIOAccount *_Nullable TWFIOAccountCreateWithString(TWString *_Nonnull string) { const auto& account = *reinterpret_cast(string); - if (Address::isValid(account)) { - const auto addr = Address(account); - return new TWFIOAccount{Actor::actor(addr)}; + if (FIO::Address::isValid(account)) { + const auto addr = FIO::Address(account); + return new TWFIOAccount{FIO::Actor::actor(addr)}; } - if (Actor::validate(account)) { + if (FIO::Actor::validate(account)) { return new TWFIOAccount{account}; } return nullptr; diff --git a/src/interface/TWNEARAccount.cpp b/src/interface/TWNEARAccount.cpp index 959fffcd049..84dca468ef0 100644 --- a/src/interface/TWNEARAccount.cpp +++ b/src/interface/TWNEARAccount.cpp @@ -13,7 +13,6 @@ #include using namespace TW; -using namespace TW::NEAR; struct TWNEARAccount { std::string description; @@ -21,11 +20,11 @@ struct TWNEARAccount { struct TWNEARAccount *_Nullable TWNEARAccountCreateWithString(TWString *_Nonnull string) { const auto& account = *reinterpret_cast(string); - if (Address::isValid(account)) { - const auto addr = Address(account); + if (TW::NEAR::Address::isValid(account)) { + const auto addr = TW::NEAR::Address(account); return new TWNEARAccount{addr.string()}; } - if (Account::isValid(account)) { + if (TW::NEAR::Account::isValid(account)) { return new TWNEARAccount{account}; } return nullptr; diff --git a/src/interface/TWRippleXAddress.cpp b/src/interface/TWRippleXAddress.cpp index 464e88bafa1..1304b1d17ab 100644 --- a/src/interface/TWRippleXAddress.cpp +++ b/src/interface/TWRippleXAddress.cpp @@ -13,7 +13,6 @@ #include using namespace TW; -using namespace TW::Ripple; bool TWRippleXAddressEqual(struct TWRippleXAddress *_Nonnull lhs, struct TWRippleXAddress *_Nonnull rhs) { return lhs->impl == rhs->impl; @@ -21,13 +20,13 @@ bool TWRippleXAddressEqual(struct TWRippleXAddress *_Nonnull lhs, struct TWRippl bool TWRippleXAddressIsValidString(TWString *_Nonnull string) { auto* s = reinterpret_cast(string); - return XAddress::isValid(*s); + return Ripple::XAddress::isValid(*s); } struct TWRippleXAddress *_Nullable TWRippleXAddressCreateWithString(TWString *_Nonnull string) { auto* s = reinterpret_cast(string); try { - const auto address = XAddress(*s); + const auto address = Ripple::XAddress(*s); return new TWRippleXAddress{ std::move(address) }; } catch (...) { return nullptr; @@ -35,7 +34,7 @@ struct TWRippleXAddress *_Nullable TWRippleXAddressCreateWithString(TWString *_N } struct TWRippleXAddress *_Nonnull TWRippleXAddressCreateWithPublicKey(struct TWPublicKey *_Nonnull publicKey, const uint32_t tag) { - return new TWRippleXAddress{ XAddress(publicKey->impl, tag) }; + return new TWRippleXAddress{ Ripple::XAddress(publicKey->impl, tag) }; } void TWRippleXAddressDelete(struct TWRippleXAddress *_Nonnull address) { diff --git a/src/interface/TWSegwitAddress.cpp b/src/interface/TWSegwitAddress.cpp index 22ce2f1da7f..59a41db467e 100644 --- a/src/interface/TWSegwitAddress.cpp +++ b/src/interface/TWSegwitAddress.cpp @@ -13,7 +13,6 @@ #include using namespace TW; -using namespace TW::Bitcoin; bool TWSegwitAddressEqual(struct TWSegwitAddress *_Nonnull lhs, struct TWSegwitAddress *_Nonnull rhs) { return lhs->impl == rhs->impl; @@ -21,12 +20,12 @@ bool TWSegwitAddressEqual(struct TWSegwitAddress *_Nonnull lhs, struct TWSegwitA bool TWSegwitAddressIsValidString(TWString *_Nonnull string) { auto* s = reinterpret_cast(string); - return SegwitAddress::isValid(*s); + return Bitcoin::SegwitAddress::isValid(*s); } struct TWSegwitAddress *_Nullable TWSegwitAddressCreateWithString(TWString *_Nonnull string) { auto* s = reinterpret_cast(string); - auto dec = SegwitAddress::decode(*s); + auto dec = Bitcoin::SegwitAddress::decode(*s); if (!std::get<2>(dec)) { return nullptr; } @@ -35,7 +34,7 @@ struct TWSegwitAddress *_Nullable TWSegwitAddressCreateWithString(TWString *_Non } struct TWSegwitAddress *_Nonnull TWSegwitAddressCreateWithPublicKey(enum TWHRP hrp, struct TWPublicKey *_Nonnull publicKey) { - const auto address = SegwitAddress(publicKey->impl, stringForHRP(hrp)); + const auto address = Bitcoin::SegwitAddress(publicKey->impl, stringForHRP(hrp)); return new TWSegwitAddress{ std::move(address) }; } diff --git a/src/interface/TWStoredKey.cpp b/src/interface/TWStoredKey.cpp index 42659dee95a..4974e87c29e 100644 --- a/src/interface/TWStoredKey.cpp +++ b/src/interface/TWStoredKey.cpp @@ -14,12 +14,12 @@ #include #include -using namespace TW::Keystore; +namespace KeyStore = TW::Keystore; struct TWStoredKey* _Nullable TWStoredKeyLoad(TWString* _Nonnull path) { try { const auto& pathString = *reinterpret_cast(path); - return new TWStoredKey{ StoredKey::load(pathString) }; + return new TWStoredKey{ KeyStore::StoredKey::load(pathString) }; } catch (...) { return nullptr; } @@ -28,7 +28,7 @@ struct TWStoredKey* _Nullable TWStoredKeyLoad(TWString* _Nonnull path) { struct TWStoredKey* _Nonnull TWStoredKeyCreateLevel(TWString* _Nonnull name, TWData* _Nonnull password, enum TWStoredKeyEncryptionLevel encryptionLevel) { const auto& nameString = *reinterpret_cast(name); const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password)); - return new TWStoredKey{ StoredKey::createWithMnemonicRandom(nameString, passwordData, encryptionLevel) }; + return new TWStoredKey{ KeyStore::StoredKey::createWithMnemonicRandom(nameString, passwordData, encryptionLevel) }; } struct TWStoredKey* _Nonnull TWStoredKeyCreate(TWString* _Nonnull name, TWData* _Nonnull password) { @@ -40,7 +40,7 @@ struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKey(TWData* _Nonnull priva const auto& privateKeyData = *reinterpret_cast(privateKey); const auto& nameString = *reinterpret_cast(name); const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password)); - return new TWStoredKey{ StoredKey::createWithPrivateKeyAddDefaultAddress(nameString, passwordData, coin, privateKeyData) }; + return new TWStoredKey{ KeyStore::StoredKey::createWithPrivateKeyAddDefaultAddress(nameString, passwordData, coin, privateKeyData) }; } catch (...) { return nullptr; } @@ -51,7 +51,7 @@ struct TWStoredKey* _Nullable TWStoredKeyImportHDWallet(TWString* _Nonnull mnemo const auto& mnemonicString = *reinterpret_cast(mnemonic); const auto& nameString = *reinterpret_cast(name); const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password)); - return new TWStoredKey{ StoredKey::createWithMnemonicAddDefaultAddress(nameString, passwordData, mnemonicString, coin) }; + return new TWStoredKey{ KeyStore::StoredKey::createWithMnemonicAddDefaultAddress(nameString, passwordData, mnemonicString, coin) }; } catch (...) { return nullptr; } @@ -61,7 +61,7 @@ struct TWStoredKey* _Nullable TWStoredKeyImportJSON(TWData* _Nonnull json) { try { const auto& d = *reinterpret_cast(json); const auto parsed = nlohmann::json::parse(d); - return new TWStoredKey{ StoredKey::createWithJson(nlohmann::json::parse(d)) }; + return new TWStoredKey{ KeyStore::StoredKey::createWithJson(nlohmann::json::parse(d)) }; } catch (...) { return nullptr; } @@ -83,7 +83,7 @@ TWString* _Nonnull TWStoredKeyName(struct TWStoredKey* _Nonnull key) { } bool TWStoredKeyIsMnemonic(struct TWStoredKey* _Nonnull key) { - return key->impl.type == StoredKeyType::mnemonicPhrase; + return key->impl.type == KeyStore::StoredKeyType::mnemonicPhrase; } size_t TWStoredKeyAccountCount(struct TWStoredKey* _Nonnull key) { diff --git a/tests/Harmony/TWHarmonyStakingTests.cpp b/tests/Harmony/TWHarmonyStakingTests.cpp index 81f6ae50108..9492225f7a7 100644 --- a/tests/Harmony/TWHarmonyStakingTests.cpp +++ b/tests/Harmony/TWHarmonyStakingTests.cpp @@ -17,7 +17,7 @@ #include using namespace TW; -using namespace Harmony; +namespace TW::Harmony::tests { static auto TEST_ACCOUNT = "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9"; @@ -91,7 +91,6 @@ TEST(TWHarmonyStakingSigner, CreateValidator) { value = store(uint256_t("0x64")); stakingMessage->set_gas_limit(value.data(), value.size()); - Proto::SigningOutput output; ANY_SIGN(input, TWCoinTypeHarmony); @@ -104,7 +103,6 @@ TEST(TWHarmonyStakingSigner, CreateValidator) { ASSERT_EQ(hex(output.s()), shouldBeS); } - TEST(TWHarmonyStakingSigner, EditValidator) { auto input = Proto::SigningInput(); input.set_private_key(PRIVATE_KEY.bytes.data(), PRIVATE_KEY.bytes.size()); @@ -149,7 +147,7 @@ TEST(TWHarmonyStakingSigner, EditValidator) { "5c864771cafef7b96be541cb3c521a98f01838dd94"); editValidatorMsg->set_slot_key_to_add_sig(value.data(), value.size()); - //test active + // test active value = store(uint256_t("1")); editValidatorMsg->set_active(value.data(), value.size()); @@ -219,7 +217,7 @@ TEST(TWHarmonyStakingSigner, EditValidator2) { "5c864771cafef7b96be541cb3c521a98f01838dd94"); editValidatorMsg->set_slot_key_to_add_sig(value.data(), value.size()); - //test null + // test null value = store(uint256_t("0")); editValidatorMsg->set_active(value.data(), value.size()); @@ -289,7 +287,7 @@ TEST(TWHarmonyStakingSigner, EditValidator3) { "5c864771cafef7b96be541cb3c521a98f01838dd94"); editValidatorMsg->set_slot_key_to_add_sig(value.data(), value.size()); - //test inactive + // test inactive value = store(uint256_t("2")); editValidatorMsg->set_active(value.data(), value.size()); @@ -314,7 +312,6 @@ TEST(TWHarmonyStakingSigner, EditValidator3) { ASSERT_EQ(hex(output.s()), shouldBeS); } - TEST(TWHarmonyStakingSigner, Delegate) { auto input = Proto::SigningInput(); input.set_private_key(PRIVATE_KEY.bytes.data(), PRIVATE_KEY.bytes.size()); @@ -351,8 +348,6 @@ TEST(TWHarmonyStakingSigner, Delegate) { ASSERT_EQ(hex(output.s()), shouldBeS); } - - TEST(TWHarmonyStakingSigner, Undelegate) { auto input = Proto::SigningInput(); input.set_private_key(PRIVATE_KEY.bytes.data(), PRIVATE_KEY.bytes.size()); @@ -420,3 +415,5 @@ TEST(TWHarmonyStakingSigner, CollectRewards) { ASSERT_EQ(hex(output.r()), shouldBeR); ASSERT_EQ(hex(output.s()), shouldBeS); } + +} // namespace TW::Harmony::tests diff --git a/tests/Nimiq/TWAnySignerTests.cpp b/tests/Nimiq/TWAnySignerTests.cpp index 5a827a87009..bc7bcaf9fec 100644 --- a/tests/Nimiq/TWAnySignerTests.cpp +++ b/tests/Nimiq/TWAnySignerTests.cpp @@ -11,8 +11,7 @@ #include "../interface/TWTestUtilities.h" #include -using namespace TW; -using namespace TW::Nimiq; +namespace TW::Nimiq::tests { TEST(TWAnySignerNimiq, Sign) { auto privateKey = parse_hex("e3cc33575834add098f8487123cd4bca543ee859b3e8cfe624e7e6a97202b756"); @@ -30,3 +29,5 @@ TEST(TWAnySignerNimiq, Sign) { EXPECT_EQ(hex(output.encoded()), "0070c7492aaa9c9ac7a05bc0d9c5db2dae9372029654f71f0c7f95deed5099b7021450ffc385cd4e7c6ac9a7e91614ca67ff90568a00000000028182ba00000000000003e80004cb2f2a74dc7f6e0ab58a0bf52cc6e8801b0cca132dd4229d9a3e3a3d2f90e4d8f045d981b771bf5fc3851a98f3c617b1a943228f963e910e061808a721cfa0e3cad50b"); } + +} // namespace TW::Nimiq::tests diff --git a/tests/Oasis/TWAnySignerTests.cpp b/tests/Oasis/TWAnySignerTests.cpp index c76d46256e1..5e1c2b504ee 100644 --- a/tests/Oasis/TWAnySignerTests.cpp +++ b/tests/Oasis/TWAnySignerTests.cpp @@ -12,7 +12,7 @@ #include using namespace TW; -using namespace TW::Oasis; +namespace TW::Oasis::tests { TEST(TWAnySignerOasis, Sign) { auto input = Proto::SigningInput(); @@ -26,7 +26,6 @@ TEST(TWAnySignerOasis, Sign) { transfer.set_amount("10000000"); transfer.set_context("oasis-core/consensus: tx for chain a245619497e580dd3bc1aa3256c07f68b8dcc13f92da115eadc3b231b083d3c4"); - auto key = parse_hex("4f8b5676990b00e23d9904a92deb8d8f428ff289c8939926358f1d20537c21a0"); input.set_private_key(key.data(), key.size()); @@ -35,3 +34,5 @@ TEST(TWAnySignerOasis, Sign) { EXPECT_EQ("a2697369676e6174757265a2697369676e617475726558406e51c18c9b2015c9b49414b3307336597f51ff331873d214ce2db81c9651a34d99529ccaa294a39ccd01c6b0bc2c2239d87c624e5ba4840cf99ac8f9283e240c6a7075626c69635f6b6579582093d8f8a455f50527976a8aa87ebde38d5606efa86cb985d3fb466aff37000e3b73756e747275737465645f7261775f76616c7565585ea463666565a2636761730066616d6f756e74410064626f6479a262746f5500c73cc001463434915ba3f39751beb7c0905b45eb66616d6f756e744400989680656e6f6e636500666d6574686f64707374616b696e672e5472616e73666572", hex(output.encoded())); } + +} // namespace TW::Oasis::tests diff --git a/tests/Ontology/AccountTests.cpp b/tests/Ontology/AccountTests.cpp index e6dcbfa56e9..ddd717f483b 100644 --- a/tests/Ontology/AccountTests.cpp +++ b/tests/Ontology/AccountTests.cpp @@ -13,7 +13,7 @@ #include using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology::tests { TEST(OntologyAccount, validity) { auto hexPrvKey = "4646464646464646464646464646464646464646464646464646464646464646"; @@ -23,4 +23,6 @@ TEST(OntologyAccount, validity) { auto pubKey = signer.getPublicKey(); EXPECT_EQ(hexPrvKey, hex(prvKey.bytes)); EXPECT_EQ(hexPubKey, hex(pubKey.bytes)); -} \ No newline at end of file +} + +} // namespace TW::Ontology::tests diff --git a/tests/Ripple/TransactionTests.cpp b/tests/Ripple/TransactionTests.cpp index f7c33b701bf..9b14781f5f4 100644 --- a/tests/Ripple/TransactionTests.cpp +++ b/tests/Ripple/TransactionTests.cpp @@ -14,8 +14,8 @@ #include using namespace std; -using namespace TW; -using namespace TW::Ripple; + +namespace TW::Ripple::tests { TEST(RippleTransaction, serializeAmount) { /// From https://github.com/trezor/trezor-core/blob/master/tests/test_apps.ripple.serializer.py @@ -124,3 +124,5 @@ TEST(RippleTransaction, preImage) { ); ASSERT_EQ(unsignedTx.size(), 114ul); } + +} // namespace TW::Ripple::tests diff --git a/tests/Solana/SignerTests.cpp b/tests/Solana/SignerTests.cpp index 2ca7fdf04e7..875300fb5e2 100644 --- a/tests/Solana/SignerTests.cpp +++ b/tests/Solana/SignerTests.cpp @@ -13,7 +13,7 @@ #include using namespace TW; -using namespace TW::Solana; +namespace TW::Solana::tests { TEST(SolanaSigner, CompiledInstruction) { const auto privateKey0 = @@ -59,10 +59,12 @@ TEST(SolanaSigner, CompiledInstructionFindAccount) { Address address2 = Address(parse_hex("0102030405060708090a0102030405060708090a0102030405060708090a0102")); Address address3 = Address(parse_hex("0102030405060708090a0102030405060708090a0102030405060708090a0103")); Address programId("11111111111111111111111111111111"); + // clang-format off Instruction instruction(programId, std::vector{ AccountMeta(address1, true, false), AccountMeta(address2, false, false), }, Data{1, 2, 3, 4}); + // clang-format on std::vector
addresses = { address1, address2, @@ -393,7 +395,7 @@ TEST(SolanaSigner, SignTransferToken_3vZ67C) { Solana::Hash recentBlockhash("CNaHfvqePgGYMvtYi9RuUdVxDYttr1zs4TWrTXYabxZi"); auto message = Message::createTokenTransfer(signer, token, - senderTokenAddress, recipientTokenAddress, amount, decimals, recentBlockhash); + senderTokenAddress, recipientTokenAddress, amount, decimals, recentBlockhash); auto transaction = Transaction(message); std::vector signerKeys; @@ -411,3 +413,5 @@ TEST(SolanaSigner, SignTransferToken_3vZ67C) { "PGfKqEaH2zZXDMZLcU6LUKdBSzU1GJWJ1CJXtRYCxaCH7k8uok38WSadZfrZw3TGejiau7nSpan2GvbK26hQim24jRe2AupmcYJFrgsdaCt1Aqs5kpGjPqzgj9krgxTZwwob3xgC1NdHK5BcNwhxwRtrCphGEH7zUFpGFrFrHzgpf2KY8FvPiPELQyxzTBuyNtjLjMMreehSKShEjD9Xzp1QeC1pEF8JL6vUKzxMXuveoEYem8q8JiWszYzmTMfDk13JPgv7pXFGMqDV3yNGCLsWccBeSFKN4UKECre6x2QbUEiKGkHkMc4zQwwyD8tGmEMBAGm339qdANssEMNpDeJp2LxLDStSoWShHnotcrH7pUa94xCVvCPPaomF"; EXPECT_EQ(transaction.serialize(), expectedString); } + +} // namespace TW::Solana::tests diff --git a/tests/Terra/SignerTests.cpp b/tests/Terra/SignerTests.cpp index 1196d7af458..483cd1adfd6 100644 --- a/tests/Terra/SignerTests.cpp +++ b/tests/Terra/SignerTests.cpp @@ -18,7 +18,7 @@ #include using namespace TW; -using namespace TW::Cosmos; +namespace TW::Cosmos::tests { TEST(TerraSigner, SignSendTx) { auto input = Proto::SigningInput(); @@ -360,3 +360,5 @@ TEST(TerraSigner, SignWasmTransferPayload) { } )"); } + +} // namespace TW::Terra diff --git a/tests/Tezos/OperationListTests.cpp b/tests/Tezos/OperationListTests.cpp index db57ea1da0e..9fb89d9e8a6 100644 --- a/tests/Tezos/OperationListTests.cpp +++ b/tests/Tezos/OperationListTests.cpp @@ -12,8 +12,7 @@ #include -using namespace TW::Tezos; -using namespace TW::Tezos::Proto; +namespace TW::Tezos::tests { TEST(TezosOperationList, ForgeBranch) { auto input = TW::Tezos::OperationList("BMNY6Jkas7BzKb7wDLCFoQ4YxfYoieU7Xmo1ED3Y9Lo3ZvVGdgW"); @@ -27,17 +26,17 @@ TEST(TezosOperationList, ForgeOperationList_TransactionOnly) { auto op_list = TW::Tezos::OperationList(branch); auto key = parsePrivateKey("edsk4bMQMM6HYtMazF3m7mYhQ6KQ1WCEcBuRwh6DTtdnoqAvC3nPCc"); - auto transactionOperationData = new TW::Tezos::Proto::TransactionOperationData(); - transactionOperationData -> set_amount(1); - transactionOperationData -> set_destination("tz1Yju7jmmsaUiG9qQLoYv35v5pHgnWoLWbt"); + auto transactionOperationData = new Proto::TransactionOperationData(); + transactionOperationData->set_amount(1); + transactionOperationData->set_destination("tz1Yju7jmmsaUiG9qQLoYv35v5pHgnWoLWbt"); - auto transactionOperation = TW::Tezos::Proto::Operation(); + auto transactionOperation = Proto::Operation(); transactionOperation.set_source("tz1XVJ8bZUXs7r5NV8dHvuiBhzECvLRLR3jW"); transactionOperation.set_fee(1272); transactionOperation.set_counter(30738); transactionOperation.set_gas_limit(10100); transactionOperation.set_storage_limit(257); - transactionOperation.set_kind(TW::Tezos::Proto::Operation::TRANSACTION); + transactionOperation.set_kind(Proto::Operation::TRANSACTION); transactionOperation.set_allocated_transaction_operation_data(transactionOperationData); op_list.addOperation(transactionOperation); @@ -53,10 +52,10 @@ TEST(TezosOperationList, ForgeOperationList_RevealOnly) { auto key = parsePrivateKey("edsk4bMQMM6HYtMazF3m7mYhQ6KQ1WCEcBuRwh6DTtdnoqAvC3nPCc"); PublicKey publicKey = parsePublicKey("edpku9ZF6UUAEo1AL3NWy1oxHLL6AfQcGYwA5hFKrEKVHMT3Xx889A"); - auto revealOperationData = new TW::Tezos::Proto::RevealOperationData(); - revealOperationData -> set_public_key(publicKey.bytes.data(), publicKey.bytes.size()); + auto revealOperationData = new Proto::RevealOperationData(); + revealOperationData->set_public_key(publicKey.bytes.data(), publicKey.bytes.size()); - auto revealOperation = TW::Tezos::Proto::Operation(); + auto revealOperation = Proto::Operation(); revealOperation.set_source("tz1XVJ8bZUXs7r5NV8dHvuiBhzECvLRLR3jW"); revealOperation.set_fee(1272); revealOperation.set_counter(30738); @@ -74,18 +73,18 @@ TEST(TezosOperationList, ForgeOperationList_RevealOnly) { TEST(TezosOperationList, ForgeOperationList_Delegation_ClearDelegate) { auto branch = "BLGJfQDFEYZBRLj5GSHskj8NPaRYhk7Kx5WAfdcDucD3q98WdeW"; - auto op_list = TW::Tezos::OperationList(branch); + auto op_list = OperationList(branch); auto key = parsePrivateKey("edsk4bMQMM6HYtMazF3m7mYhQ6KQ1WCEcBuRwh6DTtdnoqAvC3nPCc"); - auto delegationOperationData = new TW::Tezos::Proto::DelegationOperationData(); + auto delegationOperationData = new Proto::DelegationOperationData(); delegationOperationData->set_delegate("tz1gSM6yiwr85jEASZ1q3UekgHEoxYt7wg2M"); - auto delegationOperation = TW::Tezos::Proto::Operation(); + auto delegationOperation = Proto::Operation(); delegationOperation.set_source("tz1RKLoYm4vtLzo7TAgGifMDAkiWhjfyXwP4"); delegationOperation.set_fee(1257); delegationOperation.set_counter(67); delegationOperation.set_gas_limit(10000); delegationOperation.set_storage_limit(0); - delegationOperation.set_kind(TW::Tezos::Proto::Operation::DELEGATION); + delegationOperation.set_kind(Proto::Operation::DELEGATION); delegationOperation.set_allocated_delegation_operation_data(delegationOperationData); op_list.addOperation(delegationOperation); @@ -96,20 +95,20 @@ TEST(TezosOperationList, ForgeOperationList_Delegation_ClearDelegate) { TEST(TezosOperationList, ForgeOperationList_Delegation_AddDelegate) { auto branch = "BLa4GrVQTxUgQWbHv6cF7RXWSGzHGPbgecpQ795R3cLzw4cGfpD"; - auto op_list = TW::Tezos::OperationList(branch); + auto op_list = OperationList(branch); auto key = parsePrivateKey("edsk4bMQMM6HYtMazF3m7mYhQ6KQ1WCEcBuRwh6DTtdnoqAvC3nPCc"); - auto delegationOperationData = new TW::Tezos::Proto::DelegationOperationData(); - delegationOperationData -> set_delegate("tz1dYUCcrorfCoaQCtZaxi1ynGrP3prTZcxS"); + auto delegationOperationData = new Proto::DelegationOperationData(); + delegationOperationData->set_delegate("tz1dYUCcrorfCoaQCtZaxi1ynGrP3prTZcxS"); - auto delegationOperation = TW::Tezos::Proto::Operation(); + auto delegationOperation = Proto::Operation(); delegationOperation.set_source("KT1D5jmrBD7bDa3jCpgzo32FMYmRDdK2ihka"); delegationOperation.set_fee(1257); delegationOperation.set_counter(68); delegationOperation.set_gas_limit(10000); delegationOperation.set_storage_limit(0); - delegationOperation.set_kind(TW::Tezos::Proto::Operation::DELEGATION); + delegationOperation.set_kind(Proto::Operation::DELEGATION); delegationOperation.set_allocated_delegation_operation_data(delegationOperationData); - + op_list.addOperation(delegationOperation); auto expected = "7105102c032807994dd9b5edf219261896a559876ca16cbf9d31dbe3612b89f26e00315b1206ec00b1b1e64cc3b8b93059f58fa2fc39e90944904e00ff00c4650fd609f88c67356e5fe01e37cd3ff654b18c"; auto forged = op_list.forge(key); @@ -118,33 +117,33 @@ TEST(TezosOperationList, ForgeOperationList_Delegation_AddDelegate) { TEST(TezosOperationList, ForgeOperationList_TransactionAndReveal) { auto branch = "BL8euoCWqNCny9AR3AKjnpi38haYMxjei1ZqNHuXMn19JSQnoWp"; - auto op_list = TW::Tezos::OperationList(branch); + auto op_list = OperationList(branch); auto key = parsePrivateKey("edsk4bMQMM6HYtMazF3m7mYhQ6KQ1WCEcBuRwh6DTtdnoqAvC3nPCc"); auto publicKey = parsePublicKey("edpkuNb9N2UHtGeSc2BZCBHN8ETx7E4DwkSfz5Hw3m3tF3dLZTU8qp"); - auto revealOperationData = new TW::Tezos::Proto::RevealOperationData(); - revealOperationData -> set_public_key(publicKey.bytes.data(), publicKey.bytes.size()); + auto revealOperationData = new Proto::RevealOperationData(); + revealOperationData->set_public_key(publicKey.bytes.data(), publicKey.bytes.size()); - auto revealOperation = TW::Tezos::Proto::Operation(); + auto revealOperation = Proto::Operation(); revealOperation.set_source("tz1RKLoYm4vtLzo7TAgGifMDAkiWhjfyXwP4"); revealOperation.set_fee(1272); revealOperation.set_counter(30738); revealOperation.set_gas_limit(10100); revealOperation.set_storage_limit(257); - revealOperation.set_kind(TW::Tezos::Proto::Operation::REVEAL); + revealOperation.set_kind(Proto::Operation::REVEAL); revealOperation.set_allocated_reveal_operation_data(revealOperationData); - - auto transactionOperationData = new TW::Tezos::Proto::TransactionOperationData(); - transactionOperationData -> set_amount(1); - transactionOperationData -> set_destination("tz1gSM6yiwr85jEASZ1q3UekgHEoxYt7wg2M"); - auto transactionOperation = TW::Tezos::Proto::Operation(); + auto transactionOperationData = new Proto::TransactionOperationData(); + transactionOperationData->set_amount(1); + transactionOperationData->set_destination("tz1gSM6yiwr85jEASZ1q3UekgHEoxYt7wg2M"); + + auto transactionOperation = Proto::Operation(); transactionOperation.set_source("tz1RKLoYm4vtLzo7TAgGifMDAkiWhjfyXwP4"); transactionOperation.set_fee(1272); transactionOperation.set_counter(30739); transactionOperation.set_gas_limit(10100); transactionOperation.set_storage_limit(257); - transactionOperation.set_kind(TW::Tezos::Proto::Operation::TRANSACTION); + transactionOperation.set_kind(Proto::Operation::TRANSACTION); transactionOperation.set_allocated_transaction_operation_data(transactionOperationData); op_list.addOperation(revealOperation); @@ -158,18 +157,18 @@ TEST(TezosOperationList, ForgeOperationList_TransactionAndReveal) { TEST(TezosOperationList, ForgeOperationList_RevealWithoutPublicKey) { auto branch = "BL8euoCWqNCny9AR3AKjnpi38haYMxjei1ZqNHuXMn19JSQnoWp"; - auto op_list = TW::Tezos::OperationList(branch); + auto op_list = OperationList(branch); auto key = parsePrivateKey("edsk4bMQMM6HYtMazF3m7mYhQ6KQ1WCEcBuRwh6DTtdnoqAvC3nPCc"); - auto revealOperationData = new TW::Tezos::Proto::RevealOperationData(); + auto revealOperationData = new Proto::RevealOperationData(); - auto revealOperation = TW::Tezos::Proto::Operation(); + auto revealOperation = Proto::Operation(); revealOperation.set_source("tz1RKLoYm4vtLzo7TAgGifMDAkiWhjfyXwP4"); revealOperation.set_fee(1272); revealOperation.set_counter(30738); revealOperation.set_gas_limit(10100); revealOperation.set_storage_limit(257); - revealOperation.set_kind(TW::Tezos::Proto::Operation::REVEAL); + revealOperation.set_kind(Proto::Operation::REVEAL); revealOperation.set_allocated_reveal_operation_data(revealOperationData); op_list.addOperation(revealOperation); @@ -179,3 +178,5 @@ TEST(TezosOperationList, ForgeOperationList_RevealWithoutPublicKey) { ASSERT_EQ(hex(forged.begin(), forged.end()), expected); } + +} // namespace TW::Tezos::tests diff --git a/tests/Tezos/TWAnySignerTests.cpp b/tests/Tezos/TWAnySignerTests.cpp index 4f2627ed2d7..08dedc82145 100644 --- a/tests/Tezos/TWAnySignerTests.cpp +++ b/tests/Tezos/TWAnySignerTests.cpp @@ -12,7 +12,7 @@ #include using namespace TW; -using namespace TW::Tezos; +namespace TW::Tezos::tests { TEST(TWAnySignerTezos, Sign) { auto key = parse_hex("2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6f"); @@ -58,3 +58,5 @@ TEST(TWAnySignerTezos, SignJSON) { ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeTezos)); assertStringsEqual(result, "3756ef37b1be849e3114643f0aa5847cabf9a896d3bfe4dd51448de68e91da016b0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80992f001f44e810200429a986c8072a40a1f3a3e2ab5a5819bb1b2fb69993c5004837815b9dc55923e6c0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80993f001f44e810201000081faa75f741ef614b0e35fcc8c90dfa3b0b957210001b86398d5b9be737dca8e4106ea18d70e69b75e92f892fb283546a99152b8d7794b919c0fbf1c31de386069a60014491c0e7505adef5781cead1cfe6608030b"); } + +} // namespace TW::Tezos::tests diff --git a/tests/Waves/SignerTests.cpp b/tests/Waves/SignerTests.cpp index bf45d2db69e..95938c16d39 100644 --- a/tests/Waves/SignerTests.cpp +++ b/tests/Waves/SignerTests.cpp @@ -13,7 +13,8 @@ #include using namespace TW; -using namespace TW::Waves; + +namespace TW::Waves::tests { TEST(WavesSigner, SignTransaction) { const auto privateKey = @@ -59,3 +60,5 @@ TEST(WavesSigner, curve25519_pk_to_ed25519) { curve25519_pk_to_ed25519(r.data(), publicKeyCurve25519.data()); EXPECT_EQ(hex(r), "ff84c4bfc095df25b01e48807715856d95af93d88c5b57f30cb0ce567ca4ce56"); } + +} // namespace TW::Waves::tests diff --git a/tests/operators/equality_comparable_tests.cpp b/tests/operators/equality_comparable_tests.cpp index 37605b14dfd..134d172968e 100644 --- a/tests/operators/equality_comparable_tests.cpp +++ b/tests/operators/equality_comparable_tests.cpp @@ -8,7 +8,7 @@ #include "gtest/gtest.h" -using namespace TW; +namespace TW::operators::tests { struct Amount : equality_comparable { int value; @@ -19,3 +19,5 @@ TEST(Operators, EqualityComparable) { ASSERT_TRUE(Amount{.value = 1} != Amount{.value = 2}); ASSERT_TRUE(Amount{.value = 1} == Amount{.value = 1}); } + +} // namespace TW::operators::tests From c7c2b46ccc5bc0dfa0a9fa86b1f615a57c3f8f81 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Mon, 22 Aug 2022 19:44:10 +0900 Subject: [PATCH 056/497] [Tests] Read default tests root folder (#2521) * read default tests root folder * only use filesystem in tests target * remove passing test root * print TESTS_ROOT --- .github/workflows/linux-ci.yml | 2 +- cmake/StandardSettings.cmake | 2 +- tests/main.cpp | 28 ++++++++++++++-------------- tools/build-and-test | 4 +--- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index e4578e07c54..bed1b725444 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -44,7 +44,7 @@ jobs: run: | ninja -Cbuild tests TrezorCryptoTests build/trezor-crypto/crypto/tests/TrezorCryptoTests - build/tests/tests tests --gtest_output=xml + build/tests/tests --gtest_output=xml env: CC: /usr/bin/clang CXX: /usr/bin/clang++ diff --git a/cmake/StandardSettings.cmake b/cmake/StandardSettings.cmake index 60dff027c54..752b2285672 100644 --- a/cmake/StandardSettings.cmake +++ b/cmake/StandardSettings.cmake @@ -4,7 +4,7 @@ set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) -set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14" CACHE STRING "Minimum OS X deployment version" FORCE) +set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version" FORCE) # # IDE Settings diff --git a/tests/main.cpp b/tests/main.cpp index d75eab4a6bc..cd1077f409b 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -1,26 +1,26 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include #include +#include std::string TESTS_ROOT; -int main(int argc, char **argv) { - if (argc < 2) { - std::cerr << "Please specify the tests root folder." << std::endl; - exit(1); - } - - TESTS_ROOT = argv[1]; - struct stat s; - if (stat(TESTS_ROOT.c_str(), &s) != 0 || (s.st_mode & S_IFDIR) == 0) { - std::cerr << "Please specify the tests root folder. '" << TESTS_ROOT << "' is not a valid directory." << std::endl; - exit(1); - } - +int main(int argc, char** argv) { + // current path + auto path = std::filesystem::current_path(); + // executable path + path.append(argv[0]); + // normalize + path = std::filesystem::canonical(path); + // root path + path = path.parent_path().parent_path().parent_path(); + TESTS_ROOT = path.append("tests").string(); + std::cout<<"TESTS_ROOT: "< Date: Mon, 22 Aug 2022 16:19:07 +0530 Subject: [PATCH 057/497] Added support for Nervos blockchain, its native token CKB and SUDT (Simple User Defined Tokens). (#2293) * Added support Nervos blockchain and its native token CKB. * Added support for SUDT (Simple User Defined Token) in Nervos blockchain, similar to ERC20 in Ethereum. Also did some optimizations and bug fixes that were discovered in the process. * In Nervos SigningOutput, formed and returned transaction as JSON string instead of proto object. * Added Nervos DAO deposit and withdraw operations. * In Nervos DAO withdraw operation, added one more test case to increase code coverage. Also did one minor bug fix related to fee calculation of DAO withdraw transaction. * Made all constants in Nervos/Constants.h static const which was otherwise causing code coverage test to fail. * Cosmetic changes. Also added real transactions URLs in tests. * More warning fixes * Add swift / kotlin tests * Removed unordered_map gHashTypeRegistry and gDepTypeRegistry since they were causing CI pipeline to fail. * In Nervos script, initialized hashType to default value instead of garbage value in one corner case. * In Nervos, renamed hrp to _hrp and witnesses to serializedWitnesses. * Add TWNervosAddress * Add TWNervosAddress test * simplify amount types for native transfer / sudt Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- .../blockchains/CoinAddressDerivationTests.kt | 1 + .../blockchains/nervos/TestNervosAddress.kt | 29 + .../blockchains/nervos/TestNervosSigner.kt | 69 ++ docs/registry.md | 1 + include/TrustWalletCore/TWBlockchain.h | 1 + include/TrustWalletCore/TWCoinType.h | 1 + include/TrustWalletCore/TWNervosAddress.h | 50 + registry.json | 27 + src/Coin.cpp | 3 + src/Nervos/Address.cpp | 177 ++++ src/Nervos/Address.h | 80 ++ src/Nervos/Cell.h | 108 ++ src/Nervos/CellDep.cpp | 38 + src/Nervos/CellDep.h | 45 + src/Nervos/CellInput.cpp | 23 + src/Nervos/CellInput.h | 36 + src/Nervos/CellOutput.cpp | 29 + src/Nervos/CellOutput.h | 53 + src/Nervos/Constants.h | 53 + src/Nervos/Entry.cpp | 33 + src/Nervos/Entry.h | 28 + src/Nervos/HeaderDep.h | 19 + src/Nervos/OutPoint.cpp | 23 + src/Nervos/OutPoint.h | 54 + src/Nervos/Script.cpp | 52 + src/Nervos/Script.h | 107 ++ src/Nervos/Serialization.h | 60 ++ src/Nervos/Signer.cpp | 54 + src/Nervos/Signer.h | 26 + src/Nervos/Transaction.cpp | 215 ++++ src/Nervos/Transaction.h | 76 ++ src/Nervos/TransactionPlan.cpp | 328 +++++++ src/Nervos/TransactionPlan.h | 123 +++ src/Nervos/Witness.cpp | 29 + src/Nervos/Witness.h | 33 + src/interface/TWNervosAddress.cpp | 51 + src/proto/Nervos.proto | 204 ++++ swift/Tests/Blockchains/NervosTests.swift | 123 +++ swift/Tests/CoinAddressDerivationTests.swift | 3 + tests/CoinAddressDerivationTests.cpp | 4 +- tests/Kusama/SignerTests.cpp | 4 +- tests/Nervos/AddressTests.cpp | 88 ++ tests/Nervos/SignerTests.cpp | 929 ++++++++++++++++++ tests/Nervos/TWAnyAddressTests.cpp | 70 ++ tests/Nervos/TWAnySignerTests.cpp | 665 +++++++++++++ tests/Nervos/TWCoinTypeTests.cpp | 35 + tests/Nervos/TWNervosAddressTests.cpp | 32 + tests/Polkadot/AddressTests.cpp | 5 +- tests/Polkadot/SS58AddressTests.cpp | 4 + tests/Polkadot/ScaleCodecTests.cpp | 5 +- tests/Polkadot/SignerTests.cpp | 4 +- tests/Polkadot/TWCoinTypeTests.cpp | 1 - 52 files changed, 4301 insertions(+), 10 deletions(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosAddress.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosSigner.kt create mode 100644 include/TrustWalletCore/TWNervosAddress.h create mode 100644 src/Nervos/Address.cpp create mode 100644 src/Nervos/Address.h create mode 100644 src/Nervos/Cell.h create mode 100644 src/Nervos/CellDep.cpp create mode 100644 src/Nervos/CellDep.h create mode 100644 src/Nervos/CellInput.cpp create mode 100644 src/Nervos/CellInput.h create mode 100644 src/Nervos/CellOutput.cpp create mode 100644 src/Nervos/CellOutput.h create mode 100644 src/Nervos/Constants.h create mode 100644 src/Nervos/Entry.cpp create mode 100644 src/Nervos/Entry.h create mode 100644 src/Nervos/HeaderDep.h create mode 100644 src/Nervos/OutPoint.cpp create mode 100644 src/Nervos/OutPoint.h create mode 100644 src/Nervos/Script.cpp create mode 100644 src/Nervos/Script.h create mode 100644 src/Nervos/Serialization.h create mode 100644 src/Nervos/Signer.cpp create mode 100644 src/Nervos/Signer.h create mode 100644 src/Nervos/Transaction.cpp create mode 100644 src/Nervos/Transaction.h create mode 100644 src/Nervos/TransactionPlan.cpp create mode 100644 src/Nervos/TransactionPlan.h create mode 100644 src/Nervos/Witness.cpp create mode 100644 src/Nervos/Witness.h create mode 100644 src/interface/TWNervosAddress.cpp create mode 100644 src/proto/Nervos.proto create mode 100644 swift/Tests/Blockchains/NervosTests.swift create mode 100644 tests/Nervos/AddressTests.cpp create mode 100644 tests/Nervos/SignerTests.cpp create mode 100644 tests/Nervos/TWAnyAddressTests.cpp create mode 100644 tests/Nervos/TWAnySignerTests.cpp create mode 100644 tests/Nervos/TWCoinTypeTests.cpp create mode 100644 tests/Nervos/TWNervosAddressTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 59170cc4a4d..5973cdd140a 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -103,5 +103,6 @@ class CoinAddressDerivationTests { OSMOSIS -> assertEquals("osmo142j9u5eaduzd7faumygud6ruhdwme98qclefqp", address) ECASH -> assertEquals("ecash:qpelrdn7a0hcucjlf9ascz3lkxv7r3rffgzn6x5377", address) NATIVEEVMOS -> assertEquals("evmos13u6g7vqgw074mgmf2ze2cadzvkz9snlwstd20d", address) + NERVOS -> assertEquals("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02wectaumxn0664yw2jd53lqk4mxg3", address) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosAddress.kt new file mode 100644 index 00000000000..64f1c492ada --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosAddress.kt @@ -0,0 +1,29 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.nervos + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestNervosAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(true) + val address = AnyAddress(pubkey, CoinType.NERVOS) + val expected = AnyAddress("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8furras980hksatlslfaktks7epf25", CoinType.NERVOS) + + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosSigner.kt new file mode 100644 index 00000000000..3d0a149e5ae --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nervos/TestNervosSigner.kt @@ -0,0 +1,69 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.nervos + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* +import wallet.core.jni.CoinType.NERVOS +import wallet.core.jni.proto.Nervos.* +import wallet.core.java.AnySigner + +class TestNervosSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testSigning() { + val key = PrivateKey("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb".toHexByteArray()) + + val lockScript = Script.newBuilder().apply { + codeHash = "9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8".toHexBytesInByteString() + hashType = "type" + args = "c4b50c5c8d074f063ec0a77ded0eaff0fa7b65da".toHexBytesInByteString() + }.build() + + val signingInput = SigningInput.newBuilder().apply { + addPrivateKey(ByteString.copyFrom(key.data())) + byteFee = 1 + nativeTransfer = NativeTransfer.newBuilder().apply { + toAddress = "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02wectaumxn0664yw2jd53lqk4mxg3" + changeAddress = "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqds6ed78yze6eyfyvd537z66ur22c9mmrgz82ama" + amount = 10000000000 + }.build() + addAllCell(listOf( + Cell.newBuilder().apply { + capacity = 100000000000 + outPoint = OutPoint.newBuilder().apply { + txHash = "71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3".toHexBytesInByteString() + index = 1 + }.build() + lock = lockScript + }.build(), + Cell.newBuilder().apply { + capacity = 20000000000 + outPoint = OutPoint.newBuilder().apply { + txHash = "71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3".toHexBytesInByteString() + index = 0 + }.build() + lock = lockScript + }.build() + )) + }.build() + + val output = AnySigner.sign(signingInput, NERVOS, SigningOutput.parser()) + + assertEquals(output.transactionJson, "{\"cell_deps\":[{\"dep_type\":\"dep_group\",\"out_point\":{\"index\":\"0x0\",\"tx_hash\":\"0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c\"}}],\"header_deps\":[],\"inputs\":[{\"previous_output\":{\"index\":\"0x0\",\"tx_hash\":\"0x71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3\"},\"since\":\"0x0\"}],\"outputs\":[{\"capacity\":\"0x2540be400\",\"lock\":{\"args\":\"0xab201f55b02f53b385f79b34dfad548e549b48fc\",\"code_hash\":\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":\"type\"},\"type\":null},{\"capacity\":\"0x2540be230\",\"lock\":{\"args\":\"0xb0d65be39059d6489231b48f85ad706a560bbd8d\",\"code_hash\":\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":\"type\"},\"type\":null}],\"outputs_data\":[\"0x\",\"0x\"],\"version\":\"0x0\",\"witnesses\":[\"0x55000000100000005500000055000000410000002a9ef2ad7829e5ea0c7a32735d29a0cb2ec20434f6fd5bf6e29cda56b28e08140156191cbbf80313d3c9cae4b74607acce7b28eb21d52ef058ed8491cdde70b700\"]}") + assertEquals(output.transactionId, "0xf2c32afde7e72011985583873bc16c0a3c01fc01fc161eb4b914fcf84c53cdf8") + } +} diff --git a/docs/registry.md b/docs/registry.md index 61b971ab738..d6902661ca4 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -32,6 +32,7 @@ This list is generated from [./registry.json](../registry.json) | 242 | Nimiq | NIM | | | | 283 | Algorand | ALGO | | | | 304 | IoTeX | IOTX | | | +| 309 | Nervos | CKB | | | | 313 | Zilliqa | ZIL | | | | 330 | Terra Classic | LUNC | | | | 354 | Polkadot | DOT | | | diff --git a/include/TrustWalletCore/TWBlockchain.h b/include/TrustWalletCore/TWBlockchain.h index 04f8660c5e1..12c6e8f3201 100644 --- a/include/TrustWalletCore/TWBlockchain.h +++ b/include/TrustWalletCore/TWBlockchain.h @@ -51,6 +51,7 @@ enum TWBlockchain { TWBlockchainThorchain = 38, // Cosmos TWBlockchainRonin = 39, // Ethereum TWBlockchainKusama = 40, // Polkadot + TWBlockchainNervos = 41, }; TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 646e444ed73..e23bb380685 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -114,6 +114,7 @@ enum TWCoinType { TWCoinTypeKlaytn = 10008217, TWCoinTypeMeter = 18000, TWCoinTypeOKXChain = 996, + TWCoinTypeNervos = 309, }; /// Returns the blockchain for a coin type. diff --git a/include/TrustWalletCore/TWNervosAddress.h b/include/TrustWalletCore/TWNervosAddress.h new file mode 100644 index 00000000000..cbd095737dc --- /dev/null +++ b/include/TrustWalletCore/TWNervosAddress.h @@ -0,0 +1,50 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +/// Represents a Nervos address. +TW_EXPORT_CLASS +struct TWNervosAddress; + +/// Compares two addresses for equality. +TW_EXPORT_STATIC_METHOD +bool TWNervosAddressEqual(struct TWNervosAddress *_Nonnull lhs, struct TWNervosAddress *_Nonnull rhs); + +/// Determines if the string is a valid Nervos address. +TW_EXPORT_STATIC_METHOD +bool TWNervosAddressIsValidString(TWString *_Nonnull string); + +/// Initializes an address from a sring representaion. +TW_EXPORT_STATIC_METHOD +struct TWNervosAddress *_Nullable TWNervosAddressCreateWithString(TWString *_Nonnull string); + +TW_EXPORT_METHOD +void TWNervosAddressDelete(struct TWNervosAddress *_Nonnull address); + +/// Returns the address base58 string representation. +TW_EXPORT_PROPERTY +TWString *_Nonnull TWNervosAddressDescription(struct TWNervosAddress *_Nonnull address); + +/// Returns the keyhash data. +TW_EXPORT_PROPERTY +TWData *_Nonnull TWNervosAddressCodeHash(struct TWNervosAddress *_Nonnull address); + +/// Returns the address prefix. +TW_EXPORT_PROPERTY +TWString *_Nonnull TWNervosAddressHashType(struct TWNervosAddress *_Nonnull address); + +/// Returns the keyhash data. +TW_EXPORT_PROPERTY +TWData *_Nonnull TWNervosAddressArgs(struct TWNervosAddress *_Nonnull address); + +TW_EXTERN_C_END diff --git a/registry.json b/registry.json index c003b7c593d..7ef1312ff58 100644 --- a/registry.json +++ b/registry.json @@ -856,6 +856,33 @@ "documentation": "https://docs.iotex.io/#api" } }, + { + "id": "nervos", + "name": "Nervos", + "coinId": 309, + "symbol": "CKB", + "decimals": 8, + "blockchain": "Nervos", + "derivation": [ + { + "path": "m/44'/309'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "ckb", + "explorer": { + "url": "https://explorer.nervos.org", + "txPath": "/transaction/", + "accountPath": "/address/" + }, + "info": { + "url": "https://nervos.org", + "source": "https://github.com/nervosnetwork/ckb", + "rpc": "https://mainnet.ckb.dev/rpc", + "documentation": "https://github.com/nervosnetwork/rfcs" + } + }, { "id": "zilliqa", "name": "Zilliqa", diff --git a/src/Coin.cpp b/src/Coin.cpp index 90fc53fe748..609b97db6cd 100644 --- a/src/Coin.cpp +++ b/src/Coin.cpp @@ -36,6 +36,7 @@ #include "NULS/Entry.h" #include "Nano/Entry.h" #include "Nebulas/Entry.h" +#include "Nervos/Entry.h" #include "Nimiq/Entry.h" #include "Oasis/Entry.h" #include "Ontology/Entry.h" @@ -97,6 +98,7 @@ VeChain::Entry vechainDP; Waves::Entry wavesDP; Zcash::Entry zcashDP; Zilliqa::Entry zilliqaDP; +Nervos::Entry NervosDP; // end_of_coin_dipatcher_declarations_marker_do_not_modify CoinEntry* coinDispatcher(TWCoinType coinType) { @@ -144,6 +146,7 @@ CoinEntry* coinDispatcher(TWCoinType coinType) { case TWBlockchainThorchain: entry = &thorchainDP; break; case TWBlockchainRonin: entry = &roninDP; break; case TWBlockchainKusama: entry = &kusamaDP; break; + case TWBlockchainNervos: entry = &NervosDP; break; // end_of_coin_dipatcher_switch_marker_do_not_modify default: entry = nullptr; break; diff --git a/src/Nervos/Address.cpp b/src/Nervos/Address.cpp new file mode 100644 index 00000000000..7740a96657e --- /dev/null +++ b/src/Nervos/Address.cpp @@ -0,0 +1,177 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Address.h" +#include "Constants.h" + +#include "../Bech32.h" +#include "../Coin.h" + +#include +#include +#include + +namespace TW::Nervos { + +[[nodiscard]] bool Address::isValid(const std::string& string) noexcept { + return Address::isValid(string, HRP_NERVOS); +} + +[[nodiscard]] bool Address::isValid(const std::string& string, const char* hrp) noexcept { + return Address().decode(string, hrp); +} + +Address::Address(const std::string& string, const char* hrp) { + if (!decode(string, hrp)) { + throw std::invalid_argument("Invalid address string"); + } +} + +bool Address::decode(const std::string& string, const char* hrp) noexcept { + _hrp = hrp; + auto decoded = Bech32::decode(string); + auto&& [decodedHrp, decodedData, decodedVariant] = decoded; + if (decodedHrp.compare(hrp)) { + return false; + } + Data decodedPayload; + if (!Bech32::convertBits<5, 8, false>(decodedPayload, decodedData)) { + return false; + } + if (decodedPayload.empty()) { + return false; + } + addressType = AddressType(decodedPayload[0]); + switch (addressType) { + case AddressType::FullVersion: { + size_t codeHashOffset = 1; + size_t codeHashSize = 32; + size_t hashTypeOffset = codeHashOffset + codeHashSize; + size_t hashTypeSize = 1; + size_t argsOffset = hashTypeOffset + hashTypeSize; + if (decodedVariant != Bech32::ChecksumVariant::Bech32M) { + return false; + } + if (decodedPayload.size() < argsOffset) { + return false; + } + codeHashIndex = -1; + codeHash = Data(decodedPayload.begin() + codeHashOffset, + decodedPayload.begin() + codeHashOffset + codeHashSize); + hashType = HashType(decodedPayload[hashTypeOffset]); + args = Data(decodedPayload.begin() + argsOffset, decodedPayload.end()); + break; + } + case AddressType::HashIdx: { + size_t codeHashIndexOffset = 1; + size_t codeHashIndexSize = 1; + size_t argsOffset = codeHashIndexOffset + codeHashIndexSize; + size_t argsSize = 20; + if (decodedVariant != Bech32::ChecksumVariant::Bech32) { + return false; + } + if (decodedPayload.size() != argsOffset + argsSize) { + return false; + } + codeHashIndex = decodedPayload[codeHashIndexOffset]; + if (codeHashIndex != 0) { + return false; + } + codeHash = Constants::gSecp256k1CodeHash; + hashType = HashType::Type1; + args = Data(decodedPayload.begin() + argsOffset, decodedPayload.end()); + break; + } + case AddressType::DataCodeHash: + case AddressType::TypeCodeHash: { + size_t codeHashOffset = 1; + size_t codeHashSize = 32; + size_t argsOffset = codeHashOffset + codeHashSize; + if (decodedVariant != Bech32::ChecksumVariant::Bech32) { + return false; + } + if (decodedPayload.size() < argsOffset) { + return false; + } + codeHashIndex = -1; + codeHash = Data(decodedPayload.begin() + codeHashOffset, + decodedPayload.begin() + codeHashOffset + codeHashSize); + hashType = addressType == AddressType::DataCodeHash ? HashType::Data0 : HashType::Type1; + args = Data(decodedPayload.begin() + argsOffset, decodedPayload.end()); + break; + } + default: { + return false; + } + } + return true; +} + +Address::Address(const PublicKey& publicKey, const char* hrp) + : _hrp(hrp) { + if (publicKey.type != TWPublicKeyTypeSECP256k1) { + throw std::invalid_argument("Nervos::Address needs a SECP256k1 public key."); + } + addressType = AddressType::FullVersion; + codeHashIndex = -1; + codeHash = Constants::gSecp256k1CodeHash; + hashType = HashType::Type1; + Data publicKeyHash = Hash::blake2b(publicKey.bytes, 32, Constants::gHashPersonalization); + Data truncatedPublicKeyHash = Data(publicKeyHash.begin(), publicKeyHash.begin() + 20); + args = truncatedPublicKeyHash; +} + +std::string Address::string() const { + auto data = Data(); + data.emplace_back(addressType); + Bech32::ChecksumVariant checksumVariant; + switch (addressType) { + case AddressType::FullVersion: { + data.insert(data.end(), codeHash.begin(), codeHash.end()); + data.emplace_back(hashType); + data.insert(data.end(), args.begin(), args.end()); + checksumVariant = Bech32::ChecksumVariant::Bech32M; + break; + } + case AddressType::HashIdx: { + data.emplace_back(codeHashIndex); + data.insert(data.end(), args.begin(), args.end()); + checksumVariant = Bech32::ChecksumVariant::Bech32; + break; + } + case AddressType::DataCodeHash: + case AddressType::TypeCodeHash: { + data.insert(data.end(), codeHash.begin(), codeHash.end()); + data.insert(data.end(), args.begin(), args.end()); + checksumVariant = Bech32::ChecksumVariant::Bech32; + break; + } + default: { + return ""; + } + } + Data payload; + if (!Bech32::convertBits<8, 5, true>(payload, data)) { + return ""; + } + return Bech32::encode(_hrp, payload, checksumVariant); +} + +std::string Address::hashTypeString() const { + switch (hashType) { + case HashType::Data0: { + return HashTypeString[0]; + } + case HashType::Type1: { + return HashTypeString[1]; + } + case HashType::Data1: { + return HashTypeString[2]; + } + } +} + +} // namespace TW::Nervos diff --git a/src/Nervos/Address.h b/src/Nervos/Address.h new file mode 100644 index 00000000000..a31de6349e0 --- /dev/null +++ b/src/Nervos/Address.h @@ -0,0 +1,80 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include + +#include "../Data.h" +#include "../PublicKey.h" + +#include + +namespace TW::Nervos { + +enum HashType { + Data0 = 0, + Type1 = 1, + Data1 = 2 +}; + +static const char* HashTypeString[] { + "data", + "type", + "data1" +}; + +enum AddressType { + FullVersion = 0, // full version identifies the hash_type + HashIdx = 1, // short version for locks with popular codehash, deprecated + DataCodeHash = 2, // full version with hash type 'Data', deprecated + TypeCodeHash = 4, // full version with hash type 'Type', deprecated +}; + +class Address { +public: + const char* _hrp; + AddressType addressType; + TW::byte codeHashIndex; + Data codeHash; + HashType hashType; + Data args; + + /// Determines whether a string makes a valid address. + [[nodiscard]] static bool isValid(const std::string& string) noexcept; + [[nodiscard]] static bool isValid(const std::string& string, const char* hrp) noexcept; + + /// Initializes a Nervos address with a string representation. + explicit Address(const std::string& string) : Address(string, HRP_NERVOS) {} + explicit Address(const std::string& string, const char* hrp); + + /// Initializes a Nervos address with a public key. + explicit Address(const PublicKey& publicKey) : Address(publicKey, HRP_NERVOS) {} + explicit Address(const PublicKey& publicKey, const char* hrp); + + /// Returns a string representation of the address. + std::string string() const; + + std::string hashTypeString() const; + +private: + Address() = default; + + // Decodes address from string + bool decode(const std::string& string, const char* hrp) noexcept; +}; + +inline bool operator==(const Address& lhs, const Address& rhs) { + return (lhs.codeHash == rhs.codeHash) && (lhs.hashType == rhs.hashType) && + (lhs.args == rhs.args); +} + +} // namespace TW::Nervos + +/// Wrapper for C interface. +struct TWNervosAddress { + TW::Nervos::Address impl; +}; diff --git a/src/Nervos/Cell.h b/src/Nervos/Cell.h new file mode 100644 index 00000000000..750f1b0fc58 --- /dev/null +++ b/src/Nervos/Cell.h @@ -0,0 +1,108 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "OutPoint.h" +#include "Script.h" +#include "../proto/Nervos.pb.h" + +#include + +namespace TW::Nervos { + +struct Cell { + OutPoint outPoint; + uint64_t capacity; + Script lock; + Script type; + Data data; + uint64_t blockNumber; + Data blockHash; + uint64_t since; + Data inputType; + Data outputType; + + Cell() = default; + + // Copy constructor + Cell(const Cell& cell) + : outPoint(cell.outPoint) + , capacity(cell.capacity) + , lock(cell.lock) + , type(cell.type) + , data(cell.data) + , blockNumber(cell.blockNumber) + , blockHash(cell.blockHash) + , since(cell.since) + , inputType(cell.inputType) + , outputType(cell.outputType) {} + + // Move constructor + Cell(Cell&& cell) + : outPoint(std::move(cell.outPoint)) + , capacity(cell.capacity) + , lock(std::move(cell.lock)) + , type(std::move(cell.type)) + , data(std::move(cell.data)) + , blockNumber(cell.blockNumber) + , blockHash(std::move(cell.blockHash)) + , since(cell.since) + , inputType(std::move(cell.inputType)) + , outputType(std::move(cell.outputType)) {} + + // Copy assignment operator + Cell& operator=(const Cell& cell) { + outPoint = cell.outPoint; + capacity = cell.capacity; + lock = cell.lock; + type = cell.type; + data = cell.data; + blockNumber = cell.blockNumber; + blockHash = cell.blockHash; + since = cell.since; + inputType = cell.inputType; + outputType = cell.outputType; + return *this; + } + + Cell(const Proto::Cell& cell) + : outPoint(cell.out_point()) + , capacity(cell.capacity()) + , lock(cell.lock()) + , type(cell.type()) + , blockNumber(cell.block_number()) + , since(cell.since()) { + auto&& cellData = cell.data(); + data.insert(data.end(), cellData.begin(), cellData.end()); + auto&& cellBlockHash = cell.block_hash(); + blockHash.insert(blockHash.end(), cellBlockHash.begin(), cellBlockHash.end()); + auto&& cellInputType = cell.input_type(); + inputType.insert(inputType.end(), cellInputType.begin(), cellInputType.end()); + auto&& cellOutputType = cell.output_type(); + outputType.insert(outputType.end(), cellOutputType.begin(), cellOutputType.end()); + } + + Proto::Cell proto() const { + auto cell = Proto::Cell(); + *cell.mutable_out_point() = outPoint.proto(); + cell.set_capacity(capacity); + *cell.mutable_lock() = lock.proto(); + *cell.mutable_type() = type.proto(); + cell.set_data(std::string(data.begin(), data.end())); + cell.set_block_number(blockNumber); + cell.set_block_hash(std::string(blockHash.begin(), blockHash.end())); + cell.set_since(since); + cell.set_input_type(std::string(inputType.begin(), inputType.end())); + cell.set_output_type(std::string(outputType.begin(), outputType.end())); + return cell; + } +}; + +/// A list of Cell's +using Cells = std::vector; + +} // namespace TW::Nervos diff --git a/src/Nervos/CellDep.cpp b/src/Nervos/CellDep.cpp new file mode 100644 index 00000000000..9b07566d121 --- /dev/null +++ b/src/Nervos/CellDep.cpp @@ -0,0 +1,38 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "CellDep.h" +#include "Constants.h" + +#include "../BinaryCoding.h" + +using namespace TW::Nervos; + +CellDep::CellDep(const Proto::CellDep& cellDep) + : outPoint(cellDep.out_point()) { + auto&& depTypeString = cellDep.dep_type(); + for (int i = 0; i < (int)(sizeof(DepTypeString) / sizeof(DepTypeString[0])); i++) { + if (depTypeString == DepTypeString[i]) { + depType = (DepType)i; + } + } +} + +Proto::CellDep CellDep::proto() const { + auto cellDep = Proto::CellDep(); + *cellDep.mutable_out_point() = outPoint.proto(); + cellDep.set_dep_type(DepTypeString[depType]); + return cellDep; +} + +void CellDep::encode(Data& data) const { + outPoint.encode(data); + data.emplace_back(depType); +} + +nlohmann::json CellDep::json() const { + return nlohmann::json{{"out_point", outPoint.json()}, {"dep_type", DepTypeString[depType]}}; +} diff --git a/src/Nervos/CellDep.h b/src/Nervos/CellDep.h new file mode 100644 index 00000000000..9318017803e --- /dev/null +++ b/src/Nervos/CellDep.h @@ -0,0 +1,45 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "OutPoint.h" +#include "../proto/Nervos.pb.h" +#include + +namespace TW::Nervos { + +enum DepType { + Code = 0, + DepGroup = 1 +}; + +static const char* DepTypeString[] { + "code", + "dep_group" +}; + +/// Nervos cell dep. +struct CellDep { + OutPoint outPoint; + DepType depType; + + /// Initializes a cell dep with a previous output and depType + CellDep(OutPoint outPoint, DepType depType) : outPoint(std::move(outPoint)), depType(depType) {} + + CellDep(const Proto::CellDep& cellDep); + + /// Encodes the transaction into the provided buffer. + void encode(Data& data) const; + nlohmann::json json() const; + + Proto::CellDep proto() const; +}; + +/// A list of Cell Deps +using CellDeps = std::vector; + +} // namespace TW::Nervos diff --git a/src/Nervos/CellInput.cpp b/src/Nervos/CellInput.cpp new file mode 100644 index 00000000000..f0c6298b6f1 --- /dev/null +++ b/src/Nervos/CellInput.cpp @@ -0,0 +1,23 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "CellInput.h" +#include "Serialization.h" + +#include "../BinaryCoding.h" +#include "../HexCoding.h" + +using namespace TW::Nervos; + +void CellInput::encode(Data& data) const { + encode64LE(since, data); + previousOutput.encode(data); +} + +nlohmann::json CellInput::json() const { + return nlohmann::json{{"previous_output", previousOutput.json()}, + {"since", Serialization::numberToHex(since)}}; +} diff --git a/src/Nervos/CellInput.h b/src/Nervos/CellInput.h new file mode 100644 index 00000000000..afb8488cf05 --- /dev/null +++ b/src/Nervos/CellInput.h @@ -0,0 +1,36 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "OutPoint.h" +#include + +namespace TW::Nervos { + +/// Nervos cell input. +struct CellInput { + /// Reference to the previous transaction's output. + OutPoint previousOutput; + + /// Prevents the transaction to be mined before an absolute or relative time. + uint64_t since; + + /// Initializes a cell input with a previous output and since + CellInput(OutPoint previousOutput, uint64_t since) + : previousOutput(std::move(previousOutput)), since(since) {} + + /// Encodes the transaction into the provided buffer. + void encode(Data& data) const; + + /// Encodes the output into json format. + nlohmann::json json() const; +}; + +/// A list of Cell Inputs +using CellInputs = std::vector; + +} // namespace TW::Nervos diff --git a/src/Nervos/CellOutput.cpp b/src/Nervos/CellOutput.cpp new file mode 100644 index 00000000000..0af131ee645 --- /dev/null +++ b/src/Nervos/CellOutput.cpp @@ -0,0 +1,29 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "CellOutput.h" +#include "Serialization.h" + +#include "Serialization.h" +#include "../BinaryCoding.h" + +using namespace TW::Nervos; + +void CellOutput::encode(Data& data) const { + Data capacityData; + Data lockData; + Data typeData; + encode64LE(capacity, capacityData); + lock.encode(lockData); + type.encode(typeData); + Serialization::encodeDataArray(std::vector{capacityData, lockData, typeData}, data); +} + +nlohmann::json CellOutput::json() const { + return nlohmann::json{{"capacity", Serialization::numberToHex(capacity)}, + {"lock", lock.json()}, + {"type", type.json()}}; +} diff --git a/src/Nervos/CellOutput.h b/src/Nervos/CellOutput.h new file mode 100644 index 00000000000..2b8f85af9a2 --- /dev/null +++ b/src/Nervos/CellOutput.h @@ -0,0 +1,53 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Script.h" +#include "../Data.h" +#include "../proto/Nervos.pb.h" +#include + +#include + +namespace TW::Nervos { + +/// Nervos cell output. +struct CellOutput { + uint64_t capacity; + Script lock; + Script type; + + /// Initializes an empty cell output. + CellOutput() = default; + + /// Initializes a cell output with a capacity and scripts. + CellOutput(uint64_t capacity, Script&& lock, Script&& type) + : capacity(capacity), lock(std::move(lock)), type(std::move(type)) {} + + /// Initializes a CellInput from a Protobuf CellInput. + CellOutput(const Proto::CellOutput& cellOutput) + : capacity(cellOutput.capacity()), lock(cellOutput.lock()), type(cellOutput.type()) {} + + /// Encodes the output into the provided buffer. + void encode(Data& data) const; + + /// Encodes the output into json format. + nlohmann::json json() const; + + Proto::CellOutput proto() const { + auto cellOutput = Proto::CellOutput(); + cellOutput.set_capacity(capacity); + *cellOutput.mutable_lock() = lock.proto(); + *cellOutput.mutable_type() = type.proto(); + return cellOutput; + } +}; + +/// A list of Cell Outputs +using CellOutputs = std::vector; + +} // namespace TW::Nervos diff --git a/src/Nervos/Constants.h b/src/Nervos/Constants.h new file mode 100644 index 00000000000..d128c7d581e --- /dev/null +++ b/src/Nervos/Constants.h @@ -0,0 +1,53 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Address.h" +#include "CellDep.h" +#include "OutPoint.h" +#include "../Data.h" +#include "../HexCoding.h" + +#include +#include + +namespace TW::Nervos::Constants { + +static const uint64_t gTransactionBaseSize = 72; +static const uint64_t gCellDepSize = 37; +static const uint64_t gHeaderDepSize = 32; +static const uint64_t gSingleInputAndWitnessBaseSize = 44; +static const uint64_t gBlankWitnessBytes = 65; +static const uint64_t gUint32Size = 4; +static const uint64_t gMinCellCapacityForNativeToken = 6100000000; +static const uint64_t gMinCellCapacityForSUDT = 14400000000; + +static const Data gHashPersonalization{'c', 'k', 'b', '-', 'd', 'e', 'f', 'a', + 'u', 'l', 't', '-', 'h', 'a', 's', 'h'}; + +static const Data gSecp256k1CodeHash = + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8"); + +static const CellDep gSecp256k1CellDep = CellDep( + OutPoint(parse_hex("71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c"), 0), + DepType::DepGroup); + +static const Data gSUDTCodeHash = + parse_hex("5e7a36a77e68eecc013dfa2fe6a23f3b6c344b04005808694ae6dd45eea4cfd5"); + +static const CellDep gSUDTCellDep = CellDep( + OutPoint(parse_hex("c7813f6a415144643970c2e88e0bb6ca6a8edc5dd7c1022746f628284a9936d5"), 0), + DepType::Code); + +static const Data gDAOCodeHash = + parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e"); + +static const CellDep gDAOCellDep = CellDep( + OutPoint(parse_hex("e2fb199810d49a4d8beec56718ba2593b665db9d52299a0f9e6e75416d73ff5c"), 2), + DepType::Code); + +} // namespace TW::Nervos::Constants diff --git a/src/Nervos/Entry.cpp b/src/Nervos/Entry.cpp new file mode 100644 index 00000000000..44e725ae6a3 --- /dev/null +++ b/src/Nervos/Entry.cpp @@ -0,0 +1,33 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Entry.h" + +#include "Address.h" +#include "Signer.h" + +namespace TW::Nervos { +using namespace std; + +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, byte, byte, + const char* hrp) const { + return Address::isValid(address, hrp); +} + +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, byte, + const char* hrp) const { + return Address(publicKey, hrp).string(); +} + +void Entry::sign([[maybe_unused]] TWCoinType coin, const Data& dataIn, Data& dataOut) const { + signTemplate(dataIn, dataOut); +} + +void Entry::plan([[maybe_unused]] TWCoinType coin, const Data& dataIn, Data& dataOut) const { + planTemplate(dataIn, dataOut); +} + +} // namespace TW::Nervos diff --git a/src/Nervos/Entry.h b/src/Nervos/Entry.h new file mode 100644 index 00000000000..a7ea1a5376a --- /dev/null +++ b/src/Nervos/Entry.h @@ -0,0 +1,28 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "../CoinEntry.h" + +using namespace TW; + +namespace TW::Nervos { + +/// Entry point for implementation of Nervos coin. +/// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific +/// includes in this file +class Entry : public CoinEntry { +public: + bool validateAddress(TWCoinType coin, const std::string& address, byte p2pkh, byte p2sh, + const char* hrp) const final; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, byte p2pkh, + const char* hrp) const final; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const final; + void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const final; +}; + +} // namespace TW::Nervos diff --git a/src/Nervos/HeaderDep.h b/src/Nervos/HeaderDep.h new file mode 100644 index 00000000000..af94b115db8 --- /dev/null +++ b/src/Nervos/HeaderDep.h @@ -0,0 +1,19 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include + +namespace TW::Nervos { + +using HeaderDep = Data; + +/// A list of header deps +using HeaderDeps = std::vector; + +} // namespace TW::Nervos diff --git a/src/Nervos/OutPoint.cpp b/src/Nervos/OutPoint.cpp new file mode 100644 index 00000000000..2a04632b586 --- /dev/null +++ b/src/Nervos/OutPoint.cpp @@ -0,0 +1,23 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "OutPoint.h" +#include "Serialization.h" + +#include "../BinaryCoding.h" +#include "../HexCoding.h" + +using namespace TW::Nervos; + +void OutPoint::encode(Data& data) const { + data.insert(data.end(), txHash.begin(), txHash.end()); + encode32LE(index, data); +} + +nlohmann::json OutPoint::json() const { + return nlohmann::json{{"tx_hash", hexEncoded(txHash)}, + {"index", Serialization::numberToHex(uint64_t(index))}}; +} diff --git a/src/Nervos/OutPoint.h b/src/Nervos/OutPoint.h new file mode 100644 index 00000000000..a37d5a4e38b --- /dev/null +++ b/src/Nervos/OutPoint.h @@ -0,0 +1,54 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "../Data.h" +#include "../proto/Nervos.pb.h" +#include + +#include +#include +#include + +namespace TW::Nervos { + +/// Nervos transaction out-point reference. +struct OutPoint { + /// The hash of the referenced transaction. + Data txHash; + + /// The index of the specific output in the transaction. + uint32_t index; + + OutPoint() = default; + + /// Initializes an out-point reference with hash, index. + template + OutPoint(const T& h, uint32_t index) : txHash(std::begin(h), std::end(h)), index(index) {} + + /// Initializes an out-point from a Protobuf out-point. + OutPoint(const Proto::OutPoint& outPoint) + : txHash(std::begin(outPoint.tx_hash()), std::end(outPoint.tx_hash())) + , index(outPoint.index()) {} + + /// Encodes the out-point into the provided buffer. + void encode(Data& data) const; + nlohmann::json json() const; + + friend bool operator==(const OutPoint& lhs, const OutPoint& rhs) { + return (lhs.txHash == rhs.txHash && lhs.index == rhs.index); + } + + Proto::OutPoint proto() const { + auto outPoint = Proto::OutPoint(); + outPoint.set_tx_hash(std::string(txHash.begin(), txHash.end())); + outPoint.set_index(index); + return outPoint; + } +}; + +} // namespace TW::Nervos diff --git a/src/Nervos/Script.cpp b/src/Nervos/Script.cpp new file mode 100644 index 00000000000..d70ebb35f08 --- /dev/null +++ b/src/Nervos/Script.cpp @@ -0,0 +1,52 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Script.h" +#include "Constants.h" +#include "Serialization.h" + +#include "../Bech32.h" +#include "../BinaryCoding.h" +#include "../Data.h" + +#include +#include +#include + +using namespace TW; +using namespace TW::Nervos; + +Data Script::hash() const { + Data data; + encode(data); + return Hash::blake2b(data, 32, Constants::gHashPersonalization); +} + +[[nodiscard]] bool Script::empty() const { + return std::all_of(codeHash.begin(), codeHash.end(), [](byte element) { return element == 0; }); +} + +void Script::encode(Data& data) const { + Data hashTypeData(1); + Data argsData; + if (empty()) { + return; + } + hashTypeData[0] = hashType; + encode32LE(uint32_t(args.size()), argsData); + argsData.insert(argsData.end(), args.begin(), args.end()); + Serialization::encodeDataArray(std::vector{codeHash, hashTypeData, argsData}, data); +} + +nlohmann::json Script::json() const { + if (empty()) { + return nullptr; + } else { + return nlohmann::json{{"code_hash", hexEncoded(codeHash)}, + {"hash_type", HashTypeString[hashType]}, + {"args", hexEncoded(args)}}; + } +} diff --git a/src/Nervos/Script.h b/src/Nervos/Script.h new file mode 100644 index 00000000000..8f22bdf119e --- /dev/null +++ b/src/Nervos/Script.h @@ -0,0 +1,107 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Address.h" +#include "Constants.h" +#include "../Data.h" +#include "../proto/Nervos.pb.h" +#include + +#include +#include + +namespace TW::Nervos { + +struct Script { + Data codeHash; + HashType hashType; + Data args; + + /// Initializes an empty script. + Script() { + hashType = HashType::Data0; + } + + /// Copy constructor + Script(const Script& script) + : codeHash(script.codeHash), hashType(script.hashType), args(script.args) {} + + /// Move constructor + Script(Script&& script) + : codeHash(std::move(script.codeHash)) + , hashType(script.hashType) + , args(std::move(script.args)) {} + + /// Initializes a script with codeHash, args and hashType. + Script(const Data& codeHash, const HashType hashType, const Data& args) + : codeHash(codeHash), hashType(hashType), args(args) {} + + /// Initializes a script with the given address. + Script(const Address& address) + : codeHash(address.codeHash), hashType(address.hashType), args(address.args) {} + + // Copy assignment operator + Script& operator=(const Script& script) { + codeHash = script.codeHash; + hashType = script.hashType; + args = script.args; + return *this; + } + + // Move assignment operator + Script& operator=(Script&& script) { + codeHash = std::move(script.codeHash); + hashType = script.hashType; + args = std::move(script.args); + return *this; + } + + friend bool operator==(const Script& lhs, const Script& rhs) { + return (lhs.codeHash == rhs.codeHash) && (lhs.hashType == rhs.hashType) && + (lhs.args == rhs.args); + } + + friend bool operator!=(const Script& lhs, const Script& rhs) { return !(lhs == rhs); } + + /// Returns the script's script hash. + Data hash() const; + + /// Whether the script is empty. + [[nodiscard]] bool empty() const; + + /// Initializes an script from a Protobuf script. + Script(const Proto::Script& script) { + auto&& scriptCodeHash = script.code_hash(); + codeHash.insert(codeHash.end(), scriptCodeHash.begin(), scriptCodeHash.end()); + auto&& hashTypeString = script.hash_type(); + hashType = HashType::Data0; + for (int i = 0; i < (int)(sizeof(HashTypeString) / sizeof(HashTypeString[0])); i++) { + if (hashTypeString == HashTypeString[i]) { + hashType = (HashType)i; + } + } + auto&& scriptArgs = script.args(); + args.insert(args.end(), scriptArgs.begin(), scriptArgs.end()); + } + + /// Encodes the script. + void encode(Data& data) const; + + /// Encodes the script into json format. + nlohmann::json json() const; + + Proto::Script proto() const { + auto script = Proto::Script(); + script.set_code_hash(std::string(codeHash.begin(), codeHash.end())); + script.set_hash_type(HashTypeString[hashType]); + script.set_args(std::string(args.begin(), args.end())); + return script; + } +}; + +} // namespace TW::Nervos diff --git a/src/Nervos/Serialization.h b/src/Nervos/Serialization.h new file mode 100644 index 00000000000..99c62b50dc0 --- /dev/null +++ b/src/Nervos/Serialization.h @@ -0,0 +1,60 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "../BinaryCoding.h" +#include "../Data.h" +#include "../HexCoding.h" +#include "../uint256.h" + +#include +#include + +namespace TW::Nervos { + +struct Serialization { + static void encodeDataArray(const std::vector& dataArray, Data& data) { + uint32_t dataLength = std::accumulate(dataArray.begin(), dataArray.end(), uint32_t(0), + [](const uint32_t total, const Data& element) { + return total + uint32_t(element.size()); + }); + uint32_t headerLength = 4 + 4 * uint32_t(dataArray.size()); + uint32_t fullLength = headerLength + dataLength; + encode32LE(fullLength, data); + std::accumulate(dataArray.begin(), dataArray.end(), headerLength, + [&data](const uint32_t offset, const Data& element) { + encode32LE(offset, data); + return offset + uint32_t(element.size()); + }); + for (auto&& element : dataArray) { + data.insert(data.end(), element.begin(), element.end()); + } + } + + static Data encodeUint256(uint256_t number, byte minLen = 0) { + auto data = store(number, minLen); + std::reverse(data.begin(), data.end()); + return data; + } + + static uint256_t decodeUint256(const Data& data) { + auto data1 = Data(data); + std::reverse(data1.begin(), data1.end()); + return load(data1); + } + + static std::string numberToHex(uint64_t number) { + auto str = hex(number); + str.erase(0, str.find_first_not_of('0')); + if (str.length() == 0) { + return "0x0"; + } else { + return str.insert(0, "0x"); + } + } +}; +} // namespace TW::Nervos diff --git a/src/Nervos/Signer.cpp b/src/Nervos/Signer.cpp new file mode 100644 index 00000000000..1191f6fbd0a --- /dev/null +++ b/src/Nervos/Signer.cpp @@ -0,0 +1,54 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Signer.h" +#include "Transaction.h" +#include "TransactionPlan.h" + +using namespace TW; +using namespace TW::Nervos; + +Proto::TransactionPlan Signer::plan(const Proto::SigningInput& signingInput) noexcept { + TransactionPlan txPlan; + txPlan.plan(signingInput); + return txPlan.proto(); +} + +Proto::SigningOutput Signer::sign(const Proto::SigningInput& signingInput) noexcept { + Proto::SigningOutput output; + + TransactionPlan txPlan; + if (signingInput.has_plan()) { + txPlan = TransactionPlan(signingInput.plan()); + } else { + txPlan.plan(signingInput); + } + if (txPlan.error != Common::Proto::OK) { + // Planning failed + output.set_error(txPlan.error); + return output; + } + + Transaction tx; + tx.build(txPlan); + std::vector privateKeys; + privateKeys.reserve(signingInput.private_key_size()); + for (auto&& privateKey : signingInput.private_key()) { + privateKeys.emplace_back(privateKey); + } + auto error = tx.sign(privateKeys); + if (error != Common::Proto::OK) { + // Signing failed + output.set_error(error); + return output; + } + + output.set_transaction_json(tx.json().dump()); + output.set_transaction_id(hexEncoded(tx.hash())); + output.set_error(Common::Proto::OK); + + return output; +} diff --git a/src/Nervos/Signer.h b/src/Nervos/Signer.h new file mode 100644 index 00000000000..7c7c0c1d279 --- /dev/null +++ b/src/Nervos/Signer.h @@ -0,0 +1,26 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "CoinEntry.h" +#include "Data.h" +#include "../proto/Nervos.pb.h" + +namespace TW::Nervos { + +class Signer { +public: + Signer() = delete; + + /// Returns a transaction plan (utxo selection, fee estimation) + static Proto::TransactionPlan plan(const Proto::SigningInput& signingInputProto) noexcept; + + /// Signs a Proto::SigningInput transaction + static Proto::SigningOutput sign(const Proto::SigningInput& signingInputProto) noexcept; +}; + +} // namespace TW::Nervos diff --git a/src/Nervos/Transaction.cpp b/src/Nervos/Transaction.cpp new file mode 100644 index 00000000000..8e00e953efc --- /dev/null +++ b/src/Nervos/Transaction.cpp @@ -0,0 +1,215 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Transaction.h" +#include "Constants.h" +#include "Serialization.h" +#include "../BinaryCoding.h" +#include "../HexCoding.h" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace TW; +using namespace TW::Nervos; + +Data Transaction::hash() const { + Data data; + std::vector dataArray; + dataArray.reserve(6); + + // version + Data versionData; + encode32LE(version, versionData); + dataArray.emplace_back(versionData); + + // cell deps + Data cellDepsData; + encode32LE(uint32_t(cellDeps.size()), cellDepsData); + for (auto&& cellDep : cellDeps) { + cellDep.encode(cellDepsData); + } + dataArray.emplace_back(cellDepsData); + + // header deps + Data headerDepsData; + encode32LE(uint32_t(headerDeps.size()), headerDepsData); + for (auto&& headerDep : headerDeps) { + headerDepsData.insert(headerDepsData.end(), headerDep.begin(), headerDep.end()); + } + dataArray.emplace_back(headerDepsData); + + // inputs + Data inputsData; + encode32LE(uint32_t(inputs.size()), inputsData); + for (auto&& input : inputs) { + input.encode(inputsData); + } + dataArray.emplace_back(inputsData); + + // outputs + Data outputsData1; + std::vector outputsData1Array; + outputsData1Array.reserve(outputs.size()); + for (auto&& output : outputs) { + Data outputData1; + output.encode(outputData1); + outputsData1Array.emplace_back(outputData1); + } + Serialization::encodeDataArray(outputsData1Array, outputsData1); + dataArray.emplace_back(outputsData1); + + // outputs data + Data outputsData2; + std::vector outputsData2Array; + outputsData2Array.reserve(outputsData.size()); + for (auto&& outputData : outputsData) { + Data outputData2; + encode32LE(uint32_t(outputData.size()), outputData2); + outputData2.insert(outputData2.end(), outputData.begin(), outputData.end()); + outputsData2Array.emplace_back(outputData2); + } + Serialization::encodeDataArray(outputsData2Array, outputsData2); + dataArray.emplace_back(outputsData2); + + Serialization::encodeDataArray(dataArray, data); + + return Hash::blake2b(data, 32, Constants::gHashPersonalization); +} + +nlohmann::json Transaction::json() const { + auto json = nlohmann::json(); + json["version"] = "0x0"; + auto cellDepsJSON = nlohmann::json::array(); + for (auto&& cellDep : cellDeps) { + cellDepsJSON.push_back(cellDep.json()); + } + json["cell_deps"] = cellDepsJSON; + auto headerDepsJSON = nlohmann::json::array(); + for (auto&& headerDep : headerDeps) { + headerDepsJSON.push_back(hexEncoded(headerDep)); + } + json["header_deps"] = headerDepsJSON; + auto inputsJSON = nlohmann::json::array(); + for (auto&& input : inputs) { + inputsJSON.push_back(input.json()); + } + json["inputs"] = inputsJSON; + auto outputsJSON = nlohmann::json::array(); + for (auto&& output : outputs) { + outputsJSON.push_back(output.json()); + } + json["outputs"] = outputsJSON; + auto outputsDataJSON = nlohmann::json::array(); + for (auto&& outputData : outputsData) { + outputsDataJSON.push_back(hexEncoded(outputData)); + } + json["outputs_data"] = outputsDataJSON; + auto witnessesJSON = nlohmann::json::array(); + for (auto&& serializedWitness : serializedWitnesses) { + witnessesJSON.push_back(hexEncoded(serializedWitness)); + } + json["witnesses"] = witnessesJSON; + return json; +} + +void Transaction::build(const TransactionPlan& txPlan) { + cellDeps = txPlan.cellDeps; + headerDeps = txPlan.headerDeps; + selectedCells = txPlan.selectedCells; + outputs = txPlan.outputs; + outputsData = txPlan.outputsData; + for (auto&& cell : selectedCells) { + inputs.emplace_back(cell.outPoint, cell.since); + } +} + +Common::Proto::SigningError Transaction::sign(const std::vector& privateKeys) { + formGroups(); + return signGroups(privateKeys); +} + +void Transaction::formGroups() { + for (size_t index = 0; index < selectedCells.size(); index++) { + auto&& cell = selectedCells[index]; + auto lockHash = cell.lock.hash(); + int groupNum = -1; + for (size_t groupNum1 = 0; groupNum1 < m_groupNumToLockHash.size(); groupNum1++) { + if (lockHash == m_groupNumToLockHash[groupNum1]) { + // Group found. Add to existing group. + groupNum = int(groupNum1); + break; + } + } + if (groupNum == -1) { + // Group not found. Create new group. + groupNum = int(m_groupNumToLockHash.size()); + m_groupNumToLockHash.emplace_back(lockHash); + m_groupNumToInputIndices.emplace_back(); + m_groupNumToWitnesses.emplace_back(); + } + m_groupNumToInputIndices[groupNum].emplace_back(index); + m_groupNumToWitnesses[groupNum].emplace_back(Data(), cell.inputType, cell.outputType); + serializedWitnesses.emplace_back(); + } +} + +Common::Proto::SigningError Transaction::signGroups(const std::vector& privateKeys) { + const Data txHash = hash(); + for (size_t groupNum = 0; groupNum < m_groupNumToLockHash.size(); groupNum++) { + auto&& cell = selectedCells[m_groupNumToInputIndices[groupNum][0]]; + const PrivateKey* privateKey = nullptr; + for (auto&& privateKey1 : privateKeys) { + auto publicKey1 = privateKey1.getPublicKey(TWPublicKeyTypeSECP256k1); + auto address = Address(publicKey1, HRP_NERVOS); + auto script = Script(address); + if (script == cell.lock) { + privateKey = &privateKey1; + break; + } + } + if (!privateKey) { + return Common::Proto::Error_missing_private_key; + } + auto result = signWitnesses(*privateKey, txHash, m_groupNumToWitnesses[groupNum]); + if (result != Common::Proto::OK) { + return result; + } + m_groupNumToWitnesses[groupNum][0].encode(serializedWitnesses[m_groupNumToInputIndices[groupNum][0]]); + } + return Common::Proto::OK; +} + +Common::Proto::SigningError Transaction::signWitnesses(const PrivateKey& privateKey, + const Data& txHash, Witnesses& witnesses) { + Data message; + message.insert(message.end(), txHash.begin(), txHash.end()); + + witnesses[0].lock = Data(Constants::gBlankWitnessBytes, 0); + + for (auto&& witness : witnesses) { + Data serializedWitness; + witness.encode(serializedWitness); + encode64LE(serializedWitness.size(), message); + message.insert(message.end(), serializedWitness.begin(), serializedWitness.end()); + } + + auto messageHash = Hash::blake2b(message, 32, Constants::gHashPersonalization); + auto signature = privateKey.sign(messageHash, TWCurveSECP256k1); + if (signature.empty()) { + // Error: Failed to sign + return Common::Proto::Error_signing; + } + witnesses[0].lock = signature; + + return Common::Proto::OK; +} diff --git a/src/Nervos/Transaction.h b/src/Nervos/Transaction.h new file mode 100644 index 00000000000..713115861ba --- /dev/null +++ b/src/Nervos/Transaction.h @@ -0,0 +1,76 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Address.h" +#include "Cell.h" +#include "CellDep.h" +#include "CellInput.h" +#include "CellOutput.h" +#include "HeaderDep.h" +#include "Script.h" +#include "TransactionPlan.h" +#include "Witness.h" + +#include "../Coin.h" +#include "../CoinEntry.h" +#include "../Data.h" +#include "../Hash.h" +#include "../KeyPair.h" +#include "../PrivateKey.h" +#include "../PublicKey.h" +#include "../Result.h" + +#include + +namespace TW::Nervos { + +class Transaction { +public: + /// Transaction data format version (note, this is signed) + int32_t version = 0; + + // List of cell deps + CellDeps cellDeps; + + // List of header deps + HeaderDeps headerDeps; + + // List of cell inputs + CellInputs inputs; + + // List of cell outputs + CellOutputs outputs; + + // List of outputs data + std::vector outputsData; + + // List of serialized witnesses + std::vector serializedWitnesses; + + // List of cells selected for this transaction + Cells selectedCells; + + Transaction() = default; + + Data hash() const; + nlohmann::json json() const; + void build(const TransactionPlan& txPlan); + Common::Proto::SigningError sign(const std::vector& privateKeys); + +private: + std::vector m_groupNumToLockHash; + std::vector> m_groupNumToInputIndices; + std::vector m_groupNumToWitnesses; + + void formGroups(); + Common::Proto::SigningError signGroups(const std::vector& privateKeys); + Common::Proto::SigningError signWitnesses(const PrivateKey& privateKey, const Data& txHash, + Witnesses& witnesses); +}; + +} // namespace TW::Nervos diff --git a/src/Nervos/TransactionPlan.cpp b/src/Nervos/TransactionPlan.cpp new file mode 100644 index 00000000000..c4135505af8 --- /dev/null +++ b/src/Nervos/TransactionPlan.cpp @@ -0,0 +1,328 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "TransactionPlan.h" +#include "Constants.h" +#include "Serialization.h" +#include "Witness.h" +#include "../BinaryCoding.h" +#include "../HexCoding.h" + +#include + +#include +#include +#include + +using namespace TW; +namespace TW::Nervos { + +void TransactionPlan::plan(const Proto::SigningInput& signingInput) { + error = Common::Proto::OK; + + m_byteFee = signingInput.byte_fee(); + + if (signingInput.cell_size() == 0) { + error = Common::Proto::Error_missing_input_utxos; + return; + } + for (auto&& cell : signingInput.cell()) { + m_availableCells.emplace_back(cell); + } + + switch (signingInput.operation_oneof_case()) { + case Proto::SigningInput::kNativeTransfer: { + planNativeTransfer(signingInput); + break; + } + case Proto::SigningInput::kSudtTransfer: { + planSudtTransfer(signingInput); + break; + } + case Proto::SigningInput::kDaoDeposit: { + planDaoDeposit(signingInput); + break; + } + case Proto::SigningInput::kDaoWithdrawPhase1: { + planDaoWithdrawPhase1(signingInput); + break; + } + case Proto::SigningInput::kDaoWithdrawPhase2: { + planDaoWithdrawPhase2(signingInput); + break; + } + default: { + error = Common::Proto::Error_invalid_params; + } + } +} + +void TransactionPlan::planNativeTransfer(const Proto::SigningInput& signingInput) { + auto useMaxAmount = signingInput.native_transfer().use_max_amount(); + auto amount = signingInput.native_transfer().amount(); + if ((amount == 0) && !useMaxAmount) { + error = Common::Proto::Error_zero_amount_requested; + return; + } + + cellDeps.emplace_back(Constants::gSecp256k1CellDep); + + outputs.emplace_back(amount, Script(Address(signingInput.native_transfer().to_address())), + Script()); + outputsData.emplace_back(); + + if (useMaxAmount) { + selectMaximumCapacity(); + } else { + auto changeAddress = Address(signingInput.native_transfer().change_address()); + selectRequiredCapacity(changeAddress); + } +} + +void TransactionPlan::planSudtTransfer(const Proto::SigningInput& signingInput) { + auto useMaxAmount = signingInput.sudt_transfer().use_max_amount(); + uint256_t amount = uint256_t(signingInput.sudt_transfer().amount()); + if ((amount == 0) && !useMaxAmount) { + error = Common::Proto::Error_zero_amount_requested; + return; + } + + cellDeps.emplace_back(Constants::gSecp256k1CellDep); + cellDeps.emplace_back(Constants::gSUDTCellDep); + + outputs.emplace_back(Constants::gMinCellCapacityForSUDT, + Script(Address(signingInput.sudt_transfer().to_address())), + Script(Constants::gSUDTCodeHash, HashType::Type1, + data(signingInput.sudt_transfer().sudt_address()))); + outputsData.emplace_back(); + + auto changeAddress = Address(signingInput.sudt_transfer().change_address()); + selectSudtTokens(useMaxAmount, amount, changeAddress); + selectRequiredCapacity(changeAddress); +} + +void TransactionPlan::planDaoDeposit(const Proto::SigningInput& signingInput) { + auto amount = signingInput.dao_deposit().amount(); + + cellDeps.emplace_back(Constants::gSecp256k1CellDep); + cellDeps.emplace_back(Constants::gDAOCellDep); + + outputs.emplace_back(amount, Script(Address(signingInput.dao_deposit().to_address())), + Script(Constants::gDAOCodeHash, HashType::Type1, Data())); + outputsData.emplace_back(); + encode64LE(0, outputsData[outputsData.size() - 1]); + + auto changeAddress = Address(signingInput.dao_deposit().change_address()); + selectRequiredCapacity(changeAddress); +} + +void TransactionPlan::planDaoWithdrawPhase1(const Proto::SigningInput& signingInput) { + cellDeps.emplace_back(Constants::gSecp256k1CellDep); + cellDeps.emplace_back(Constants::gDAOCellDep); + + auto depositCell = Cell(signingInput.dao_withdraw_phase1().deposit_cell()); + selectedCells.emplace_back(depositCell); + m_availableCells.erase(std::remove_if( + m_availableCells.begin(), m_availableCells.end(), + [&depositCell](const Cell& cell) { return cell.outPoint == depositCell.outPoint; })); + + headerDeps.emplace_back(depositCell.blockHash); + + outputs.emplace_back(depositCell.capacity, Script(depositCell.lock), Script(depositCell.type)); + outputsData.emplace_back(); + encode64LE(depositCell.blockNumber, outputsData[outputsData.size() - 1]); + + auto changeAddress = Address(signingInput.dao_withdraw_phase1().change_address()); + selectRequiredCapacity(changeAddress); +} + +void TransactionPlan::planDaoWithdrawPhase2(const Proto::SigningInput& signingInput) { + cellDeps.emplace_back(Constants::gSecp256k1CellDep); + cellDeps.emplace_back(Constants::gDAOCellDep); + + auto depositCell = Cell(signingInput.dao_withdraw_phase2().deposit_cell()); + auto withdrawingCell = Cell(signingInput.dao_withdraw_phase2().withdrawing_cell()); + selectedCells.emplace_back(withdrawingCell); + encode64LE(0, selectedCells[selectedCells.size() - 1].inputType); + + headerDeps.emplace_back(depositCell.blockHash); + headerDeps.emplace_back(withdrawingCell.blockHash); + + outputs.emplace_back(signingInput.dao_withdraw_phase2().amount(), Script(withdrawingCell.lock), + Script()); + outputsData.emplace_back(); + + outputs[0].capacity -= calculateFee(); +} + +void TransactionPlan::selectMaximumCapacity() { + uint64_t selectedCapacity = + std::accumulate(m_availableCells.begin(), m_availableCells.end(), uint64_t(0), + [&](const uint64_t total, const Cell& cell) { + if (cell.type.empty()) { + selectedCells.emplace_back(cell); + return total + cell.capacity; + } else { + return total; + } + }); + uint64_t fee = calculateFee(); + outputs[0].capacity = selectedCapacity - fee; +} + +void TransactionPlan::selectRequiredCapacity(const Address& changeAddress) { + uint64_t requiredCapacity = getRequiredCapacity(); + uint64_t fee = calculateFee(); + uint64_t feeForChangeOutput = sizeOfSingleOutput(changeAddress) * m_byteFee; + uint64_t selectedCapacity = getSelectedCapacity(); + uint64_t requiredCapacityPlusFees = requiredCapacity + fee + feeForChangeOutput; + if (selectedCapacity >= requiredCapacityPlusFees + Constants::gMinCellCapacityForNativeToken) { + outputs.emplace_back(selectedCapacity - requiredCapacityPlusFees, Script(changeAddress), + Script()); + outputsData.emplace_back(); + return; + } + sortAccordingToCapacity(); + bool gotEnough = false; + for (auto&& cell : m_availableCells) { + if (!cell.type.empty()) { + continue; + } + selectedCells.emplace_back(cell); + selectedCapacity += cell.capacity; + fee += sizeOfSingleInputAndWitness(cell.inputType, cell.outputType) * m_byteFee; + if (selectedCapacity >= requiredCapacity + fee) { + gotEnough = true; + uint64_t remainingCapacity = selectedCapacity - requiredCapacity - fee; + if (remainingCapacity >= + feeForChangeOutput + Constants::gMinCellCapacityForNativeToken) { + // If change is enough, add it to the change address + outputs.emplace_back(remainingCapacity - feeForChangeOutput, Script(changeAddress), + Script()); + outputsData.emplace_back(); + } else { + // If change is not enough, add it to the destination address + outputs[outputs.size() - 1].capacity += remainingCapacity; + } + break; + } + } + if (!gotEnough) { + error = Common::Proto::Error_not_enough_utxos; + } +} + +void TransactionPlan::selectSudtTokens(const bool useMaxAmount, const uint256_t amount, + const Address& changeAddress) { + uint256_t selectedSudtAmount = 0; + sortAccordingToTypeAndData(outputs[0].type); + bool gotEnough = false; + auto cell = m_availableCells.begin(); + while (cell != m_availableCells.end()) { + if (cell->type != outputs[0].type) { + cell++; + continue; + } + selectedCells.emplace_back(*cell); + selectedSudtAmount += Serialization::decodeUint256(cell->data); + cell = m_availableCells.erase(cell); + if (useMaxAmount) { + // Transfer maximum available tokens + gotEnough = true; + } else if (selectedSudtAmount >= amount) { + // Transfer exact number of tokens + gotEnough = true; + uint256_t changeValue = selectedSudtAmount - amount; + if (changeValue > 0) { + outputs.emplace_back(Constants::gMinCellCapacityForSUDT, Script(changeAddress), + Script(outputs[0].type)); + outputsData.emplace_back(Serialization::encodeUint256(changeValue, 16)); + } + break; + } + } + if (!gotEnough) { + error = Common::Proto::Error_not_enough_utxos; + return; + } + outputsData[0] = Serialization::encodeUint256(useMaxAmount ? selectedSudtAmount : amount, 16); +} + +uint64_t TransactionPlan::sizeWithoutInputs() { + uint64_t size = Constants::gTransactionBaseSize; + size += Constants::gCellDepSize * cellDeps.size(); + size += Constants::gHeaderDepSize * headerDeps.size(); + size += std::accumulate(outputs.begin(), outputs.end(), 0, + [](const uint64_t size, const CellOutput& output) { + Data outputData1; + output.encode(outputData1); + return size + outputData1.size() + Constants::gUint32Size; + }); + size += std::accumulate( + outputsData.begin(), outputsData.end(), 0, [](const uint64_t size, const Data& outputData) { + return size + Constants::gUint32Size + outputData.size() + Constants::gUint32Size; + }); + return size; +} + +uint64_t TransactionPlan::sizeOfSingleInputAndWitness(const Data& inputType, + const Data& outputType) { + uint64_t size = Constants::gSingleInputAndWitnessBaseSize; + auto witness = Witness(Data(Constants::gBlankWitnessBytes, 0), inputType, outputType); + Data witnessData; + witness.encode(witnessData); + size += Constants::gUint32Size + witnessData.size() + Constants::gUint32Size; + return size; +} + +uint64_t TransactionPlan::sizeOfSingleOutput(const Address& address) { + uint64_t size = 0; + auto output = CellOutput(0, Script(address), Script()); + Data outputData1; + output.encode(outputData1); + size += outputData1.size() + Constants::gUint32Size; // output + size += Constants::gUint32Size + 0 + Constants::gUint32Size; // blank outputData + return size; +} + +uint64_t TransactionPlan::calculateFee() { + uint64_t size = sizeWithoutInputs(); + size += std::accumulate(selectedCells.begin(), selectedCells.end(), uint64_t(0), + [&](const uint64_t total, const Cell& cell) { + return total + + sizeOfSingleInputAndWitness(cell.inputType, cell.outputType); + }); + return size * m_byteFee; +} + +void TransactionPlan::sortAccordingToCapacity() { + std::sort(m_availableCells.begin(), m_availableCells.end(), + [](const Cell& lhs, const Cell& rhs) { return lhs.capacity < rhs.capacity; }); +} + +void TransactionPlan::sortAccordingToTypeAndData(const Script& type) { + std::sort( + m_availableCells.begin(), m_availableCells.end(), [&](const Cell& lhs, const Cell& rhs) { + uint256_t lhsAmount = (lhs.type == type) ? Serialization::decodeUint256(lhs.data) : 0; + uint256_t rhsAmount = (rhs.type == type) ? Serialization::decodeUint256(rhs.data) : 0; + return lhsAmount < rhsAmount; + }); +} + +uint64_t TransactionPlan::getRequiredCapacity() { + return std::accumulate(outputs.begin(), outputs.end(), uint64_t(0), + [](const uint64_t total, const CellOutput& cellOutput) { + return total + cellOutput.capacity; + }); +} + +uint64_t TransactionPlan::getSelectedCapacity() { + return std::accumulate( + selectedCells.begin(), selectedCells.end(), uint64_t(0), + [](const uint64_t total, const Cell& cell) { return total + cell.capacity; }); +} + +} // namespace TW::Nervos diff --git a/src/Nervos/TransactionPlan.h b/src/Nervos/TransactionPlan.h new file mode 100644 index 00000000000..aded69fe9da --- /dev/null +++ b/src/Nervos/TransactionPlan.h @@ -0,0 +1,123 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Address.h" +#include "Cell.h" +#include "CellDep.h" +#include "CellInput.h" +#include "CellOutput.h" +#include "HeaderDep.h" +#include "Script.h" + +#include "../Coin.h" +#include "../CoinEntry.h" +#include "../Data.h" +#include "../Hash.h" +#include "../KeyPair.h" +#include "../PrivateKey.h" +#include "../PublicKey.h" +#include "../Result.h" +#include "../proto/Nervos.pb.h" + +#include + +namespace TW::Nervos { + +class TransactionPlan { +public: + // List of cell deps + CellDeps cellDeps; + + // List of header deps + HeaderDeps headerDeps; + + // List of cells selected for this transaction + Cells selectedCells; + + // List of cell outputs + CellOutputs outputs; + + // List of outputs data + std::vector outputsData; + + // Error during transaction planning + Common::Proto::SigningError error; + + TransactionPlan() = default; + + /// Initializes a transaction from a Protobuf transaction. + TransactionPlan(const Proto::TransactionPlan& txPlan) { + for (auto&& cellDep : txPlan.cell_deps()) { + cellDeps.emplace_back(cellDep); + } + for (auto&& headerDep : txPlan.header_deps()) { + Data data; + data.insert(data.end(), headerDep.begin(), headerDep.end()); + headerDeps.emplace_back(data); + } + for (auto&& cell : txPlan.selected_cells()) { + selectedCells.emplace_back(cell); + } + for (auto&& output : txPlan.outputs()) { + outputs.emplace_back(output); + } + for (auto&& outputData : txPlan.outputs_data()) { + Data data; + data.insert(data.end(), outputData.begin(), outputData.end()); + outputsData.emplace_back(data); + } + error = txPlan.error(); + } + + /// Converts to Protobuf model + Proto::TransactionPlan proto() const { + auto txPlan = Proto::TransactionPlan(); + for (auto&& cellDep : cellDeps) { + *txPlan.add_cell_deps() = cellDep.proto(); + } + for (auto&& headerDep : headerDeps) { + txPlan.add_header_deps(headerDep.data(), headerDep.size()); + } + for (auto&& cell : selectedCells) { + *txPlan.add_selected_cells() = cell.proto(); + } + for (auto&& output : outputs) { + *txPlan.add_outputs() = output.proto(); + } + for (auto&& outputData : outputsData) { + txPlan.add_outputs_data(outputData.data(), outputData.size()); + } + return txPlan; + } + + void plan(const Proto::SigningInput& signingInput); + +private: + uint64_t m_byteFee; + Cells m_availableCells; + + void planNativeTransfer(const Proto::SigningInput& signingInput); + void planSudtTransfer(const Proto::SigningInput& signingInput); + void planDaoDeposit(const Proto::SigningInput& signingInput); + void planDaoWithdrawPhase1(const Proto::SigningInput& signingInput); + void planDaoWithdrawPhase2(const Proto::SigningInput& signingInput); + void selectMaximumCapacity(); + void selectRequiredCapacity(const Address& changeAddress); + void selectSudtTokens(const bool useMaxAmount, const uint256_t amount, + const Address& changeAddress); + uint64_t sizeWithoutInputs(); + uint64_t sizeOfSingleInputAndWitness(const Data& inputType, const Data& outputType); + uint64_t sizeOfSingleOutput(const Address& address); + uint64_t calculateFee(); + void sortAccordingToCapacity(); + void sortAccordingToTypeAndData(const Script& type); + uint64_t getRequiredCapacity(); + uint64_t getSelectedCapacity(); +}; + +} // namespace TW::Nervos diff --git a/src/Nervos/Witness.cpp b/src/Nervos/Witness.cpp new file mode 100644 index 00000000000..979d06c4b0a --- /dev/null +++ b/src/Nervos/Witness.cpp @@ -0,0 +1,29 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Witness.h" +#include "Serialization.h" +#include "../BinaryCoding.h" + +using namespace TW; +using namespace TW::Nervos; + +void Witness::encode(Data& data) const { + if ((lock.size() == 0) && (inputType.size() == 0) && (outputType.size() == 0)) { + return; + } + std::vector dataArray; + dataArray.reserve(3); + for (auto&& data1 : std::vector({lock, inputType, outputType})) { + Data data2; + if (data1.size() > 0) { + encode32LE(uint32_t(data1.size()), data2); + data2.insert(data2.end(), data1.begin(), data1.end()); + } + dataArray.emplace_back(data2); + } + Serialization::encodeDataArray(dataArray, data); +} diff --git a/src/Nervos/Witness.h b/src/Nervos/Witness.h new file mode 100644 index 00000000000..13a60640fef --- /dev/null +++ b/src/Nervos/Witness.h @@ -0,0 +1,33 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "../Data.h" + +#include + +namespace TW::Nervos { + +struct Witness { + Data lock; + Data inputType; + Data outputType; + + Witness() = default; + + /// Initializes a witness with lock, inputType and outputType. + Witness(const Data& lock, const Data& inputType, const Data& outputType) + : lock(lock), inputType(inputType), outputType(outputType) {} + + /// Encodes the witness into the provided buffer. + void encode(Data& data) const; +}; + +/// A list of Witness's +using Witnesses = std::vector; + +} // namespace TW::Nervos diff --git a/src/interface/TWNervosAddress.cpp b/src/interface/TWNervosAddress.cpp new file mode 100644 index 00000000000..963ddf763ff --- /dev/null +++ b/src/interface/TWNervosAddress.cpp @@ -0,0 +1,51 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "TrustWalletCore/TWData.h" +#include "../Base58.h" +#include "../Nervos/Address.h" + +#include + +#include + +bool TWNervosAddressEqual(struct TWNervosAddress *_Nonnull lhs, struct TWNervosAddress *_Nonnull rhs) { + return lhs->impl == rhs->impl; +} + +bool TWNervosAddressIsValidString(TWString *_Nonnull string) { + auto& s = *reinterpret_cast(string); + return TW::Nervos::Address::isValid(s); +} + +struct TWNervosAddress *_Nullable TWNervosAddressCreateWithString(TWString *_Nonnull string) { + auto& s = *reinterpret_cast(string); + try { + return new TWNervosAddress{ TW::Nervos::Address(s) }; + } catch (...) { + return nullptr; + } +} + +void TWNervosAddressDelete(struct TWNervosAddress *_Nonnull address) { + delete address; +} + +TWString *_Nonnull TWNervosAddressDescription(struct TWNervosAddress *_Nonnull address) { + return TWStringCreateWithUTF8Bytes(address->impl.string().c_str()); +} + +TWData *_Nonnull TWNervosAddressCodeHash(struct TWNervosAddress *_Nonnull address) { + return TWDataCreateWithBytes(address->impl.codeHash.data(), address->impl.codeHash.size()); +} + +TWString *_Nonnull TWNervosAddressHashType(struct TWNervosAddress *_Nonnull address) { + return TWStringCreateWithUTF8Bytes(address->impl.hashTypeString().c_str()); +} + +TWData *_Nonnull TWNervosAddressArgs(struct TWNervosAddress *_Nonnull address) { + return TWDataCreateWithBytes(address->impl.args.data(), address->impl.args.size()); +} diff --git a/src/proto/Nervos.proto b/src/proto/Nervos.proto new file mode 100644 index 00000000000..fd7c92afc6f --- /dev/null +++ b/src/proto/Nervos.proto @@ -0,0 +1,204 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +syntax = "proto3"; + +package TW.Nervos.Proto; +option java_package = "wallet.core.jni.proto"; + +import "Common.proto"; + +// Nervos transaction plan +message TransactionPlan { + // A list of cell deps. + repeated CellDep cell_deps = 1; + + // A list of header deps. + repeated bytes header_deps = 2; + + // A list of 1 or more selected cells for this transaction + repeated Cell selected_cells = 3; + + // A list of 1 or more outputs by this transaciton + repeated CellOutput outputs = 4; + + // A list of outputs data. + repeated bytes outputs_data = 5; + + // Optional error + Common.Proto.SigningError error = 6; +} + +// Nervos cell dep. +message CellDep { + // Prevents the transaction to be mined before an absolute or relative time + string dep_type = 1; + + // Reference to the previous transaction's output. + OutPoint out_point = 2; +} + +// Nervos transaction out-point reference. +message OutPoint { + // The hash of the referenced transaction. + bytes tx_hash = 1; + + // The index of the specific output in the transaction. + uint32 index = 2; +} + +// Nervos cell output. +message CellOutput { + // Transaction amount. + uint64 capacity = 1; + + // Lock script + Script lock = 2; + + // Type script + Script type = 3; +} + +// Nervos script +message Script { + // Code hash + bytes code_hash = 1; + + // Hash type + string hash_type = 2; + + // args + bytes args = 3; +} + +message NativeTransfer { + // Recipient's address. + string to_address = 1; + + // Change address. + string change_address = 2; + + // Amount to send. + uint64 amount = 3; + + // If sending max amount. + bool use_max_amount = 4; +} + +message SudtTransfer { + // Recipient's address. + string to_address = 1; + + // Change address. + string change_address = 2; + + // SUDT (Simple User Defined Token) address + bytes sudt_address = 3; + + // Amount to send. + string amount = 4; + + // If sending max amount. + bool use_max_amount = 5; +} + +message DaoDeposit { + // Recipient's address. + string to_address = 1; + + // Change address. + string change_address = 2; + + // Amount to deposit. + uint64 amount = 3; +} + +message DaoWithdrawPhase1 { + // Deposit cell + Cell deposit_cell = 1; + + // Change address. + string change_address = 2; +} + +message DaoWithdrawPhase2 { + // Deposit cell + Cell deposit_cell = 1; + + // Withdrawing cell + Cell withdrawing_cell = 2; + + // Amount + uint64 amount = 3; +} + +// Input data necessary to create a signed transaction. +message SigningInput { + // Transaction fee per byte. + uint64 byte_fee = 1; + + // Available private keys. + repeated bytes private_key = 2; + + // Available unspent cell outputs. + repeated Cell cell = 3; + + // Optional transaction plan + TransactionPlan plan = 4; + + oneof operation_oneof { + NativeTransfer native_transfer = 5; + SudtTransfer sudt_transfer = 6; + DaoDeposit dao_deposit = 7; + DaoWithdrawPhase1 dao_withdraw_phase1 = 8; + DaoWithdrawPhase2 dao_withdraw_phase2 = 9; + } +} + +// An unspent cell output, that can serve as input to a transaction +message Cell { + // The unspent output + OutPoint out_point = 1; + + // Amount of the cell + uint64 capacity = 2; + + // Lock script + Script lock = 3; + + // Type script + Script type = 4; + + // Data + bytes data = 5; + + // Optional block number + uint64 block_number = 6; + + // Optional block hash + bytes block_hash = 7; + + // Optional since the cell is available to spend + uint64 since = 8; + + // Optional input type data to be included in witness + bytes input_type = 9; + + // Optional output type data to be included in witness + bytes output_type = 10; +} + +// Transaction signing output. +message SigningOutput { + // Resulting transaction. Note that the amount may be different than the requested amount to account for fees and available funds. + string transaction_json = 1; + + // Transaction id + string transaction_id = 2; + + // Optional error + Common.Proto.SigningError error = 3; +} diff --git a/swift/Tests/Blockchains/NervosTests.swift b/swift/Tests/Blockchains/NervosTests.swift new file mode 100644 index 00000000000..e250869c9ad --- /dev/null +++ b/swift/Tests/Blockchains/NervosTests.swift @@ -0,0 +1,123 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import XCTest +import WalletCore + +class NervosTests: XCTestCase { + + func testDerive() throws { + let wallet = HDWallet(mnemonic: "disorder wolf eager ladder fence renew dynamic idea metal camera bread obscure", passphrase: "")! + let address = wallet.getAddressForCoin(coin: .nervos) + + XCTAssertEqual(address, "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqga4k4agxexsd3zdq0wvrlyumfz7n5r7fsjxtnw8") + } + + func testAddress() throws { + + let key = PrivateKey(data: Data(hexString: "8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb")!)! + let pubkey = key.getPublicKeySecp256k1(compressed: true) + let address = AnyAddress(publicKey: pubkey, coin: .nervos) + let addressFromString = AnyAddress(string: "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8furras980hksatlslfaktks7epf25", coin: .nervos)! + + XCTAssertEqual(address.description, addressFromString.description) + } + + func testSign() throws { + + let string = "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8furras980hksatlslfaktks7epf25" + let address = NervosAddress(string: string)! + let lockScript = NervosScript.with { + $0.codeHash = address.codeHash + $0.hashType = address.hashType + $0.args = address.args + } + + let input = NervosSigningInput.with { + $0.nativeTransfer = NervosNativeTransfer.with { + $0.toAddress = "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02wectaumxn0664yw2jd53lqk4mxg3" + $0.changeAddress = "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqds6ed78yze6eyfyvd537z66ur22c9mmrgz82ama" + $0.amount = 10000000000 + } + $0.byteFee = 1 + $0.cell = [ + NervosCell.with { + $0.capacity = 100000000000 + $0.outPoint = NervosOutPoint.with { + $0.txHash = Data(hexString: "71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3")! + $0.index = 1 + } + $0.lock = lockScript + }, + NervosCell.with { + $0.capacity = 20000000000 + $0.outPoint = NervosOutPoint.with { + $0.txHash = Data(hexString: "71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3")! + $0.index = 0 + } + $0.lock = lockScript + } + ] + $0.privateKey = [ + Data(hexString: "8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb")! + ] + } + + let output: NervosSigningOutput = AnySigner.sign(input: input, coin: .nervos) + let json = """ + { + "cell_deps": [ + { + "dep_type": "dep_group", + "out_point": { + "index": "0x0", + "tx_hash": "0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c" + } + } + ], + "header_deps": [], + "inputs": [ + { + "previous_output": { + "index": "0x0", + "tx_hash": "0x71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3" + }, + "since": "0x0" + } + ], + "outputs": [ + { + "capacity": "0x2540be400", + "lock": { + "args": "0xab201f55b02f53b385f79b34dfad548e549b48fc", + "code_hash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", + "hash_type": "type" + }, + "type": null + }, + { + "capacity": "0x2540be230", + "lock": { + "args": "0xb0d65be39059d6489231b48f85ad706a560bbd8d", + "code_hash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", + "hash_type": "type" + }, + "type": null + } + ], + "outputs_data": ["0x", "0x"], + "version": "0x0", + "witnesses": [ + "0x55000000100000005500000055000000410000002a9ef2ad7829e5ea0c7a32735d29a0cb2ec20434f6fd5bf6e29cda56b28e08140156191cbbf80313d3c9cae4b74607acce7b28eb21d52ef058ed8491cdde70b700" + ] + } + """ + + XCTAssertEqual(output.transactionID, "0xf2c32afde7e72011985583873bc16c0a3c01fc01fc161eb4b914fcf84c53cdf8") + XCTAssertEqual(output.error, CommonSigningError.ok) + XCTAssertJSONEqual(output.transactionJson, json) + } +} diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 0440ed7f739..c02527d54fa 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -140,6 +140,9 @@ class CoinAddressDerivationTests: XCTestCase { case .neo: let expectedResult = "AT6w7PJvwPcSqHvtbNBY2aHPDv12eW5Uuf" assertCoinDerivation(coin, expectedResult, derivedAddress, address) + case .nervos: + let expectedResult = "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02wectaumxn0664yw2jd53lqk4mxg3"; + assertCoinDerivation(coin, expectedResult, derivedAddress, address) case .nimiq: let expectedResult = "NQ76 7AVR EHDA N05U X7SY XB14 XJU7 8ERV GM6H" assertCoinDerivation(coin, expectedResult, derivedAddress, address) diff --git a/tests/CoinAddressDerivationTests.cpp b/tests/CoinAddressDerivationTests.cpp index 270f29087a5..e109a4dae5f 100644 --- a/tests/CoinAddressDerivationTests.cpp +++ b/tests/CoinAddressDerivationTests.cpp @@ -242,7 +242,9 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeZilliqa: EXPECT_EQ(address, "zil1j2cvtd7j9n7fnxfv2r3neucjw8tp4xz9sp07v4"); break; - + case TWCoinTypeNervos: + EXPECT_EQ(address, "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqtsqfsf77ae0wn5a7795hs2ydv83g6hl4qleywxw"); + break; // no default branch here, intentionally, to better notice any missing coins } } diff --git a/tests/Kusama/SignerTests.cpp b/tests/Kusama/SignerTests.cpp index 99acb6efa5b..3af2df1c9ec 100644 --- a/tests/Kusama/SignerTests.cpp +++ b/tests/Kusama/SignerTests.cpp @@ -17,7 +17,7 @@ #include -namespace TW::Polkadot { +namespace TW::Polkadot::tests { extern PrivateKey privateKey; extern PublicKey toPublicKey; auto genesisHashKSM = parse_hex("b0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe"); @@ -49,4 +49,4 @@ TEST(PolkadotSigner, SignTransferKSM) { ASSERT_EQ(hex(output.encoded()), "25028488dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee000765cfa76cfe19499f4f19ef7dc4527652ec5b2e6b5ecfaf68725dafd48ae2694ad52e61f44152a544784e847de10ddb2c56bee4406574dcbcfdb5e5d35b6d0300000004008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48e5c0"); } -} // namespace +} // namespace TW::Polkadot::tests diff --git a/tests/Nervos/AddressTests.cpp b/tests/Nervos/AddressTests.cpp new file mode 100644 index 00000000000..15fb9cadfe0 --- /dev/null +++ b/tests/Nervos/AddressTests.cpp @@ -0,0 +1,88 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HDWallet.h" +#include "HexCoding.h" +#include "Nervos/Address.h" +#include "PrivateKey.h" +#include "PublicKey.h" +#include +#include + +namespace TW::Nervos::tests { + +TEST(NervosAddress, Valid) { + ASSERT_TRUE(Address::isValid("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9e" + "rg8furras980hksatlslfaktks7epf25")); + ASSERT_TRUE(Address::isValid("ckb1qyqvfdgvtjxswncx8mq2wl0dp6hlp7nmvhdqcecnt6")); + ASSERT_TRUE(Address::isValid("ckb1qjda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xw3394p3wg6" + "p60qclvpfmaa582lu860dja5h0fk0v")); +} + +TEST(NervosAddress, Invalid) { + ASSERT_FALSE(Address::isValid("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9" + "erg8furras980hksatlslfaktks7epf26")); + ASSERT_FALSE(Address::isValid("ckb1qyqvfdgvtjxswncx8mq2wl0dp6hlp7nmvhdqcecnt7")); + ASSERT_FALSE(Address::isValid("ckb1qjda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xw3394p3wg" + "6p60qclvpfmaa582lu860dja5h0fk0w")); +} + +TEST(NervosAddress, FromPrivateKey) { + auto privateKey = + PrivateKey(parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb")); + auto address = Address(privateKey.getPublicKey(TWPublicKeyTypeSECP256k1)); + ASSERT_EQ(address.string(), "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9er" + "g8furras980hksatlslfaktks7epf25"); +} + +TEST(NervosAddress, FromPublicKey) { + auto publicKey = + PublicKey(parse_hex("026c9e4cbb95d4b3a123c1fc80795feacc38029683a1b3e16bccf49bba25fb2858"), + TWPublicKeyTypeSECP256k1); + auto address = Address(publicKey); + ASSERT_EQ(address.string(), "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9er" + "g8furras980hksatlslfaktks7epf25"); +} + +TEST(NervosAddress, FromString) { + auto address1 = Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8fu" + "rras980hksatlslfaktks7epf25"); + ASSERT_EQ(address1.string(), "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9e" + "rg8furras980hksatlslfaktks7epf25"); + auto address2 = Address("ckb1qyqvfdgvtjxswncx8mq2wl0dp6hlp7nmvhdqcecnt6"); + ASSERT_EQ(address2.string(), "ckb1qyqvfdgvtjxswncx8mq2wl0dp6hlp7nmvhdqcecnt6"); + auto address3 = Address("ckb1qjda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xw3394p3wg6p60qc" + "lvpfmaa582lu860dja5h0fk0v"); + ASSERT_EQ(address3.string(), "ckb1qjda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xw3394p3wg6" + "p60qclvpfmaa582lu860dja5h0fk0v"); +} + +TEST(TWNervosAddress, AddressFromPublicKey) { + auto privateKey = + PrivateKey(parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb")); + auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); + ASSERT_EQ(publicKey.bytes.size(), 33ul); + auto address = Address(publicKey); + ASSERT_EQ(address.string(), "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9er" + "g8furras980hksatlslfaktks7epf25"); +} + +TEST(NervosAddress, AddressFromString) { + auto address = Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8fur" + "ras980hksatlslfaktks7epf25"); + ASSERT_EQ(address.string(), "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9er" + "g8furras980hksatlslfaktks7epf25"); +} + +TEST(NervosAddress, AddressFromWallet) { + auto hdWallet = HDWallet( + "alpha draw toss question picnic endless recycle wrong enable roast success palm", ""); + auto addressString = hdWallet.deriveAddress(TWCoinTypeNervos); + ASSERT_EQ(addressString, "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8f" + "urras980hksatlslfaktks7epf25"); +} + +} // namespace TW::Nervos::tests diff --git a/tests/Nervos/SignerTests.cpp b/tests/Nervos/SignerTests.cpp new file mode 100644 index 00000000000..b7ea9e3645f --- /dev/null +++ b/tests/Nervos/SignerTests.cpp @@ -0,0 +1,929 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "Nervos/Address.h" +#include "Nervos/Cell.h" +#include "Nervos/Serialization.h" +#include "Nervos/Signer.h" +#include "Nervos/Transaction.h" +#include "Nervos/TransactionPlan.h" +#include "PrivateKey.h" +#include "PublicKey.h" +#include "uint256.h" +#include "../interface/TWTestUtilities.h" +#include + +#include + +namespace TW::Nervos::tests { + +std::vector getPrivateKeys(Proto::SigningInput& input) { + std::vector privateKeys; + privateKeys.reserve(input.private_key_size()); + for (auto&& privateKey : input.private_key()) { + privateKeys.emplace_back(privateKey); + } + return privateKeys; +} + +Proto::SigningInput getInput1() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_native_transfer(); + + operation.set_to_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02" + "wectaumxn0664yw2jd53lqk4mxg3"); + operation.set_change_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqds6ed78" + "yze6eyfyvd537z66ur22c9mmrgz82ama"); + operation.set_amount(10000000000); + input.set_byte_fee(1); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(100000000000); + *cell1.mutable_out_point() = + OutPoint(parse_hex("71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3"), 1) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto& cell2 = *input.add_cell(); + cell2.set_capacity(20000000000); + *cell2.mutable_out_point() = + OutPoint(parse_hex("71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3"), 0) + .proto(); + *cell2.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto privateKey = parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey.begin(), privateKey.end())); + + return input; +} + +void checkOutput1(Transaction& tx) { + // https://explorer.nervos.org/transaction/0xf2c32afde7e72011985583873bc16c0a3c01fc01fc161eb4b914fcf84c53cdf8 + ASSERT_EQ(tx.hash(), + parse_hex("f2c32afde7e72011985583873bc16c0a3c01fc01fc161eb4b914fcf84c53cdf8")); + + ASSERT_EQ(tx.cellDeps.size(), 1ul); + + ASSERT_EQ(tx.cellDeps[0].outPoint.txHash, + parse_hex("71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c")); + ASSERT_EQ(tx.cellDeps[0].outPoint.index, 0ul); + ASSERT_EQ(tx.cellDeps[0].depType, DepType::DepGroup); + + ASSERT_EQ(tx.headerDeps.size(), 0ul); + + ASSERT_EQ(tx.inputs.size(), 1ul); + + ASSERT_EQ(tx.inputs[0].previousOutput.txHash, + parse_hex("71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3")); + ASSERT_EQ(tx.inputs[0].previousOutput.index, 0ul); + ASSERT_EQ(tx.inputs[0].since, 0ul); + + ASSERT_EQ(tx.outputs.size(), 2ul); + ASSERT_EQ(tx.outputsData.size(), 2ul); + + ASSERT_EQ(tx.outputs[0].capacity, 10000000000ul); + ASSERT_EQ(tx.outputs[0].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[0].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[0].lock.args, parse_hex("ab201f55b02f53b385f79b34dfad548e549b48fc")); + ASSERT_EQ(tx.outputs[0].type.codeHash.size(), 0ul); + ASSERT_EQ(tx.outputs[0].type.args.size(), 0ul); + ASSERT_EQ(tx.outputsData[0].size(), 0ul); + + ASSERT_EQ(tx.outputs[1].capacity, 9999999536ul); + ASSERT_EQ(tx.outputs[1].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[1].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[1].lock.args, parse_hex("b0d65be39059d6489231b48f85ad706a560bbd8d")); + ASSERT_EQ(tx.outputs[1].type.codeHash.size(), 0ul); + ASSERT_EQ(tx.outputs[1].type.args.size(), 0ul); + ASSERT_EQ(tx.outputsData[1].size(), 0ul); + + ASSERT_EQ(tx.serializedWitnesses.size(), 1ul); + ASSERT_EQ( + hex(tx.serializedWitnesses[0]), + "55000000100000005500000055000000410000002a9ef2ad7829e5ea0c7a32735d29a0cb2ec20434f6fd5bf6e2" + "9cda56b28e08140156191cbbf80313d3c9cae4b74607acce7b28eb21d52ef058ed8491cdde70b700"); +} + +void checkPlan1(TransactionPlan& txPlan) { + ASSERT_EQ(txPlan.error, Common::Proto::SigningError::OK); + + ASSERT_EQ(txPlan.cellDeps.size(), 1ul); + + ASSERT_EQ(txPlan.cellDeps[0].outPoint.txHash, + parse_hex("71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c")); + ASSERT_EQ(txPlan.cellDeps[0].outPoint.index, 0ul); + ASSERT_EQ(txPlan.cellDeps[0].depType, DepType::DepGroup); + + ASSERT_EQ(txPlan.headerDeps.size(), 0ul); + + ASSERT_EQ(txPlan.selectedCells.size(), 1ul); + + ASSERT_EQ(txPlan.selectedCells[0].outPoint.txHash, + parse_hex("71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3")); + ASSERT_EQ(txPlan.selectedCells[0].outPoint.index, 0ul); + ASSERT_EQ(txPlan.selectedCells[0].capacity, 20000000000ul); + ASSERT_EQ(txPlan.selectedCells[0].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(txPlan.selectedCells[0].lock.hashType, HashType::Type1); + ASSERT_EQ(txPlan.selectedCells[0].lock.args, + parse_hex("c4b50c5c8d074f063ec0a77ded0eaff0fa7b65da")); + ASSERT_EQ(txPlan.selectedCells[0].type.codeHash.size(), 0ul); + ASSERT_EQ(txPlan.selectedCells[0].type.args.size(), 0ul); + ASSERT_EQ(txPlan.selectedCells[0].data.size(), 0ul); + + ASSERT_EQ(txPlan.outputs.size(), 2ul); + ASSERT_EQ(txPlan.outputsData.size(), 2ul); + + ASSERT_EQ(txPlan.outputs[0].capacity, 10000000000ul); + ASSERT_EQ(txPlan.outputs[0].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(txPlan.outputs[0].lock.hashType, HashType::Type1); + ASSERT_EQ(txPlan.outputs[0].lock.args, parse_hex("ab201f55b02f53b385f79b34dfad548e549b48fc")); + ASSERT_EQ(txPlan.outputs[0].type.codeHash.size(), 0ul); + ASSERT_EQ(txPlan.outputs[0].type.args.size(), 0ul); + ASSERT_EQ(txPlan.outputsData[0].size(), 0ul); + + ASSERT_EQ(txPlan.outputs[1].capacity, 9999999536ul); + ASSERT_EQ(txPlan.outputs[1].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(txPlan.outputs[1].lock.hashType, HashType::Type1); + ASSERT_EQ(txPlan.outputs[1].lock.args, parse_hex("b0d65be39059d6489231b48f85ad706a560bbd8d")); + ASSERT_EQ(txPlan.outputs[1].type.codeHash.size(), 0ul); + ASSERT_EQ(txPlan.outputs[1].type.args.size(), 0ul); + ASSERT_EQ(txPlan.outputsData[1].size(), 0ul); +} + +TEST(NervosSigner, PlanAndSign_Native_Simple) { + auto input = getInput1(); + TransactionPlan txPlan; + txPlan.plan(input); + ASSERT_EQ(txPlan.error, Common::Proto::SigningError::OK); + checkPlan1(txPlan); + Transaction tx; + tx.build(txPlan); + auto error = tx.sign(getPrivateKeys(input)); + ASSERT_EQ(error, Common::Proto::SigningError::OK); + checkOutput1(tx); +} + +TEST(NervosSigner, Sign_NegativeMissingKey) { + auto input = getInput1(); + TransactionPlan txPlan; + txPlan.plan(input); + ASSERT_EQ(txPlan.error, Common::Proto::SigningError::OK); + Transaction tx; + tx.build(txPlan); + auto privateKey = parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61fec"); + *input.mutable_private_key(0) = std::string(privateKey.begin(), privateKey.end()); + auto error = tx.sign(getPrivateKeys(input)); + ASSERT_EQ(error, Common::Proto::Error_missing_private_key); +} + +TEST(NervosSigner, Sign_NegativeNotEnoughUtxos) { + auto input = getInput1(); + auto& operation = *input.mutable_native_transfer(); + operation.set_amount(1000000000000); + TransactionPlan txPlan; + txPlan.plan(input); + ASSERT_EQ(txPlan.error, Common::Proto::Error_not_enough_utxos); +} + +Proto::SigningInput getInput2() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_native_transfer(); + + operation.set_to_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02" + "wectaumxn0664yw2jd53lqk4mxg3"); + operation.set_change_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqds6ed78" + "yze6eyfyvd537z66ur22c9mmrgz82ama"); + operation.set_use_max_amount(true); + input.set_byte_fee(1); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(11410040620); + *cell1.mutable_out_point() = + OutPoint(parse_hex("c75567c80dc9b97aaf4e5c23f4c7f37b077f2b33a50dd7abd952abfbd5beb247"), 0) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto privateKey = parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey.begin(), privateKey.end())); + + return input; +} + +TEST(NervosSigner, Sign_Native_SendMaximum) { + auto input = getInput2(); + TransactionPlan txPlan; + txPlan.plan(input); + ASSERT_EQ(txPlan.error, Common::Proto::SigningError::OK); + Transaction tx; + tx.build(txPlan); + auto error = tx.sign(getPrivateKeys(input)); + + ASSERT_EQ(error, Common::Proto::SigningError::OK); + + // https://explorer.nervos.org/transaction/0x298f5e04b6900796614b89062eb96cec63c3b2c460d01058736a793b567bc5c8 + ASSERT_EQ(tx.hash(), + parse_hex("298f5e04b6900796614b89062eb96cec63c3b2c460d01058736a793b567bc5c8")); + + ASSERT_EQ(tx.cellDeps.size(), 1ul); + + ASSERT_EQ(tx.cellDeps[0].outPoint.txHash, + parse_hex("71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c")); + ASSERT_EQ(tx.cellDeps[0].outPoint.index, 0ul); + ASSERT_EQ(tx.cellDeps[0].depType, DepType::DepGroup); + + ASSERT_EQ(tx.headerDeps.size(), 0ul); + + ASSERT_EQ(tx.inputs.size(), 1ul); + + ASSERT_EQ(tx.inputs[0].previousOutput.txHash, + parse_hex("c75567c80dc9b97aaf4e5c23f4c7f37b077f2b33a50dd7abd952abfbd5beb247")); + ASSERT_EQ(tx.inputs[0].previousOutput.index, 0ul); + ASSERT_EQ(tx.inputs[0].since, 0ul); + + ASSERT_EQ(tx.outputs.size(), 1ul); + ASSERT_EQ(tx.outputsData.size(), 1ul); + + ASSERT_EQ(tx.outputs[0].capacity, 11410040265ul); + ASSERT_EQ(tx.outputs[0].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[0].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[0].lock.args, parse_hex("ab201f55b02f53b385f79b34dfad548e549b48fc")); + ASSERT_EQ(tx.outputs[0].type.codeHash.size(), 0ul); + ASSERT_EQ(tx.outputs[0].type.args.size(), 0ul); + ASSERT_EQ(tx.outputsData[0].size(), 0ul); + + ASSERT_EQ(tx.serializedWitnesses.size(), 1ul); + ASSERT_EQ( + hex(tx.serializedWitnesses[0]), + "5500000010000000550000005500000041000000daf6e65e5a1fe447a4feb7199886b6635c44738e04ea594576" + "08fb1c447e068026529d57b02014ddc144622f886153df426853f22083f8891461eeb50b5ce97d01"); +} + +Proto::SigningInput getInput3() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_sudt_transfer(); + + operation.set_to_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02" + "wectaumxn0664yw2jd53lqk4mxg3"); + operation.set_change_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqds6ed78" + "yze6eyfyvd537z66ur22c9mmrgz82ama"); + uint256_t amount = 1000000000000000; + operation.set_amount(toString(amount)); + input.set_byte_fee(1); + auto sudtAddress = + parse_hex("9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8"); + *operation.mutable_sudt_address() = std::string(sudtAddress.begin(), sudtAddress.end()); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(14399998906); + *cell1.mutable_out_point() = + OutPoint(parse_hex("5b12911e7413e011f251c1fb5fae4e76fd5fcae4f0d4c6412dcc5b0bfcece823"), 0) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto& cell2 = *input.add_cell(); + cell2.set_capacity(14400000000); + *cell2.mutable_out_point() = + OutPoint(parse_hex("e118bd11a73d381daf288381ce182d92b6cf2f52d25886bbda9e1a61525c7c4a"), 0) + .proto(); + *cell2.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + *cell2.mutable_type() = + Script(parse_hex("5e7a36a77e68eecc013dfa2fe6a23f3b6c344b04005808694ae6dd45eea4cfd5"), + HashType::Type1, + parse_hex("9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8")) + .proto(); + auto cell2Data = parse_hex("00e0e4c9b9f84f000000000000000000"); + *cell2.mutable_data() = std::string(cell2Data.begin(), cell2Data.end()); + + auto& cell3 = *input.add_cell(); + cell3.set_capacity(8210025567); + *cell3.mutable_out_point() = + OutPoint(parse_hex("09a45a15e48f985b554a0b6e5f0857913cc492ec061cc9b0b2befa4b24609a4a"), 1) + .proto(); + *cell3.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqds6ed78yze6eyfyvd537z66ur22c9mmrgz82ama")) + .proto(); + + auto privateKey1 = + parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey1.begin(), privateKey1.end())); + auto privateKey2 = + parse_hex("0c8859a9d9084a8c2b55963268b352e258756f9240f2a1f4645c610ed191dae9"); + input.add_private_key(std::string(privateKey2.begin(), privateKey2.end())); + + return input; +} + +TEST(NervosSigner, Sign_SUDT_Simple) { + auto input = getInput3(); + + TransactionPlan txPlan; + txPlan.plan(input); + ASSERT_EQ(txPlan.error, Common::Proto::SigningError::OK); + Transaction tx; + tx.build(txPlan); + auto error = tx.sign(getPrivateKeys(input)); + + ASSERT_EQ(error, Common::Proto::SigningError::OK); + + // https://explorer.nervos.org/transaction/0x9b15f2bea26b98201540d8e20e8b1c21d96dd77ad246520b405c6aabb7173371 + ASSERT_EQ(tx.hash(), + parse_hex("9b15f2bea26b98201540d8e20e8b1c21d96dd77ad246520b405c6aabb7173371")); + + ASSERT_EQ(tx.cellDeps.size(), 2ul); + + ASSERT_EQ(tx.cellDeps[0].outPoint.txHash, + parse_hex("71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c")); + ASSERT_EQ(tx.cellDeps[0].outPoint.index, 0ul); + ASSERT_EQ(tx.cellDeps[0].depType, DepType::DepGroup); + + ASSERT_EQ(tx.cellDeps[1].outPoint.txHash, + parse_hex("c7813f6a415144643970c2e88e0bb6ca6a8edc5dd7c1022746f628284a9936d5")); + ASSERT_EQ(tx.cellDeps[1].outPoint.index, 0ul); + ASSERT_EQ(tx.cellDeps[1].depType, DepType::Code); + + ASSERT_EQ(tx.headerDeps.size(), 0ul); + + ASSERT_EQ(tx.inputs.size(), 3ul); + + ASSERT_EQ(tx.inputs[0].previousOutput.txHash, + parse_hex("e118bd11a73d381daf288381ce182d92b6cf2f52d25886bbda9e1a61525c7c4a")); + ASSERT_EQ(tx.inputs[0].previousOutput.index, 0ul); + ASSERT_EQ(tx.inputs[0].since, 0ul); + + ASSERT_EQ(tx.inputs[1].previousOutput.txHash, + parse_hex("09a45a15e48f985b554a0b6e5f0857913cc492ec061cc9b0b2befa4b24609a4a")); + ASSERT_EQ(tx.inputs[1].previousOutput.index, 1ul); + ASSERT_EQ(tx.inputs[1].since, 0ul); + + ASSERT_EQ(tx.inputs[2].previousOutput.txHash, + parse_hex("5b12911e7413e011f251c1fb5fae4e76fd5fcae4f0d4c6412dcc5b0bfcece823")); + ASSERT_EQ(tx.inputs[2].previousOutput.index, 0ul); + ASSERT_EQ(tx.inputs[2].since, 0ul); + + ASSERT_EQ(tx.outputs.size(), 3ul); + ASSERT_EQ(tx.outputsData.size(), 3ul); + + ASSERT_EQ(tx.outputs[0].capacity, 14400000000ul); + ASSERT_EQ(tx.outputs[0].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[0].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[0].lock.args, parse_hex("ab201f55b02f53b385f79b34dfad548e549b48fc")); + ASSERT_EQ(tx.outputs[0].type.codeHash, + parse_hex("5e7a36a77e68eecc013dfa2fe6a23f3b6c344b04005808694ae6dd45eea4cfd5")); + ASSERT_EQ(tx.outputs[0].type.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[0].type.args, + parse_hex("9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8")); + ASSERT_EQ(hex(tx.outputsData[0]), "0080c6a47e8d03000000000000000000"); + + ASSERT_EQ(tx.outputs[1].capacity, 14400000000ul); + ASSERT_EQ(tx.outputs[1].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[1].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[1].lock.args, parse_hex("b0d65be39059d6489231b48f85ad706a560bbd8d")); + ASSERT_EQ(tx.outputs[1].type.codeHash, + parse_hex("5e7a36a77e68eecc013dfa2fe6a23f3b6c344b04005808694ae6dd45eea4cfd5")); + ASSERT_EQ(tx.outputs[1].type.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[1].type.args, + parse_hex("9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8")); + ASSERT_EQ(hex(tx.outputsData[1]), "00601e253b6b4c000000000000000000"); + + ASSERT_EQ(tx.outputs[2].capacity, 8210023387ul); + ASSERT_EQ(tx.outputs[2].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[2].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[2].lock.args, parse_hex("b0d65be39059d6489231b48f85ad706a560bbd8d")); + ASSERT_EQ(tx.outputs[2].type.codeHash.size(), 0ul); + ASSERT_EQ(tx.outputs[2].type.args.size(), 0ul); + ASSERT_EQ(tx.outputsData[2].size(), 0ul); + + ASSERT_EQ(tx.serializedWitnesses.size(), 3ul); + ASSERT_EQ( + hex(tx.serializedWitnesses[0]), + "550000001000000055000000550000004100000035d55fd46316f248552eb6af7ac9589c9ec533c4e5b71896b0" + "5cdf697e2d18551ceff54d7b860ebb2f4dd5f6c5bb4af1da15460a7621f5aa4bc7d5585a0504de00"); + ASSERT_EQ( + hex(tx.serializedWitnesses[1]), + "5500000010000000550000005500000041000000eaa4bf69126d3016ab786610f2f0668b2ef353915d623d0b01" + "84fc25cec3dcad6dc08a1504a2d7dd9faced17b041d79d4c21f1977e57859713360f5e3609583501"); + ASSERT_EQ(hex(tx.serializedWitnesses[2]), ""); +} + +Proto::SigningInput getInput4() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_sudt_transfer(); + + operation.set_to_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02" + "wectaumxn0664yw2jd53lqk4mxg3"); + operation.set_change_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqds6ed78" + "yze6eyfyvd537z66ur22c9mmrgz82ama"); + operation.set_use_max_amount(true); + input.set_byte_fee(1); + auto sudtAddress = + parse_hex("9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8"); + *operation.mutable_sudt_address() = std::string(sudtAddress.begin(), sudtAddress.end()); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(8210026306); + *cell1.mutable_out_point() = + OutPoint(parse_hex("430cb60ee816e2631d6d9605659c18fec8eb3de94526f5fd4ad51feaad6f1664"), 0) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto& cell2 = *input.add_cell(); + cell2.set_capacity(14400000000); + *cell2.mutable_out_point() = + OutPoint(parse_hex("378b6bd2f7fc2b1599ee55be7e8fa17fdd6e0d25e2e146d5f46006e0292d6564"), 0) + .proto(); + *cell2.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + *cell2.mutable_type() = + Script(parse_hex("5e7a36a77e68eecc013dfa2fe6a23f3b6c344b04005808694ae6dd45eea4cfd5"), + HashType::Type1, + parse_hex("9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8")) + .proto(); + auto cell2Data = parse_hex("00601e253b6b4c000000000000000000"); + *cell2.mutable_data() = std::string(cell2Data.begin(), cell2Data.end()); + + auto privateKey = parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey.begin(), privateKey.end())); + + return input; +} + +TEST(NervosSigner, Sign_SUDT_SendMaximum) { + auto input = getInput4(); + TransactionPlan txPlan; + txPlan.plan(input); + ASSERT_EQ(txPlan.error, Common::Proto::SigningError::OK); + Transaction tx; + tx.build(txPlan); + auto error = tx.sign(getPrivateKeys(input)); + + ASSERT_EQ(error, Common::Proto::SigningError::OK); + + // https://explorer.nervos.org/transaction/0x09a45a15e48f985b554a0b6e5f0857913cc492ec061cc9b0b2befa4b24609a4a + ASSERT_EQ(tx.hash(), + parse_hex("09a45a15e48f985b554a0b6e5f0857913cc492ec061cc9b0b2befa4b24609a4a")); + + ASSERT_EQ(tx.cellDeps.size(), 2ul); + + ASSERT_EQ(tx.cellDeps[0].outPoint.txHash, + parse_hex("71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c")); + ASSERT_EQ(tx.cellDeps[0].outPoint.index, 0ul); + ASSERT_EQ(tx.cellDeps[0].depType, DepType::DepGroup); + + ASSERT_EQ(tx.cellDeps[1].outPoint.txHash, + parse_hex("c7813f6a415144643970c2e88e0bb6ca6a8edc5dd7c1022746f628284a9936d5")); + ASSERT_EQ(tx.cellDeps[1].outPoint.index, 0ul); + ASSERT_EQ(tx.cellDeps[1].depType, DepType::Code); + + ASSERT_EQ(tx.headerDeps.size(), 0ul); + + ASSERT_EQ(tx.inputs.size(), 2ul); + + ASSERT_EQ(tx.inputs[0].previousOutput.txHash, + parse_hex("378b6bd2f7fc2b1599ee55be7e8fa17fdd6e0d25e2e146d5f46006e0292d6564")); + ASSERT_EQ(tx.inputs[0].previousOutput.index, 0ul); + ASSERT_EQ(tx.inputs[0].since, 0ul); + + ASSERT_EQ(tx.inputs[1].previousOutput.txHash, + parse_hex("430cb60ee816e2631d6d9605659c18fec8eb3de94526f5fd4ad51feaad6f1664")); + ASSERT_EQ(tx.inputs[1].previousOutput.index, 0ul); + ASSERT_EQ(tx.inputs[1].since, 0ul); + + ASSERT_EQ(tx.outputs.size(), 2ul); + ASSERT_EQ(tx.outputsData.size(), 2ul); + + ASSERT_EQ(tx.outputs[0].capacity, 14400000000ul); + ASSERT_EQ(tx.outputs[0].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[0].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[0].lock.args, parse_hex("ab201f55b02f53b385f79b34dfad548e549b48fc")); + ASSERT_EQ(tx.outputs[0].type.codeHash, + parse_hex("5e7a36a77e68eecc013dfa2fe6a23f3b6c344b04005808694ae6dd45eea4cfd5")); + ASSERT_EQ(tx.outputs[0].type.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[0].type.args, + parse_hex("9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8")); + ASSERT_EQ(hex(tx.outputsData[0]), "00601e253b6b4c000000000000000000"); + + ASSERT_EQ(tx.outputs[1].capacity, 8210025567ul); + ASSERT_EQ(tx.outputs[1].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[1].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[1].lock.args, parse_hex("b0d65be39059d6489231b48f85ad706a560bbd8d")); + ASSERT_EQ(tx.outputs[1].type.codeHash.size(), 0ul); + ASSERT_EQ(tx.outputs[1].type.args.size(), 0ul); + ASSERT_EQ(tx.outputsData[1].size(), 0ul); + + ASSERT_EQ(tx.serializedWitnesses.size(), 2ul); + ASSERT_EQ( + hex(tx.serializedWitnesses[0]), + "5500000010000000550000005500000041000000da7c908bdf2cb091b7ff9bb682b762d1323c5e1ecf9b2ce0eb" + "edb9d55f6625c52ab14910ae401833112f2ea516ab11bc9ef691c3dff7886e3238c9348c3d73a701"); + ASSERT_EQ(hex(tx.serializedWitnesses[1]), ""); +} + +Proto::SigningInput getInput5() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_dao_deposit(); + + operation.set_to_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8f" + "urras980hksatlslfaktks7epf25"); + operation.set_change_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9e" + "rg8furras980hksatlslfaktks7epf25"); + + operation.set_amount(10200000000); + input.set_byte_fee(1); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(8210021909); + *cell1.mutable_out_point() = + OutPoint(parse_hex("c7dacd4aab49f5f9643e87752428cebde38eeb49c7726781c4d8b526822004a1"), 1) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqds6ed78yze6eyfyvd537z66ur22c9mmrgz82ama")) + .proto(); + + auto& cell2 = *input.add_cell(); + cell2.set_capacity(14399998167); + *cell2.mutable_out_point() = + OutPoint(parse_hex("d3c3263170815b326779e2fd8d548f846ae13eff9d9a82833c7071069a1d32bf"), 0) + .proto(); + *cell2.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto privateKey1 = + parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey1.begin(), privateKey1.end())); + auto privateKey2 = + parse_hex("0c8859a9d9084a8c2b55963268b352e258756f9240f2a1f4645c610ed191dae9"); + input.add_private_key(std::string(privateKey2.begin(), privateKey2.end())); + + return input; +} + +TEST(NervosSigner, Sign_DAO_Deposit) { + auto input = getInput5(); + + TransactionPlan txPlan; + txPlan.plan(input); + ASSERT_EQ(txPlan.error, Common::Proto::SigningError::OK); + Transaction tx; + tx.build(txPlan); + auto error = tx.sign(getPrivateKeys(input)); + + ASSERT_EQ(error, Common::Proto::SigningError::OK); + + // https://explorer.nervos.org/transaction/0x583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683 + ASSERT_EQ(tx.hash(), + parse_hex("583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683")); + + ASSERT_EQ(tx.cellDeps.size(), 2ul); + + ASSERT_EQ(tx.cellDeps[0].outPoint.txHash, + parse_hex("71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c")); + ASSERT_EQ(tx.cellDeps[0].outPoint.index, 0ul); + ASSERT_EQ(tx.cellDeps[0].depType, DepType::DepGroup); + + ASSERT_EQ(tx.cellDeps[1].outPoint.txHash, + parse_hex("e2fb199810d49a4d8beec56718ba2593b665db9d52299a0f9e6e75416d73ff5c")); + ASSERT_EQ(tx.cellDeps[1].outPoint.index, 2ul); + ASSERT_EQ(tx.cellDeps[1].depType, DepType::Code); + + ASSERT_EQ(tx.headerDeps.size(), 0ul); + + ASSERT_EQ(tx.inputs.size(), 2ul); + + ASSERT_EQ(tx.inputs[0].previousOutput.txHash, + parse_hex("c7dacd4aab49f5f9643e87752428cebde38eeb49c7726781c4d8b526822004a1")); + ASSERT_EQ(tx.inputs[0].previousOutput.index, 1ul); + ASSERT_EQ(tx.inputs[0].since, 0ul); + + ASSERT_EQ(tx.inputs[1].previousOutput.txHash, + parse_hex("d3c3263170815b326779e2fd8d548f846ae13eff9d9a82833c7071069a1d32bf")); + ASSERT_EQ(tx.inputs[1].previousOutput.index, 0ul); + ASSERT_EQ(tx.inputs[1].since, 0ul); + + ASSERT_EQ(tx.outputs.size(), 2ul); + ASSERT_EQ(tx.outputsData.size(), 2ul); + + ASSERT_EQ(tx.outputs[0].capacity, 10200000000ul); + ASSERT_EQ(tx.outputs[0].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[0].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[0].lock.args, parse_hex("c4b50c5c8d074f063ec0a77ded0eaff0fa7b65da")); + ASSERT_EQ(tx.outputs[0].type.codeHash, + parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e")); + ASSERT_EQ(tx.outputs[0].type.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[0].type.args, parse_hex("")); + ASSERT_EQ(hex(tx.outputsData[0]), "0000000000000000"); + + ASSERT_EQ(tx.outputs[1].capacity, 12410019377ul); + ASSERT_EQ(tx.outputs[1].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[1].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[1].lock.args, parse_hex("c4b50c5c8d074f063ec0a77ded0eaff0fa7b65da")); + ASSERT_EQ(tx.outputs[1].type.codeHash.size(), 0ul); + ASSERT_EQ(tx.outputs[1].type.args.size(), 0ul); + ASSERT_EQ(tx.outputsData[1].size(), 0ul); + + ASSERT_EQ(tx.serializedWitnesses.size(), 2ul); + ASSERT_EQ( + hex(tx.serializedWitnesses[0]), + "5500000010000000550000005500000041000000305d09c7de3f34a4d53bc4e0031ee59c95b9abc4fc3ff5548e" + "1a17ca726c069a232012c9c4be6ec4d4ffbe88613ca5e686e3e4b7d0b9bbd7038003e23ffdcdd601"); + ASSERT_EQ( + hex(tx.serializedWitnesses[1]), + "55000000100000005500000055000000410000007c514c77482dd1e1086f41a6d17364c9b5ed16364d61df6f7f" + "d8540f8bf7c131275c877943786b1b72fbf4f9d817ee5dd554a689808b7919543c691b5068e5be01"); +} + +Proto::SigningInput getInput6() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_dao_withdraw_phase1(); + + operation.set_change_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9e" + "rg8furras980hksatlslfaktks7epf25"); + auto& depositCell = *operation.mutable_deposit_cell(); + depositCell.set_capacity(10200000000); + *depositCell.mutable_out_point() = + OutPoint(parse_hex("583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683"), 0) + .proto(); + *depositCell.mutable_lock() = + Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8furras9" + "80hksatlslfaktks7epf25")) + .proto(); + *depositCell.mutable_type() = + Script(parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e"), + HashType::Type1, Data()) + .proto(); + auto depositCellData = parse_hex("0000000000000000"); + *depositCell.mutable_data() = std::string(depositCellData.begin(), depositCellData.end()); + depositCell.set_block_number(7575466); + auto blockHashData = + parse_hex("3dfdb4b702a355a5593315016f8af0537d5a2f3292811b79420ded78a092be6a"); + *depositCell.mutable_block_hash() = std::string(blockHashData.begin(), blockHashData.end()); + input.set_byte_fee(1); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(10200000000); + *cell1.mutable_out_point() = + OutPoint(parse_hex("583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683"), 0) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + *cell1.mutable_type() = + Script(parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e"), + HashType::Type1, Data()) + .proto(); + auto cell1Data = parse_hex("0000000000000000"); + *cell1.mutable_data() = std::string(cell1Data.begin(), cell1Data.end()); + + auto& cell2 = *input.add_cell(); + cell2.set_capacity(12410019377); + *cell2.mutable_out_point() = + OutPoint(parse_hex("583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683"), 1) + .proto(); + *cell2.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto privateKey1 = + parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey1.begin(), privateKey1.end())); + + return input; +} + +TEST(NervosSigner, Sign_DAO_Withdraw_Phase1) { + auto input = getInput6(); + + TransactionPlan txPlan; + txPlan.plan(input); + ASSERT_EQ(txPlan.error, Common::Proto::SigningError::OK); + Transaction tx; + tx.build(txPlan); + auto error = tx.sign(getPrivateKeys(input)); + + ASSERT_EQ(error, Common::Proto::SigningError::OK); + + // https://explorer.nervos.org/transaction/0xb4e62bc5f5108275b0ef3da8f8cc3fb0172843c4a2a9cdfef3b04d6c65e9acca + ASSERT_EQ(tx.hash(), + parse_hex("b4e62bc5f5108275b0ef3da8f8cc3fb0172843c4a2a9cdfef3b04d6c65e9acca")); + + ASSERT_EQ(tx.cellDeps.size(), 2ul); + + ASSERT_EQ(tx.cellDeps[0].outPoint.txHash, + parse_hex("71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c")); + ASSERT_EQ(tx.cellDeps[0].outPoint.index, 0ul); + ASSERT_EQ(tx.cellDeps[0].depType, DepType::DepGroup); + + ASSERT_EQ(tx.cellDeps[1].outPoint.txHash, + parse_hex("e2fb199810d49a4d8beec56718ba2593b665db9d52299a0f9e6e75416d73ff5c")); + ASSERT_EQ(tx.cellDeps[1].outPoint.index, 2ul); + ASSERT_EQ(tx.cellDeps[1].depType, DepType::Code); + + ASSERT_EQ(tx.headerDeps.size(), 1ul); + ASSERT_EQ(tx.headerDeps[0], + parse_hex("3dfdb4b702a355a5593315016f8af0537d5a2f3292811b79420ded78a092be6a")); + + ASSERT_EQ(tx.inputs.size(), 2ul); + + ASSERT_EQ(tx.inputs[0].previousOutput.txHash, + parse_hex("583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683")); + ASSERT_EQ(tx.inputs[0].previousOutput.index, 0ul); + ASSERT_EQ(tx.inputs[0].since, 0ul); + + ASSERT_EQ(tx.inputs[1].previousOutput.txHash, + parse_hex("583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683")); + ASSERT_EQ(tx.inputs[1].previousOutput.index, 1ul); + ASSERT_EQ(tx.inputs[1].since, 0ul); + + ASSERT_EQ(tx.outputs.size(), 2ul); + ASSERT_EQ(tx.outputsData.size(), 2ul); + + ASSERT_EQ(tx.outputs[0].capacity, 10200000000ul); + ASSERT_EQ(tx.outputs[0].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[0].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[0].lock.args, parse_hex("c4b50c5c8d074f063ec0a77ded0eaff0fa7b65da")); + ASSERT_EQ(tx.outputs[0].type.codeHash, + parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e")); + ASSERT_EQ(tx.outputs[0].type.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[0].type.args, parse_hex("")); + ASSERT_EQ(hex(tx.outputsData[0]), "aa97730000000000"); + + ASSERT_EQ(tx.outputs[1].capacity, 12410018646ul); + ASSERT_EQ(tx.outputs[1].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[1].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[1].lock.args, parse_hex("c4b50c5c8d074f063ec0a77ded0eaff0fa7b65da")); + ASSERT_EQ(tx.outputs[1].type.codeHash.size(), 0ul); + ASSERT_EQ(tx.outputs[1].type.args.size(), 0ul); + ASSERT_EQ(tx.outputsData[1].size(), 0ul); + + ASSERT_EQ(tx.serializedWitnesses.size(), 2ul); + ASSERT_EQ( + hex(tx.serializedWitnesses[0]), + "5500000010000000550000005500000041000000d5131c1a6b8eca11e2c280b72c5db09ea00bb788fd3262eace" + "d861c39db2aad04a36f9d174b6f167a9c98b85d2bccf537a163c44459d23467dfa86408f48dd5f01"); + ASSERT_EQ(tx.serializedWitnesses[1].size(), 0ul); +} + +Proto::SigningInput getInput7() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_dao_withdraw_phase2(); + + auto& depositCell = *operation.mutable_deposit_cell(); + depositCell.set_capacity(10200000000); + *depositCell.mutable_out_point() = + OutPoint(parse_hex("583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683"), 0) + .proto(); + *depositCell.mutable_lock() = + Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8furras9" + "80hksatlslfaktks7epf25")) + .proto(); + *depositCell.mutable_type() = + Script(parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e"), + HashType::Type1, Data()) + .proto(); + auto depositCellData = parse_hex("0000000000000000"); + *depositCell.mutable_data() = std::string(depositCellData.begin(), depositCellData.end()); + depositCell.set_block_number(7575466); + auto blockHashData1 = + parse_hex("3dfdb4b702a355a5593315016f8af0537d5a2f3292811b79420ded78a092be6a"); + *depositCell.mutable_block_hash() = std::string(blockHashData1.begin(), blockHashData1.end()); + + auto& withdrawingCell = *operation.mutable_withdrawing_cell(); + withdrawingCell.set_capacity(10200000000); + *withdrawingCell.mutable_out_point() = + OutPoint(parse_hex("b4e62bc5f5108275b0ef3da8f8cc3fb0172843c4a2a9cdfef3b04d6c65e9acca"), 0) + .proto(); + *withdrawingCell.mutable_lock() = + Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8furras9" + "80hksatlslfaktks7epf25")) + .proto(); + *withdrawingCell.mutable_type() = + Script(parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e"), + HashType::Type1, Data()) + .proto(); + auto withdrawingCellData = parse_hex("aa97730000000000"); + *withdrawingCell.mutable_data() = + std::string(withdrawingCellData.begin(), withdrawingCellData.end()); + withdrawingCell.set_block_number(7575534); + auto blockHashData2 = + parse_hex("b070d5364afd47c23fe267077d454009d6f665f200a915e68af1616e46f4aa52"); + *withdrawingCell.mutable_block_hash() = + std::string(blockHashData2.begin(), blockHashData2.end()); + withdrawingCell.set_since(0x20037c0000001731); + + operation.set_amount(10200000000); + input.set_byte_fee(1); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(10200000000); + *cell1.mutable_out_point() = + OutPoint(parse_hex("b4e62bc5f5108275b0ef3da8f8cc3fb0172843c4a2a9cdfef3b04d6c65e9acca"), 0) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + *cell1.mutable_type() = + Script(parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e"), + HashType::Type1, Data()) + .proto(); + auto cell1Data = parse_hex("aa97730000000000"); + *cell1.mutable_data() = std::string(cell1Data.begin(), cell1Data.end()); + + auto privateKey1 = + parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey1.begin(), privateKey1.end())); + + return input; +} + +TEST(NervosSigner, Sign_DAO_Withdraw_Phase2) { + auto input = getInput7(); + + TransactionPlan txPlan; + txPlan.plan(input); + ASSERT_EQ(txPlan.error, Common::Proto::SigningError::OK); + Transaction tx; + tx.build(txPlan); + auto error = tx.sign(getPrivateKeys(input)); + + ASSERT_EQ(error, Common::Proto::SigningError::OK); + + ASSERT_EQ(tx.hash(), + parse_hex("4fde13c93fc5d24ab7f660070aaa0b1725809d585f6258605e595cdbd856ea1c")); + + ASSERT_EQ(tx.cellDeps.size(), 2ul); + + ASSERT_EQ(tx.cellDeps[0].outPoint.txHash, + parse_hex("71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c")); + ASSERT_EQ(tx.cellDeps[0].outPoint.index, 0ul); + ASSERT_EQ(tx.cellDeps[0].depType, DepType::DepGroup); + + ASSERT_EQ(tx.cellDeps[1].outPoint.txHash, + parse_hex("e2fb199810d49a4d8beec56718ba2593b665db9d52299a0f9e6e75416d73ff5c")); + ASSERT_EQ(tx.cellDeps[1].outPoint.index, 2ul); + ASSERT_EQ(tx.cellDeps[1].depType, DepType::Code); + + ASSERT_EQ(tx.headerDeps.size(), 2ul); + ASSERT_EQ(tx.headerDeps[0], + parse_hex("3dfdb4b702a355a5593315016f8af0537d5a2f3292811b79420ded78a092be6a")); + ASSERT_EQ(tx.headerDeps[1], + parse_hex("b070d5364afd47c23fe267077d454009d6f665f200a915e68af1616e46f4aa52")); + + ASSERT_EQ(tx.inputs.size(), 1ul); + + ASSERT_EQ(tx.inputs[0].previousOutput.txHash, + parse_hex("b4e62bc5f5108275b0ef3da8f8cc3fb0172843c4a2a9cdfef3b04d6c65e9acca")); + ASSERT_EQ(tx.inputs[0].previousOutput.index, 0ul); + ASSERT_EQ(tx.inputs[0].since, 0x20037c0000001731ul); + + ASSERT_EQ(tx.outputs.size(), 1ul); + ASSERT_EQ(tx.outputsData.size(), 1ul); + + ASSERT_EQ(tx.outputs[0].capacity, 10199999532ul); + ASSERT_EQ(tx.outputs[0].lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(tx.outputs[0].lock.hashType, HashType::Type1); + ASSERT_EQ(tx.outputs[0].lock.args, parse_hex("c4b50c5c8d074f063ec0a77ded0eaff0fa7b65da")); + ASSERT_EQ(tx.outputs[0].type.codeHash.size(), 0ul); + ASSERT_EQ(tx.outputs[0].type.args.size(), 0ul); + ASSERT_EQ(tx.outputsData[0].size(), 0ul); + + ASSERT_EQ(tx.serializedWitnesses.size(), 1ul); + ASSERT_EQ(hex(tx.serializedWitnesses[0]), + "6100000010000000550000006100000041000000743f86c5557f4e2d3327f4d17e7bad27209b29c1e9cd" + "bab42ab03f7094af917b4b203ddd7f2e87102e09ae579f2fe7f6adb7900b7386b58c1183ba0011b7c421" + "00080000000000000000000000"); +} + +} // namespace TW::Nervos::tests diff --git a/tests/Nervos/TWAnyAddressTests.cpp b/tests/Nervos/TWAnyAddressTests.cpp new file mode 100644 index 00000000000..c948853f3ec --- /dev/null +++ b/tests/Nervos/TWAnyAddressTests.cpp @@ -0,0 +1,70 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "PrivateKey.h" +#include +#include +#include +#include +#include +#include + +#include "../interface/TWTestUtilities.h" +#include + +using namespace TW; + +TEST(TWAnyAddressNervos, AddressFromPublicKey) { + auto privateKey = + WRAP(TWPrivateKey, + TWPrivateKeyCreateWithData( + DATA("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb").get())); + ASSERT_NE(nullptr, privateKey.get()); + auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(privateKey.get(), true)); + ASSERT_NE(nullptr, publicKey.get()); + ASSERT_EQ(33ul, publicKey.get()->impl.bytes.size()); + auto address = + WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKey(publicKey.get(), TWCoinTypeNervos)); + auto addressString = WRAPS(TWAnyAddressDescription(address.get())); + assertStringsEqual(addressString, "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwy" + "k5x9erg8furras980hksatlslfaktks7epf25"); +} + +TEST(TWAnyAddressNervos, AddressFromString) { + auto address = + WRAP(TWAnyAddress, + TWAnyAddressCreateWithString(STRING("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthy" + "waa50xwsqwyk5x9erg8furras980hksatlslfaktks7epf25") + .get(), + TWCoinTypeNervos)); + ASSERT_NE(nullptr, address.get()); + auto addressString = WRAPS(TWAnyAddressDescription(address.get())); + assertStringsEqual(addressString, "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwy" + "k5x9erg8furras980hksatlslfaktks7epf25"); +} + +TEST(TWAnyAddressNervos, AddressFromWallet) { + auto wallet = WRAP( + TWHDWallet, + TWHDWalletCreateWithMnemonic( + STRING( + "alpha draw toss question picnic endless recycle wrong enable roast success palm") + .get(), + STRING("").get())); + auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeNervos)); + auto privateKeyData = WRAPD(TWPrivateKeyData(privateKey.get())); + EXPECT_EQ(TWDataSize(privateKeyData.get()), 32ul); + + auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(privateKey.get(), true)); + auto publicKeyData = WRAPD(TWPublicKeyData(publicKey.get())); + EXPECT_EQ(TWDataSize(publicKeyData.get()), 33ul); + assertHexEqual(publicKeyData, + "026c9e4cbb95d4b3a123c1fc80795feacc38029683a1b3e16bccf49bba25fb2858"); + + auto address = WRAPS(TWCoinTypeDeriveAddress(TWCoinTypeNervos, privateKey.get())); + assertStringsEqual(address, "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9er" + "g8furras980hksatlslfaktks7epf25"); +} diff --git a/tests/Nervos/TWAnySignerTests.cpp b/tests/Nervos/TWAnySignerTests.cpp new file mode 100644 index 00000000000..79a4b91079c --- /dev/null +++ b/tests/Nervos/TWAnySignerTests.cpp @@ -0,0 +1,665 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "Nervos/Address.h" +#include "Nervos/Serialization.h" +#include "Nervos/TransactionPlan.h" +#include "PublicKey.h" +#include "proto/Nervos.pb.h" +#include "uint256.h" +#include "../interface/TWTestUtilities.h" +#include + +#include + +namespace TW::Nervos::tests { + +Proto::SigningInput getAnySignerInput1() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_native_transfer(); + + operation.set_to_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02" + "wectaumxn0664yw2jd53lqk4mxg3"); + operation.set_change_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqds6ed78" + "yze6eyfyvd537z66ur22c9mmrgz82ama"); + operation.set_amount(10000000000); + input.set_byte_fee(1); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(100000000000); + *cell1.mutable_out_point() = + OutPoint(parse_hex("71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3"), 1) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto& cell2 = *input.add_cell(); + cell2.set_capacity(20000000000); + *cell2.mutable_out_point() = + OutPoint(parse_hex("71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3"), 0) + .proto(); + *cell2.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto privateKey = parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey.begin(), privateKey.end())); + + return input; +} + +void checkAnySignerOutput1(Proto::SigningOutput& output) { + ASSERT_EQ(output.error(), Common::Proto::OK); + // https://explorer.nervos.org/transaction/0xf2c32afde7e72011985583873bc16c0a3c01fc01fc161eb4b914fcf84c53cdf8 + ASSERT_EQ(output.transaction_id(), + "0xf2c32afde7e72011985583873bc16c0a3c01fc01fc161eb4b914fcf84c53cdf8"); + ASSERT_EQ( + output.transaction_json(), + "{\"cell_deps\":[{\"dep_type\":\"dep_group\",\"out_point\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c\"}}],\"header_deps\":" + "[],\"inputs\":[{\"previous_output\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0x71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3\"},\"since\":\"0x0\"}" + "],\"outputs\":[{\"capacity\":\"0x2540be400\",\"lock\":{\"args\":" + "\"0xab201f55b02f53b385f79b34dfad548e549b48fc\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":" + "\"type\"},\"type\":null},{\"capacity\":\"0x2540be230\",\"lock\":{\"args\":" + "\"0xb0d65be39059d6489231b48f85ad706a560bbd8d\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":" + "\"type\"},\"type\":null}],\"outputs_data\":[\"0x\",\"0x\"],\"version\":\"0x0\"," + "\"witnesses\":[" + "\"0x55000000100000005500000055000000410000002a9ef2ad7829e5ea0c7a32735d29a0cb2ec20434f6fd5b" + "f6e29cda56b28e08140156191cbbf80313d3c9cae4b74607acce7b28eb21d52ef058ed8491cdde70b700\"]}"); +} + +void checkPlan1(Proto::TransactionPlan& txPlanProto) { + ASSERT_EQ(txPlanProto.error(), Common::Proto::OK); + + ASSERT_EQ(txPlanProto.cell_deps_size(), 1); + + const auto cellDep1 = txPlanProto.cell_deps(0); + const auto cellDep1TxHash = + parse_hex("71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c"); + ASSERT_EQ(cellDep1.out_point().tx_hash(), + std::string(cellDep1TxHash.begin(), cellDep1TxHash.end())); + ASSERT_EQ(cellDep1.out_point().index(), 0ul); + ASSERT_EQ(cellDep1.dep_type(), "dep_group"); + + ASSERT_EQ(txPlanProto.header_deps_size(), 0); + + ASSERT_EQ(txPlanProto.selected_cells_size(), 1); + + auto cell1 = Cell(txPlanProto.selected_cells(0)); + ASSERT_EQ(cell1.outPoint.txHash, + parse_hex("71caea2d3ac9e3ea899643e3e67dd11eb587e7fe0d8c6e67255d0959fa0a1fa3")); + ASSERT_EQ(cell1.outPoint.index, 0ul); + ASSERT_EQ(cell1.capacity, 20000000000ul); + ASSERT_EQ(cell1.lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(cell1.lock.hashType, HashType::Type1); + ASSERT_EQ(cell1.lock.args, parse_hex("c4b50c5c8d074f063ec0a77ded0eaff0fa7b65da")); + ASSERT_EQ(cell1.type.codeHash.size(), 0ul); + ASSERT_EQ(cell1.type.args.size(), 0ul); + ASSERT_EQ(cell1.data.size(), 0ul); + + ASSERT_EQ(txPlanProto.outputs_size(), 2); + ASSERT_EQ(txPlanProto.outputs_data_size(), 2); + + auto cellOutput1 = CellOutput(txPlanProto.outputs(0)); + ASSERT_EQ(cellOutput1.capacity, 10000000000ul); + ASSERT_EQ(cellOutput1.lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(cellOutput1.lock.hashType, HashType::Type1); + ASSERT_EQ(cellOutput1.lock.args, parse_hex("ab201f55b02f53b385f79b34dfad548e549b48fc")); + ASSERT_EQ(cellOutput1.type.codeHash.size(), 0ul); + ASSERT_EQ(cellOutput1.type.args.size(), 0ul); + ASSERT_EQ(txPlanProto.outputs_data(0).length(), 0ul); + + auto cellOutput2 = CellOutput(txPlanProto.outputs(1)); + ASSERT_EQ(cellOutput2.capacity, 9999999536ul); + ASSERT_EQ(cellOutput2.lock.codeHash, + parse_hex("9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8")); + ASSERT_EQ(cellOutput2.lock.hashType, HashType::Type1); + ASSERT_EQ(cellOutput2.lock.args, parse_hex("b0d65be39059d6489231b48f85ad706a560bbd8d")); + ASSERT_EQ(cellOutput2.type.codeHash.size(), 0ul); + ASSERT_EQ(cellOutput2.type.args.size(), 0ul); + ASSERT_EQ(txPlanProto.outputs_data(1).length(), 0ul); +} + +TEST(TWAnySignerNervos, Sign_Native_Simple) { + auto input = getAnySignerInput1(); + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeNervos); + checkAnySignerOutput1(output); +} + +TEST(TWAnySignerNervos, PlanAndSign_Native_Simple) { + auto input = getAnySignerInput1(); + Proto::TransactionPlan txPlanProto; + ANY_PLAN(input, txPlanProto, TWCoinTypeNervos); + checkPlan1(txPlanProto); + *input.mutable_plan() = txPlanProto; + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeNervos); + checkAnySignerOutput1(output); +} + +TEST(TWAnySignerNervos, Sign_NegativeMissingKey) { + auto input = getAnySignerInput1(); + input.clear_private_key(); + auto privateKey = parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61fec"); + input.add_private_key(std::string(privateKey.begin(), privateKey.end())); + Proto::SigningOutput output; + + ANY_SIGN(input, TWCoinTypeNervos); + + ASSERT_EQ(output.error(), Common::Proto::Error_missing_private_key); +} + +TEST(TWAnySignerNervos, Sign_NegativeNotEnoughUtxos) { + auto input = getAnySignerInput1(); + auto& operation = *input.mutable_native_transfer(); + operation.set_amount(1000000000000); + Proto::SigningOutput output; + + ANY_SIGN(input, TWCoinTypeNervos); + + ASSERT_EQ(output.error(), Common::Proto::Error_not_enough_utxos); +} + +Proto::SigningInput getAnySignerInput2() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_native_transfer(); + + operation.set_to_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02" + "wectaumxn0664yw2jd53lqk4mxg3"); + operation.set_change_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqds6ed78" + "yze6eyfyvd537z66ur22c9mmrgz82ama"); + operation.set_use_max_amount(true); + input.set_byte_fee(1); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(11410040620); + *cell1.mutable_out_point() = + OutPoint(parse_hex("c75567c80dc9b97aaf4e5c23f4c7f37b077f2b33a50dd7abd952abfbd5beb247"), 0) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto privateKey = parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey.begin(), privateKey.end())); + + return input; +} + +TEST(TWAnySignerNervos, Sign_Native_SendMaximum) { + auto input = getAnySignerInput2(); + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeNervos); + ASSERT_EQ(output.error(), Common::Proto::OK); + // https://explorer.nervos.org/transaction/0x298f5e04b6900796614b89062eb96cec63c3b2c460d01058736a793b567bc5c8 + ASSERT_EQ(output.transaction_id(), + "0x298f5e04b6900796614b89062eb96cec63c3b2c460d01058736a793b567bc5c8"); + ASSERT_EQ( + output.transaction_json(), + "{\"cell_deps\":[{\"dep_type\":\"dep_group\",\"out_point\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c\"}}],\"header_deps\":" + "[],\"inputs\":[{\"previous_output\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0xc75567c80dc9b97aaf4e5c23f4c7f37b077f2b33a50dd7abd952abfbd5beb247\"},\"since\":\"0x0\"}" + "],\"outputs\":[{\"capacity\":\"0x2a81765c9\",\"lock\":{\"args\":" + "\"0xab201f55b02f53b385f79b34dfad548e549b48fc\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":" + "\"type\"},\"type\":null}],\"outputs_data\":[\"0x\"],\"version\":\"0x0\",\"witnesses\":[" + "\"0x5500000010000000550000005500000041000000daf6e65e5a1fe447a4feb7199886b6635c44738e04ea59" + "457608fb1c447e068026529d57b02014ddc144622f886153df426853f22083f8891461eeb50b5ce97d01\"]}"); +} + +Proto::SigningInput getAnySignerInput3() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_sudt_transfer(); + + operation.set_to_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02" + "wectaumxn0664yw2jd53lqk4mxg3"); + operation.set_change_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqds6ed78" + "yze6eyfyvd537z66ur22c9mmrgz82ama"); + uint256_t amount = 1000000000000000; + operation.set_amount(toString(amount)); + input.set_byte_fee(1); + auto sudtAddress = + parse_hex("9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8"); + *operation.mutable_sudt_address() = std::string(sudtAddress.begin(), sudtAddress.end()); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(14399998906); + *cell1.mutable_out_point() = + OutPoint(parse_hex("5b12911e7413e011f251c1fb5fae4e76fd5fcae4f0d4c6412dcc5b0bfcece823"), 0) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto& cell2 = *input.add_cell(); + cell2.set_capacity(14400000000); + *cell2.mutable_out_point() = + OutPoint(parse_hex("e118bd11a73d381daf288381ce182d92b6cf2f52d25886bbda9e1a61525c7c4a"), 0) + .proto(); + *cell2.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + *cell2.mutable_type() = + Script(parse_hex("5e7a36a77e68eecc013dfa2fe6a23f3b6c344b04005808694ae6dd45eea4cfd5"), + HashType::Type1, + parse_hex("9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8")) + .proto(); + auto cell2Data = parse_hex("00e0e4c9b9f84f000000000000000000"); + *cell2.mutable_data() = std::string(cell2Data.begin(), cell2Data.end()); + + auto& cell3 = *input.add_cell(); + cell3.set_capacity(8210025567); + *cell3.mutable_out_point() = + OutPoint(parse_hex("09a45a15e48f985b554a0b6e5f0857913cc492ec061cc9b0b2befa4b24609a4a"), 1) + .proto(); + *cell3.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqds6ed78yze6eyfyvd537z66ur22c9mmrgz82ama")) + .proto(); + + auto privateKey1 = + parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey1.begin(), privateKey1.end())); + auto privateKey2 = + parse_hex("0c8859a9d9084a8c2b55963268b352e258756f9240f2a1f4645c610ed191dae9"); + input.add_private_key(std::string(privateKey2.begin(), privateKey2.end())); + + return input; +} + +TEST(TWAnySignerNervos, Sign_SUDT_Simple) { + auto input = getAnySignerInput3(); + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeNervos); + ASSERT_EQ(output.error(), Common::Proto::OK); + // https://explorer.nervos.org/transaction/0x9b15f2bea26b98201540d8e20e8b1c21d96dd77ad246520b405c6aabb7173371 + ASSERT_EQ(output.transaction_id(), + "0x9b15f2bea26b98201540d8e20e8b1c21d96dd77ad246520b405c6aabb7173371"); + ASSERT_EQ( + output.transaction_json(), + "{\"cell_deps\":[{\"dep_type\":\"dep_group\",\"out_point\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c\"}},{\"dep_type\":" + "\"code\",\"out_point\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0xc7813f6a415144643970c2e88e0bb6ca6a8edc5dd7c1022746f628284a9936d5\"}}],\"header_deps\":" + "[],\"inputs\":[{\"previous_output\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0xe118bd11a73d381daf288381ce182d92b6cf2f52d25886bbda9e1a61525c7c4a\"},\"since\":\"0x0\"}" + ",{\"previous_output\":{\"index\":\"0x1\",\"tx_hash\":" + "\"0x09a45a15e48f985b554a0b6e5f0857913cc492ec061cc9b0b2befa4b24609a4a\"},\"since\":\"0x0\"}" + ",{\"previous_output\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0x5b12911e7413e011f251c1fb5fae4e76fd5fcae4f0d4c6412dcc5b0bfcece823\"},\"since\":\"0x0\"}" + "],\"outputs\":[{\"capacity\":\"0x35a4e9000\",\"lock\":{\"args\":" + "\"0xab201f55b02f53b385f79b34dfad548e549b48fc\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":" + "\"type\"},\"type\":{\"args\":" + "\"0x9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8\",\"code_hash\":" + "\"0x5e7a36a77e68eecc013dfa2fe6a23f3b6c344b04005808694ae6dd45eea4cfd5\",\"hash_type\":" + "\"type\"}},{\"capacity\":\"0x35a4e9000\",\"lock\":{\"args\":" + "\"0xb0d65be39059d6489231b48f85ad706a560bbd8d\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":" + "\"type\"},\"type\":{\"args\":" + "\"0x9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8\",\"code_hash\":" + "\"0x5e7a36a77e68eecc013dfa2fe6a23f3b6c344b04005808694ae6dd45eea4cfd5\",\"hash_type\":" + "\"type\"}},{\"capacity\":\"0x1e95b03db\",\"lock\":{\"args\":" + "\"0xb0d65be39059d6489231b48f85ad706a560bbd8d\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":" + "\"type\"},\"type\":null}],\"outputs_data\":[\"0x0080c6a47e8d03000000000000000000\"," + "\"0x00601e253b6b4c000000000000000000\",\"0x\"],\"version\":\"0x0\",\"witnesses\":[" + "\"0x550000001000000055000000550000004100000035d55fd46316f248552eb6af7ac9589c9ec533c4e5b718" + "96b05cdf697e2d18551ceff54d7b860ebb2f4dd5f6c5bb4af1da15460a7621f5aa4bc7d5585a0504de00\"," + "\"0x5500000010000000550000005500000041000000eaa4bf69126d3016ab786610f2f0668b2ef353915d623d" + "0b0184fc25cec3dcad6dc08a1504a2d7dd9faced17b041d79d4c21f1977e57859713360f5e3609583501\"," + "\"0x\"]}"); +} + +Proto::SigningInput getAnySignerInput4() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_sudt_transfer(); + + operation.set_to_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02" + "wectaumxn0664yw2jd53lqk4mxg3"); + operation.set_change_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqds6ed78" + "yze6eyfyvd537z66ur22c9mmrgz82ama"); + operation.set_use_max_amount(true); + input.set_byte_fee(1); + auto sudtAddress = + parse_hex("9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8"); + *operation.mutable_sudt_address() = std::string(sudtAddress.begin(), sudtAddress.end()); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(8210026306); + *cell1.mutable_out_point() = + OutPoint(parse_hex("430cb60ee816e2631d6d9605659c18fec8eb3de94526f5fd4ad51feaad6f1664"), 0) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto& cell2 = *input.add_cell(); + cell2.set_capacity(14400000000); + *cell2.mutable_out_point() = + OutPoint(parse_hex("378b6bd2f7fc2b1599ee55be7e8fa17fdd6e0d25e2e146d5f46006e0292d6564"), 0) + .proto(); + *cell2.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + *cell2.mutable_type() = + Script(parse_hex("5e7a36a77e68eecc013dfa2fe6a23f3b6c344b04005808694ae6dd45eea4cfd5"), + HashType::Type1, + parse_hex("9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8")) + .proto(); + auto cell2Data = parse_hex("00601e253b6b4c000000000000000000"); + *cell2.mutable_data() = std::string(cell2Data.begin(), cell2Data.end()); + + auto privateKey = parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey.begin(), privateKey.end())); + + return input; +} + +TEST(TWAnySignerNervos, Sign_SUDT_SendMaximum) { + auto input = getAnySignerInput4(); + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeNervos); + ASSERT_EQ(output.error(), Common::Proto::OK); + // https://explorer.nervos.org/transaction/0x09a45a15e48f985b554a0b6e5f0857913cc492ec061cc9b0b2befa4b24609a4a + ASSERT_EQ(output.transaction_id(), + "0x09a45a15e48f985b554a0b6e5f0857913cc492ec061cc9b0b2befa4b24609a4a"); + ASSERT_EQ(output.transaction_json(), + "{\"cell_deps\":[{\"dep_type\":\"dep_group\",\"out_point\":{\"index\":\"0x0\",\"tx_" + "hash\":\"0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c\"}},{" + "\"dep_type\":\"code\",\"out_point\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0xc7813f6a415144643970c2e88e0bb6ca6a8edc5dd7c1022746f628284a9936d5\"}}],\"header_" + "deps\":[],\"inputs\":[{\"previous_output\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0x378b6bd2f7fc2b1599ee55be7e8fa17fdd6e0d25e2e146d5f46006e0292d6564\"},\"since\":" + "\"0x0\"},{\"previous_output\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0x430cb60ee816e2631d6d9605659c18fec8eb3de94526f5fd4ad51feaad6f1664\"},\"since\":" + "\"0x0\"}],\"outputs\":[{\"capacity\":\"0x35a4e9000\",\"lock\":{\"args\":" + "\"0xab201f55b02f53b385f79b34dfad548e549b48fc\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_" + "type\":\"type\"},\"type\":{\"args\":" + "\"0x9657b32fcdc463e13ec9205914fd91c443822a949937ae94add9869e7f2e1de8\",\"code_" + "hash\":\"0x5e7a36a77e68eecc013dfa2fe6a23f3b6c344b04005808694ae6dd45eea4cfd5\"," + "\"hash_type\":\"type\"}},{\"capacity\":\"0x1e95b0c5f\",\"lock\":{\"args\":" + "\"0xb0d65be39059d6489231b48f85ad706a560bbd8d\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_" + "type\":\"type\"},\"type\":null}],\"outputs_data\":[" + "\"0x00601e253b6b4c000000000000000000\",\"0x\"],\"version\":\"0x0\",\"witnesses\":[" + "\"0x5500000010000000550000005500000041000000da7c908bdf2cb091b7ff9bb682b762d1323c5e1e" + "cf9b2ce0ebedb9d55f6625c52ab14910ae401833112f2ea516ab11bc9ef691c3dff7886e3238c9348c3d" + "73a701\",\"0x\"]}"); +} + +Proto::SigningInput getAnySignerInput5() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_dao_deposit(); + + operation.set_to_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8f" + "urras980hksatlslfaktks7epf25"); + operation.set_change_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9e" + "rg8furras980hksatlslfaktks7epf25"); + operation.set_amount(10200000000); + input.set_byte_fee(1); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(8210021909); + *cell1.mutable_out_point() = + OutPoint(parse_hex("c7dacd4aab49f5f9643e87752428cebde38eeb49c7726781c4d8b526822004a1"), 1) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqds6ed78yze6eyfyvd537z66ur22c9mmrgz82ama")) + .proto(); + + auto& cell2 = *input.add_cell(); + cell2.set_capacity(14399998167); + *cell2.mutable_out_point() = + OutPoint(parse_hex("d3c3263170815b326779e2fd8d548f846ae13eff9d9a82833c7071069a1d32bf"), 0) + .proto(); + *cell2.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto privateKey1 = + parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey1.begin(), privateKey1.end())); + auto privateKey2 = + parse_hex("0c8859a9d9084a8c2b55963268b352e258756f9240f2a1f4645c610ed191dae9"); + input.add_private_key(std::string(privateKey2.begin(), privateKey2.end())); + + return input; +} + +TEST(TWAnySignerNervos, Sign_DAO_Deposit) { + auto input = getAnySignerInput5(); + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeNervos); + ASSERT_EQ(output.error(), Common::Proto::OK); + // https://explorer.nervos.org/transaction/0x583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683 + ASSERT_EQ(output.transaction_id(), + "0x583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683"); + ASSERT_EQ( + output.transaction_json(), + "{\"cell_deps\":[{\"dep_type\":\"dep_group\",\"out_point\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c\"}},{\"dep_type\":" + "\"code\",\"out_point\":{\"index\":\"0x2\",\"tx_hash\":" + "\"0xe2fb199810d49a4d8beec56718ba2593b665db9d52299a0f9e6e75416d73ff5c\"}}],\"header_deps\":" + "[],\"inputs\":[{\"previous_output\":{\"index\":\"0x1\",\"tx_hash\":" + "\"0xc7dacd4aab49f5f9643e87752428cebde38eeb49c7726781c4d8b526822004a1\"},\"since\":\"0x0\"}" + ",{\"previous_output\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0xd3c3263170815b326779e2fd8d548f846ae13eff9d9a82833c7071069a1d32bf\"},\"since\":\"0x0\"}" + "],\"outputs\":[{\"capacity\":\"0x25ff7a600\",\"lock\":{\"args\":" + "\"0xc4b50c5c8d074f063ec0a77ded0eaff0fa7b65da\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":" + "\"type\"},\"type\":{\"args\":\"0x\",\"code_hash\":" + "\"0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e\",\"hash_type\":" + "\"type\"}},{\"capacity\":\"0x2e3b1de31\",\"lock\":{\"args\":" + "\"0xc4b50c5c8d074f063ec0a77ded0eaff0fa7b65da\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":" + "\"type\"},\"type\":null}],\"outputs_data\":[\"0x0000000000000000\",\"0x\"],\"version\":" + "\"0x0\",\"witnesses\":[" + "\"0x5500000010000000550000005500000041000000305d09c7de3f34a4d53bc4e0031ee59c95b9abc4fc3ff5" + "548e1a17ca726c069a232012c9c4be6ec4d4ffbe88613ca5e686e3e4b7d0b9bbd7038003e23ffdcdd601\"," + "\"0x55000000100000005500000055000000410000007c514c77482dd1e1086f41a6d17364c9b5ed16364d61df" + "6f7fd8540f8bf7c131275c877943786b1b72fbf4f9d817ee5dd554a689808b7919543c691b5068e5be01\"]}"); +} + +Proto::SigningInput getAnySignerInput6() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_dao_withdraw_phase1(); + + operation.set_change_address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9e" + "rg8furras980hksatlslfaktks7epf25"); + auto& depositCell = *operation.mutable_deposit_cell(); + depositCell.set_capacity(10200000000); + *depositCell.mutable_out_point() = + OutPoint(parse_hex("583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683"), 0) + .proto(); + *depositCell.mutable_lock() = + Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8furras9" + "80hksatlslfaktks7epf25")) + .proto(); + *depositCell.mutable_type() = + Script(parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e"), + HashType::Type1, Data()) + .proto(); + auto depositCellData = parse_hex("0000000000000000"); + *depositCell.mutable_data() = std::string(depositCellData.begin(), depositCellData.end()); + depositCell.set_block_number(7575466); + auto blockHashData = + parse_hex("3dfdb4b702a355a5593315016f8af0537d5a2f3292811b79420ded78a092be6a"); + *depositCell.mutable_block_hash() = std::string(blockHashData.begin(), blockHashData.end()); + input.set_byte_fee(1); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(10200000000); + *cell1.mutable_out_point() = + OutPoint(parse_hex("583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683"), 0) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + *cell1.mutable_type() = + Script(parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e"), + HashType::Type1, Data()) + .proto(); + auto cell1Data = parse_hex("0000000000000000"); + *cell1.mutable_data() = std::string(cell1Data.begin(), cell1Data.end()); + + auto& cell2 = *input.add_cell(); + cell2.set_capacity(12410019377); + *cell2.mutable_out_point() = + OutPoint(parse_hex("583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683"), 1) + .proto(); + *cell2.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + + auto privateKey1 = + parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey1.begin(), privateKey1.end())); + + return input; +} + +TEST(TWAnySignerNervos, Sign_DAO_Withdraw_Phase1) { + auto input = getAnySignerInput6(); + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeNervos); + ASSERT_EQ(output.error(), Common::Proto::OK); + // https://explorer.nervos.org/transaction/0xb4e62bc5f5108275b0ef3da8f8cc3fb0172843c4a2a9cdfef3b04d6c65e9acca + ASSERT_EQ(output.transaction_id(), + "0xb4e62bc5f5108275b0ef3da8f8cc3fb0172843c4a2a9cdfef3b04d6c65e9acca"); + ASSERT_EQ(output.transaction_json(), + "{\"cell_deps\":[{\"dep_type\":\"dep_group\",\"out_point\":{\"index\":\"0x0\",\"tx_" + "hash\":\"0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c\"}},{" + "\"dep_type\":\"code\",\"out_point\":{\"index\":\"0x2\",\"tx_hash\":" + "\"0xe2fb199810d49a4d8beec56718ba2593b665db9d52299a0f9e6e75416d73ff5c\"}}],\"header_" + "deps\":[\"0x3dfdb4b702a355a5593315016f8af0537d5a2f3292811b79420ded78a092be6a\"]," + "\"inputs\":[{\"previous_output\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0x583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683\"},\"since\":" + "\"0x0\"},{\"previous_output\":{\"index\":\"0x1\",\"tx_hash\":" + "\"0x583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683\"},\"since\":" + "\"0x0\"}],\"outputs\":[{\"capacity\":\"0x25ff7a600\",\"lock\":{\"args\":" + "\"0xc4b50c5c8d074f063ec0a77ded0eaff0fa7b65da\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_" + "type\":\"type\"},\"type\":{\"args\":\"0x\",\"code_hash\":" + "\"0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e\",\"hash_" + "type\":\"type\"}},{\"capacity\":\"0x2e3b1db56\",\"lock\":{\"args\":" + "\"0xc4b50c5c8d074f063ec0a77ded0eaff0fa7b65da\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_" + "type\":\"type\"},\"type\":null}],\"outputs_data\":[\"0xaa97730000000000\",\"0x\"]," + "\"version\":\"0x0\",\"witnesses\":[" + "\"0x5500000010000000550000005500000041000000d5131c1a6b8eca11e2c280b72c5db09ea00bb788" + "fd3262eaced861c39db2aad04a36f9d174b6f167a9c98b85d2bccf537a163c44459d23467dfa86408f48" + "dd5f01\",\"0x\"]}"); +} + +Proto::SigningInput getAnySignerInput7() { + auto input = Proto::SigningInput(); + auto& operation = *input.mutable_dao_withdraw_phase2(); + + auto& depositCell = *operation.mutable_deposit_cell(); + depositCell.set_capacity(10200000000); + *depositCell.mutable_out_point() = + OutPoint(parse_hex("583d77a037e86155b7ab79ac59fc9bb01640e2427e859467ea10c4a6f222b683"), 0) + .proto(); + *depositCell.mutable_lock() = + Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8furras9" + "80hksatlslfaktks7epf25")) + .proto(); + *depositCell.mutable_type() = + Script(parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e"), + HashType::Type1, Data()) + .proto(); + auto depositCellData = parse_hex("0000000000000000"); + *depositCell.mutable_data() = std::string(depositCellData.begin(), depositCellData.end()); + depositCell.set_block_number(7575466); + auto blockHashData1 = + parse_hex("3dfdb4b702a355a5593315016f8af0537d5a2f3292811b79420ded78a092be6a"); + *depositCell.mutable_block_hash() = std::string(blockHashData1.begin(), blockHashData1.end()); + + auto& withdrawingCell = *operation.mutable_withdrawing_cell(); + withdrawingCell.set_capacity(10200000000); + *withdrawingCell.mutable_out_point() = + OutPoint(parse_hex("b4e62bc5f5108275b0ef3da8f8cc3fb0172843c4a2a9cdfef3b04d6c65e9acca"), 0) + .proto(); + *withdrawingCell.mutable_lock() = + Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8furras9" + "80hksatlslfaktks7epf25")) + .proto(); + *withdrawingCell.mutable_type() = + Script(parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e"), + HashType::Type1, Data()) + .proto(); + auto withdrawingCellData = parse_hex("aa97730000000000"); + *withdrawingCell.mutable_data() = + std::string(withdrawingCellData.begin(), withdrawingCellData.end()); + withdrawingCell.set_block_number(7575534); + auto blockHashData2 = + parse_hex("b070d5364afd47c23fe267077d454009d6f665f200a915e68af1616e46f4aa52"); + *withdrawingCell.mutable_block_hash() = + std::string(blockHashData2.begin(), blockHashData2.end()); + withdrawingCell.set_since(0x20037c0000001731); + + operation.set_amount(10200000000); + input.set_byte_fee(1); + + auto& cell1 = *input.add_cell(); + cell1.set_capacity(10200000000); + *cell1.mutable_out_point() = + OutPoint(parse_hex("b4e62bc5f5108275b0ef3da8f8cc3fb0172843c4a2a9cdfef3b04d6c65e9acca"), 0) + .proto(); + *cell1.mutable_lock() = Script(Address("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50x" + "wsqwyk5x9erg8furras980hksatlslfaktks7epf25")) + .proto(); + *cell1.mutable_type() = + Script(parse_hex("82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e"), + HashType::Type1, Data()) + .proto(); + auto cell1Data = parse_hex("aa97730000000000"); + *cell1.mutable_data() = std::string(cell1Data.begin(), cell1Data.end()); + + auto privateKey1 = + parse_hex("8a2a726c44e46d1efaa0f9c2a8efed932f0e96d6050b914fde762ee285e61feb"); + input.add_private_key(std::string(privateKey1.begin(), privateKey1.end())); + + return input; +} + +TEST(TWAnySignerNervos, Sign_DAO_Withdraw_Phase2) { + auto input = getAnySignerInput7(); + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeNervos); + ASSERT_EQ(output.error(), Common::Proto::OK); + ASSERT_EQ(output.transaction_id(), + "0x4fde13c93fc5d24ab7f660070aaa0b1725809d585f6258605e595cdbd856ea1c"); + ASSERT_EQ( + output.transaction_json(), + "{\"cell_deps\":[{\"dep_type\":\"dep_group\",\"out_point\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c\"}},{\"dep_type\":" + "\"code\",\"out_point\":{\"index\":\"0x2\",\"tx_hash\":" + "\"0xe2fb199810d49a4d8beec56718ba2593b665db9d52299a0f9e6e75416d73ff5c\"}}],\"header_deps\":" + "[\"0x3dfdb4b702a355a5593315016f8af0537d5a2f3292811b79420ded78a092be6a\"," + "\"0xb070d5364afd47c23fe267077d454009d6f665f200a915e68af1616e46f4aa52\"],\"inputs\":[{" + "\"previous_output\":{\"index\":\"0x0\",\"tx_hash\":" + "\"0xb4e62bc5f5108275b0ef3da8f8cc3fb0172843c4a2a9cdfef3b04d6c65e9acca\"},\"since\":" + "\"0x20037c0000001731\"}],\"outputs\":[{\"capacity\":\"0x25ff7a42c\",\"lock\":{\"args\":" + "\"0xc4b50c5c8d074f063ec0a77ded0eaff0fa7b65da\",\"code_hash\":" + "\"0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8\",\"hash_type\":" + "\"type\"},\"type\":null}],\"outputs_data\":[\"0x\"],\"version\":\"0x0\",\"witnesses\":[" + "\"0x6100000010000000550000006100000041000000743f86c5557f4e2d3327f4d17e7bad27209b29c1e9cdba" + "b42ab03f7094af917b4b203ddd7f2e87102e09ae579f2fe7f6adb7900b7386b58c1183ba0011b7c42100080000" + "000000000000000000\"]}"); +} + +} // namespace TW::Nervos::tests \ No newline at end of file diff --git a/tests/Nervos/TWCoinTypeTests.cpp b/tests/Nervos/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..bff876ae0c3 --- /dev/null +++ b/tests/Nervos/TWCoinTypeTests.cpp @@ -0,0 +1,35 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "../interface/TWTestUtilities.h" +#include +#include + + +TEST(TWNervosCoinType, TWCoinType) { + const auto coin = TWCoinTypeNervos; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("t123")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("a12")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "nervos"); + assertStringsEqual(name, "Nervos"); + assertStringsEqual(symbol, "CKB"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 8); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainNervos); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); + assertStringsEqual(txUrl, "https://explorer.nervos.org/transaction/t123"); + assertStringsEqual(accUrl, "https://explorer.nervos.org/address/a12"); +} diff --git a/tests/Nervos/TWNervosAddressTests.cpp b/tests/Nervos/TWNervosAddressTests.cpp new file mode 100644 index 00000000000..2ba8dc05a0c --- /dev/null +++ b/tests/Nervos/TWNervosAddressTests.cpp @@ -0,0 +1,32 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "PrivateKey.h" +#include + +#include "../interface/TWTestUtilities.h" +#include + +namespace TW::Nervos::tests { + +const auto ckbAddress = "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8furras980hksatlslfaktks7epf25"; + +TEST(TWBitcoinAddress, Create) { + TWNervosAddress* addr = TWNervosAddressCreateWithString(STRING(ckbAddress).get()); + + const auto codeCash = WRAPD(TWNervosAddressCodeHash(addr)); + const auto args = WRAPD(TWNervosAddressArgs(addr)); + const auto hashType = WRAPS(TWNervosAddressHashType(addr)); + + assertHexEqual(codeCash, "9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8"); + assertHexEqual(args, "c4b50c5c8d074f063ec0a77ded0eaff0fa7b65da"); + assertStringsEqual(hashType, "type"); + + TWNervosAddressDelete(addr); +} + +} // namespace TW::Nervos::tests diff --git a/tests/Polkadot/AddressTests.cpp b/tests/Polkadot/AddressTests.cpp index 6cc3fb06368..d2b4b74a230 100644 --- a/tests/Polkadot/AddressTests.cpp +++ b/tests/Polkadot/AddressTests.cpp @@ -11,8 +11,7 @@ #include #include -using namespace TW; -using namespace TW::Polkadot; +namespace TW::Polkadot::tests { TEST(PolkadotAddress, Validation) { // Substrate ed25519 @@ -49,3 +48,5 @@ TEST(PolkadotAddress, FromString) { auto address = Address("15KRsCq9LLNmCxNFhGk55s5bEyazKefunDxUH24GFZwsTxyu"); ASSERT_EQ(address.string(), "15KRsCq9LLNmCxNFhGk55s5bEyazKefunDxUH24GFZwsTxyu"); } + +} // namespace TW::Polkadot::tests diff --git a/tests/Polkadot/SS58AddressTests.cpp b/tests/Polkadot/SS58AddressTests.cpp index a65ce6c965d..b8db84c66af 100644 --- a/tests/Polkadot/SS58AddressTests.cpp +++ b/tests/Polkadot/SS58AddressTests.cpp @@ -14,6 +14,8 @@ using namespace TW; +namespace TW::Polkadot::tests { + TEST(SS58Address, IsValid) { EXPECT_TRUE(SS58Address::isValid("15KRsCq9LLNmCxNFhGk55s5bEyazKefunDxUH24GFZwsTxyu", 0)); @@ -140,3 +142,5 @@ TEST(SS58Address, EncodeNetwork) { EXPECT_FALSE(SS58Address::encodeNetwork(0x4000, data)); EXPECT_FALSE(SS58Address::encodeNetwork(0x8000, data)); } + +} // namespace TW::Polkadot::tests diff --git a/tests/Polkadot/ScaleCodecTests.cpp b/tests/Polkadot/ScaleCodecTests.cpp index efdd07515c8..c31892fddea 100644 --- a/tests/Polkadot/ScaleCodecTests.cpp +++ b/tests/Polkadot/ScaleCodecTests.cpp @@ -12,8 +12,7 @@ #include using namespace TW; -using namespace TW::Polkadot; - +namespace TW::Polkadot::tests { TEST(PolkadotCodec, EncodeCompact) { ASSERT_EQ(hex(encodeCompact(0)), "00"); @@ -76,3 +75,5 @@ TEST(PolkadotCodec, EncodeEra) { ASSERT_EQ(hex(era1), "7200"); ASSERT_EQ(hex(era2), "1100"); } + +} // namespace TW::Polkadot::tests diff --git a/tests/Polkadot/SignerTests.cpp b/tests/Polkadot/SignerTests.cpp index 376a9402edf..17164a45ea4 100644 --- a/tests/Polkadot/SignerTests.cpp +++ b/tests/Polkadot/SignerTests.cpp @@ -18,7 +18,7 @@ #include -namespace TW::Polkadot { +namespace TW::Polkadot::tests { auto privateKey = PrivateKey(parse_hex("0xabf8e5bdbe30c65656c0a3cbd181ff8a56294a69dfedd27982aace4a76909115")); auto privateKeyIOS = PrivateKey(parse_hex("37932b086586a6675e66e562fe68bd3eeea4177d066619c602fe3efc290ada62")); auto privateKeyThrow2 = PrivateKey(parse_hex("70a794d4f1019c3ce002f33062f45029c4f930a56b3d20ec477f7668c6bbc37f")); @@ -336,4 +336,4 @@ TEST(PolkadotSigner, SignChillAndUnbond) { ASSERT_EQ(hex(output.encoded()), "d10184008361bd08ddca5fda28b5e2aa84dc2621de566e23e089e555a42194c3eaf2da7900c891ba102db672e378945d74cf7f399226a76b43cab502436971599255451597fc2599902e4b62c7ce85ecc3f653c693fef3232be620984b5bb5bcecbbd7b209d50318001a02080706070207004d446617"); } -} // namespace +} // namespace TW::Polkadot::tests diff --git a/tests/Polkadot/TWCoinTypeTests.cpp b/tests/Polkadot/TWCoinTypeTests.cpp index 82030aaeeec..f5504a5c30f 100644 --- a/tests/Polkadot/TWCoinTypeTests.cpp +++ b/tests/Polkadot/TWCoinTypeTests.cpp @@ -12,7 +12,6 @@ #include #include - TEST(TWPolkadotCoinType, TWCoinType) { auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypePolkadot)); From dfefb634ec147757257a1f996ca8ff18114259e0 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Mon, 22 Aug 2022 20:01:35 +0900 Subject: [PATCH 058/497] [Sample] Fix reading grp user/key from local.properties for Android (#2520) * Fix reading grp user/key from local.properties --- samples/android/app/build.gradle | 2 +- samples/android/build.gradle | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/samples/android/app/build.gradle b/samples/android/app/build.gradle index f25cde25f75..71479d4bac2 100644 --- a/samples/android/app/build.gradle +++ b/samples/android/app/build.gradle @@ -23,7 +23,7 @@ android { } project.ext { - walletcore_version = "2.9.5" + walletcore_version = "2.9.8" } dependencies { diff --git a/samples/android/build.gradle b/samples/android/build.gradle index 2ed2d65a3db..5aa93a5e31a 100644 --- a/samples/android/build.gradle +++ b/samples/android/build.gradle @@ -1,5 +1,15 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. +Properties properties = new Properties() +File localProps = new File(rootDir.absolutePath, "local.properties") +if (localProps.exists()) { + properties.load(localProps.newDataInputStream()) + println "Authenticating user: " + properties.getProperty("gpr.user") +} else { + println "local.properties not found, please create it next to build.gradle and set gpr.user and gpr.key (Create a GitHub package read only + non expiration token at https://github.com/settings/tokens)\n" + + "Or set GITHUB_USER and GITHUB_TOKEN environment variables" +} + buildscript { ext.kotlin_version = '1.3.50' repositories { @@ -19,8 +29,8 @@ allprojects { maven { url = uri("https://maven.pkg.github.com/trustwallet/wallet-core") credentials { - username = project.findProperty("gpr.user") as String?: System.getenv("GITHUB_USER") - password = project.findProperty("gpr.key") as String?: System.getenv("GITHUB_TOKEN") + username = properties.getProperty("gpr.user") as String?: System.getenv("GITHUB_USER") + password = properties.getProperty("gpr.key") as String?: System.getenv("GITHUB_TOKEN") } } } From 0131a96ad186950b43ea5c7a9c4ab8a8ca8c6814 Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Tue, 23 Aug 2022 07:07:31 +0100 Subject: [PATCH 059/497] [Fix] Fix ambigious reference compile error (#2530) --- src/Theta/Entry.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Theta/Entry.cpp b/src/Theta/Entry.cpp index 05875a67d7e..634a661a059 100644 --- a/src/Theta/Entry.cpp +++ b/src/Theta/Entry.cpp @@ -9,9 +9,10 @@ #include "Ethereum/Address.h" #include "Signer.h" -using namespace TW::Theta; -using namespace std; +namespace TW::Theta { void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Theta From 5acbf25248f25939bd747649b6857c0595d8fd74 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Wed, 24 Aug 2022 15:36:13 +0900 Subject: [PATCH 060/497] One more fix for unity build (#2532) * More fix found from Everscale pr * more fixes for sharing variable between tests * Fix namespace name --- tests/Bitcoin/BitcoinScriptTests.cpp | 3 ++- tests/Bitcoin/SegwitAddressTests.cpp | 4 +++- tests/Bitcoin/TWBitcoinScriptTests.cpp | 4 ++-- tests/Cardano/AddressTests.cpp | 5 ++++- tests/EOS/TransactionTests.cpp | 4 +++- tests/EncryptTests.cpp | 5 ++++- tests/HDWallet/HDWalletInternalTests.cpp | 2 +- tests/HDWallet/HDWalletTests.cpp | 2 +- tests/Solana/TWAnySignerTests.cpp | 4 +++- 9 files changed, 23 insertions(+), 10 deletions(-) diff --git a/tests/Bitcoin/BitcoinScriptTests.cpp b/tests/Bitcoin/BitcoinScriptTests.cpp index cff0a76434f..15d3cf7fc5e 100644 --- a/tests/Bitcoin/BitcoinScriptTests.cpp +++ b/tests/Bitcoin/BitcoinScriptTests.cpp @@ -12,7 +12,7 @@ #include using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin::tests { const Script PayToScriptHash(parse_hex("a914" "4733f37cf4db86fbc2efed2500b4f4e49f312023" "87")); const Script PayToWitnessScriptHash(parse_hex("0020" "ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3db")); @@ -366,3 +366,4 @@ TEST(BitcoinTransactionSigner, PushAllEmpty) { EXPECT_EQ(hex(res), hex(expected)); } } +} // namespace TW::Bitcoin::tests diff --git a/tests/Bitcoin/SegwitAddressTests.cpp b/tests/Bitcoin/SegwitAddressTests.cpp index 8bb0783ec01..4545ff9dc86 100644 --- a/tests/Bitcoin/SegwitAddressTests.cpp +++ b/tests/Bitcoin/SegwitAddressTests.cpp @@ -14,7 +14,7 @@ #include using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin::tests { static const std::string valid_checksum[] = { "A12UEL5L", @@ -207,3 +207,5 @@ TEST(SegwitAddress, Equals) { ASSERT_TRUE(addr1 == addr1); ASSERT_FALSE(addr1 == addr2); } + +} // namespace TW::Bitcoin::tests diff --git a/tests/Bitcoin/TWBitcoinScriptTests.cpp b/tests/Bitcoin/TWBitcoinScriptTests.cpp index db0511e3ab8..064b83f50d9 100644 --- a/tests/Bitcoin/TWBitcoinScriptTests.cpp +++ b/tests/Bitcoin/TWBitcoinScriptTests.cpp @@ -11,7 +11,7 @@ #include -namespace TW::Bitcoin::tests { +namespace TW::Bitcoin::TWScriptTests { // clang-format off const auto PayToScriptHash = WRAP(TWBitcoinScript, TWBitcoinScriptCreateWithData(DATA("a914" "4733f37cf4db86fbc2efed2500b4f4e49f312023" "87").get())); @@ -242,4 +242,4 @@ TEST(TWBitcoinSigHashType, IsNone) { EXPECT_FALSE(TWBitcoinSigHashTypeIsNone(TWBitcoinSigHashTypeFork)); } -} // namespace TW::Bitcoin::tests +} // namespace TW::Bitcoin::TWScriptTests diff --git a/tests/Cardano/AddressTests.cpp b/tests/Cardano/AddressTests.cpp index 0cd6eae62b8..0b4a24218f5 100644 --- a/tests/Cardano/AddressTests.cpp +++ b/tests/Cardano/AddressTests.cpp @@ -13,10 +13,11 @@ #include -using namespace TW::Cardano; using namespace TW; using namespace std; +namespace TW::Cardano::tests { + const auto dummyKey = parse_hex("1111111111111111111111111111111111111111111111111111111111111111"); TEST(CardanoAddress, V3NetworkIdKind) { @@ -461,3 +462,5 @@ TEST(CardanoAddress, AssignmentOperatorLegacy) { EXPECT_TRUE(address.legacyAddressV2.has_value()); EXPECT_TRUE(*address.legacyAddressV2 == *addr3leg.legacyAddressV2); } + +} // namespace TW::Cardano::tests diff --git a/tests/EOS/TransactionTests.cpp b/tests/EOS/TransactionTests.cpp index 50e8860658d..65bfa0fb392 100644 --- a/tests/EOS/TransactionTests.cpp +++ b/tests/EOS/TransactionTests.cpp @@ -15,7 +15,7 @@ #include using namespace TW; -using namespace TW::EOS; +namespace TW::EOS::tests { static std::string k1Sigs[5] { "SIG_K1_KfCdjsrTnx5cBpbA5cUdHZAsRYsnC9uKzuS1shFeqfMCfdZwX4PBm9pfHwGRT6ffz3eavhtkyNci5GoFozQAx8P8PBnDmj", @@ -112,3 +112,5 @@ TEST(EOSTransaction, formatDate) { EXPECT_EQ(Transaction::formatDate(0), "1970-01-01T00:00:00"); EXPECT_EQ(Transaction::formatDate(std::numeric_limits::max()), "2038-01-19T03:14:07"); } + +} // namespace TW::EOS::tests diff --git a/tests/EncryptTests.cpp b/tests/EncryptTests.cpp index 85f20b1160f..74fe4a1f13a 100644 --- a/tests/EncryptTests.cpp +++ b/tests/EncryptTests.cpp @@ -12,9 +12,10 @@ #include -using namespace TW::Encrypt; using namespace TW; +namespace TW::Encrypt::test { + const Data gKey = parse_hex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); inline void assertHexEqual(const Data& data, const char* expected) { @@ -200,3 +201,5 @@ TEST(Encrypt, AESCTRDecryptInvalidKeySize) { } ADD_FAILURE() << "Missed expected exeption"; } + +} // namespace TW::Encrypt::tests diff --git a/tests/HDWallet/HDWalletInternalTests.cpp b/tests/HDWallet/HDWalletInternalTests.cpp index 763b2c9561b..10c7282a665 100644 --- a/tests/HDWallet/HDWalletInternalTests.cpp +++ b/tests/HDWallet/HDWalletInternalTests.cpp @@ -17,7 +17,7 @@ #include #include -namespace TW { +namespace TW::HDWalletInternalTests { const auto mnemonic1 = "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal"; diff --git a/tests/HDWallet/HDWalletTests.cpp b/tests/HDWallet/HDWalletTests.cpp index c646d801e91..fdf70a687d2 100644 --- a/tests/HDWallet/HDWalletTests.cpp +++ b/tests/HDWallet/HDWalletTests.cpp @@ -21,7 +21,7 @@ extern std::string TESTS_ROOT; -namespace TW { +namespace TW::HDWalletTests { const auto mnemonic1 = "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal"; const auto gPassphrase = "passphrase"; diff --git a/tests/Solana/TWAnySignerTests.cpp b/tests/Solana/TWAnySignerTests.cpp index d37800122a1..2a0dd1ca007 100644 --- a/tests/Solana/TWAnySignerTests.cpp +++ b/tests/Solana/TWAnySignerTests.cpp @@ -16,7 +16,7 @@ #include using namespace TW; -using namespace TW::Solana; +namespace TW::Solana::tests { const auto expectedString1 = "3p2kzZ1DvquqC6LApPuxpTg5CCDVPqJFokGSnGhnBHrta4uq7S2EyehV1XNUVXp51D69GxGzQZU" @@ -393,3 +393,5 @@ TEST(TWAnySignerSolana, SignJSON) { ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeSolana)); assertStringsEqual(result, expectedString1); } + +} // namespace TW::Solana::tests From 72c1a67383dd61f7a1d78a8323d0ff1528996d07 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 25 Aug 2022 20:33:22 +0900 Subject: [PATCH 061/497] Improve documents for C headers (#2315) * doc: add missing documentation for all c headers * persist code comment for generated code * improve generated comments indentation * Fix codegen test Co-authored-by: Milerius --- codegen/bin/newcoin | 2 +- codegen/lib/entity_decl.rb | 5 +- codegen/lib/enum_decl.rb | 5 +- codegen/lib/function_decl.rb | 5 +- codegen/lib/parser.rb | 75 ++-- codegen/lib/templates/java/class.erb | 11 +- codegen/lib/templates/java/enum.erb | 1 + codegen/lib/templates/java/header.erb | 2 +- codegen/lib/templates/java/struct.erb | 11 +- codegen/lib/templates/swift/class.erb | 2 + .../lib/templates/swift/class_properties.erb | 1 + codegen/lib/templates/swift/enum.erb | 1 + .../lib/templates/swift/enum_extension.erb | 2 +- codegen/lib/templates/swift/method.erb | 1 + codegen/lib/templates/swift/static_method.erb | 1 + codegen/lib/templates/swift/struct.erb | 2 + .../lib/templates/swift/struct_properties.erb | 1 + codegen/test/test_jni_helper.rb | 2 +- codegen/test/test_parser.rb | 6 +- include/TrustWalletCore/TWAES.h | 33 +- include/TrustWalletCore/TWAESPaddingMode.h | 3 +- include/TrustWalletCore/TWAccount.h | 50 ++- include/TrustWalletCore/TWAnyAddress.h | 31 +- include/TrustWalletCore/TWAnySigner.h | 27 +- include/TrustWalletCore/TWBase32.h | 1 + include/TrustWalletCore/TWBase58.h | 19 +- include/TrustWalletCore/TWBase64.h | 6 +- include/TrustWalletCore/TWBitcoinAddress.h | 39 +- include/TrustWalletCore/TWBitcoinScript.h | 160 ++++++-- .../TrustWalletCore/TWBitcoinSigHashType.h | 9 + include/TrustWalletCore/TWBlockchain.h | 1 + include/TrustWalletCore/TWCardano.h | 8 +- include/TrustWalletCore/TWCoinType.h | 60 ++- .../TrustWalletCore/TWCoinTypeConfiguration.h | 22 ++ include/TrustWalletCore/TWData.h | 59 ++- include/TrustWalletCore/TWDataVector.h | 31 +- include/TrustWalletCore/TWEthereumAbi.h | 17 +- .../TrustWalletCore/TWEthereumAbiFunction.h | 364 +++++++++++++++--- include/TrustWalletCore/TWEthereumAbiValue.h | 54 ++- include/TrustWalletCore/TWFIOAccount.h | 11 + .../TrustWalletCore/TWGroestlcoinAddress.h | 24 +- include/TrustWalletCore/TWHDVersion.h | 14 +- include/TrustWalletCore/TWHDWallet.h | 205 +++++++--- include/TrustWalletCore/TWHash.h | 72 ++++ include/TrustWalletCore/TWMnemonic.h | 12 +- include/TrustWalletCore/TWNEARAccount.h | 11 + include/TrustWalletCore/TWNervosAddress.h | 29 +- include/TrustWalletCore/TWPBKDF2.h | 3 + include/TrustWalletCore/TWPrivateKey.h | 76 +++- include/TrustWalletCore/TWPublicKey.h | 62 +++ include/TrustWalletCore/TWPurpose.h | 6 +- include/TrustWalletCore/TWRippleXAddress.h | 27 +- include/TrustWalletCore/TWSS58AddressType.h | 6 +- include/TrustWalletCore/TWSegwitAddress.h | 33 +- include/TrustWalletCore/TWSolanaAddress.h | 19 +- include/TrustWalletCore/TWStellarMemoType.h | 3 +- include/TrustWalletCore/TWStellarPassphrase.h | 1 + .../TrustWalletCore/TWStellarVersionByte.h | 9 +- include/TrustWalletCore/TWStoredKey.h | 163 +++++++- .../TWStoredKeyEncryptionLevel.h | 2 +- include/TrustWalletCore/TWString.h | 49 ++- include/TrustWalletCore/TWTHORChainSwap.h | 6 +- .../TrustWalletCore/TWTransactionCompiler.h | 53 ++- src/BinaryCoding.h | 6 +- src/DerivationPath.h | 2 +- src/Ethereum/Signer.h | 8 +- src/FIO/Action.h | 2 +- src/FIO/Encryption.h | 22 +- src/Harmony/Signer.h | 4 +- src/Keystore/StoredKey.h | 12 +- src/PublicKey.cpp | 2 +- src/PublicKey.h | 2 +- 72 files changed, 1740 insertions(+), 346 deletions(-) diff --git a/codegen/bin/newcoin b/codegen/bin/newcoin index 40d67e0bc26..b2336c50489 100755 --- a/codegen/bin/newcoin +++ b/codegen/bin/newcoin @@ -104,7 +104,7 @@ puts "New coin template for coin '#{coin_id}' requested" json_string = File.read('registry.json') coins = JSON.parse(json_string).sort_by { |x| x['name'] } -entity = EntityDecl.new(name: "New" + coin_id, is_struct: false) +entity = EntityDecl.new(name: "New" + coin_id, is_struct: false, comment: '') file = "new"+ coin_id generator = CodeGenerator.new(entities: [entity], files: [file], output_folder: ".") diff --git a/codegen/lib/entity_decl.rb b/codegen/lib/entity_decl.rb index f22a0ea6587..aee285ef97b 100644 --- a/codegen/lib/entity_decl.rb +++ b/codegen/lib/entity_decl.rb @@ -2,16 +2,17 @@ # Class or struct declaration class EntityDecl - attr_reader :name + attr_reader :name, :comment attr_accessor :is_struct, :methods, :properties, :static_methods, :static_properties - def initialize(name:, is_struct:) + def initialize(name:, is_struct:, comment:) @name = name @is_struct = is_struct @methods = [] @properties = [] @static_methods = [] @static_properties = [] + @comment = comment end def struct? diff --git a/codegen/lib/enum_decl.rb b/codegen/lib/enum_decl.rb index 303909dec82..0fae5774f50 100644 --- a/codegen/lib/enum_decl.rb +++ b/codegen/lib/enum_decl.rb @@ -2,11 +2,11 @@ # Enum declaration. class EnumDecl - attr_reader :name + attr_reader :name, :comment attr_accessor :cases, :raw_type attr_accessor :methods, :properties, :static_methods, :static_properties - def initialize(name:, raw_type:) + def initialize(name:, raw_type:, comment:) @name = name @cases = [] @raw_type = raw_type @@ -14,6 +14,7 @@ def initialize(name:, raw_type:) @properties = [] @static_methods = [] @static_properties = [] + @comment = comment end def struct? diff --git a/codegen/lib/function_decl.rb b/codegen/lib/function_decl.rb index cd5135f1231..de0a3f7853c 100644 --- a/codegen/lib/function_decl.rb +++ b/codegen/lib/function_decl.rb @@ -4,8 +4,9 @@ class FunctionDecl attr_reader :name, :entity attr_accessor :is_method, :return_type, :parameters, :static, :discardable_result + attr_accessor :comment, :comment_with_indent - def initialize(name:, entity:, is_method:, return_type: :void, parameters: [], static: false, discardable_result: false) + def initialize(name:, entity:, is_method:, return_type: :void, parameters: [], static: false, discardable_result: false, comment: '') @name = name @entity = entity @is_method = is_method @@ -13,6 +14,8 @@ def initialize(name:, entity:, is_method:, return_type: :void, parameters: [], s @parameters = parameters @static = static @discardable_result = discardable_result + @comment = comment + @comment_with_indent = comment.to_s.gsub('///', ' ///') end end diff --git a/codegen/lib/parser.rb b/codegen/lib/parser.rb index fab69837507..e4e287614a0 100644 --- a/codegen/lib/parser.rb +++ b/codegen/lib/parser.rb @@ -9,7 +9,7 @@ # C header parser class Parser - attr_reader :path, :entity + attr_reader :path, :entity, :entity_comment def initialize(path:, string: nil) @path = path @@ -19,32 +19,49 @@ def initialize(path:, string: nil) # Parses a C header file for class/struct declarations def parse + clear_comment until @buffer.eos? - break if @buffer.skip_until(/\n/).nil? + @buffer.skip(/\s*/) + + if !@buffer.scan(/\/\//).nil? + @entity_comment = @entity_comment + '//' + @buffer.scan_until(/(\r\n|\r|\n)/) + next + end + + if !@buffer.scan(/TW_EXTERN_C_BEGIN/).nil? + # This is to ignore very first comments from the file + clear_comment + next + end + + @entity_comment = @entity_comment.strip # Look for TW_EXPORT statements - @buffer.skip(/\s*/) - next if @buffer.scan(/TW_EXPORT_[A-Z_]+/).nil? - - # Handle statements - case @buffer[0] - when 'TW_EXPORT_CLASS' - handle_class - when 'TW_EXPORT_STRUCT' - handle_struct - when 'TW_EXPORT_ENUM' - handle_enum - when 'TW_EXPORT_FUNC' - handle_func - when 'TW_EXPORT_METHOD' - handle_method - when 'TW_EXPORT_PROPERTY' - handle_property - when 'TW_EXPORT_STATIC_METHOD' - handle_static_method - when 'TW_EXPORT_STATIC_PROPERTY' - handle_static_property + if !@buffer.scan(/TW_EXPORT_[A-Z_]+/).nil? + # Handle statements + case @buffer[0] + when 'TW_EXPORT_CLASS' + handle_class + when 'TW_EXPORT_STRUCT' + handle_struct + when 'TW_EXPORT_ENUM' + handle_enum + when 'TW_EXPORT_FUNC' + handle_func + when 'TW_EXPORT_METHOD' + handle_method + when 'TW_EXPORT_PROPERTY' + handle_property + when 'TW_EXPORT_STATIC_METHOD' + handle_static_method + when 'TW_EXPORT_STATIC_PROPERTY' + handle_static_property + end + + clear_comment end + + break if @buffer.skip_until(/\n/).nil? end @entity @@ -80,7 +97,7 @@ def parse_func @buffer.skip(/\s*/) scan_or_fail(/\w+/, 'Invalid function name') - func = FunctionDecl.new(name: @buffer[0], entity: @entity, is_method: true, return_type: return_type) + func = FunctionDecl.new(name: @buffer[0], entity: @entity, is_method: true, return_type: return_type, comment: @entity_comment) @buffer.skip(/\s*/) scan_or_fail(/\(/, 'Invalid function declaration. Expected (') @@ -117,7 +134,7 @@ def handle_class @buffer.skip(/\s*/) report_error 'Invalid type name' if @buffer.scan(/struct TW(\w+)\s*;/).nil? report_error 'Found more than one class/struct in the same file' unless @entity.nil? - @entity = EntityDecl.new(name: @buffer[1], is_struct: false) + @entity = EntityDecl.new(name: @buffer[1], is_struct: false, comment: @entity_comment) puts "Found a class #{@entity.name}" end @@ -125,7 +142,7 @@ def handle_struct @buffer.skip(/\s*/) report_error 'Invalid type name at' if @buffer.scan(/struct TW(\w+)\s*\{?/).nil? report_error 'Found more than one class/struct in the same file' unless @entity.nil? - @entity = EntityDecl.new(name: @buffer[1], is_struct: true) + @entity = EntityDecl.new(name: @buffer[1], is_struct: true, comment: @entity_comment) puts "Found a struct #{@buffer[1]}" end @@ -136,7 +153,7 @@ def handle_enum @buffer.skip(/\s*/) report_error 'Invalid enum' if @buffer.scan(/enum TW(\w+)\s*\{/).nil? - @entity = EnumDecl.new(name: @buffer[1], raw_type: TypeDecl.fromPrimitive(type)) + @entity = EnumDecl.new(name: @buffer[1], raw_type: TypeDecl.fromPrimitive(type), comment: @entity_comment) incremental_value = 0 until @buffer.eos? @@ -277,4 +294,8 @@ def report_error(message) def current_line_number @buffer.string[0..@buffer.pos].count("\n") + 1 end + + def clear_comment + @entity_comment = '' + end end diff --git a/codegen/lib/templates/java/class.erb b/codegen/lib/templates/java/class.erb index 8f9d3367739..69cd027f403 100644 --- a/codegen/lib/templates/java/class.erb +++ b/codegen/lib/templates/java/class.erb @@ -3,6 +3,7 @@ import java.util.HashSet; <% less = entity.static_methods.detect{ |i| i.name == 'Less' } -%> <% equal = entity.static_methods.detect{ |i| i.name == 'Equal' } -%> +<%= entity.comment %> <% if !less.nil? && !equal.nil? -%> public class <%= entity.name %> implements Comparable<<%= entity.name %>> { <% else -%> @@ -24,10 +25,10 @@ public class <%= entity.name %> { <% end -%> return instance; } - <%# Constructor declarations -%> <% entity.static_methods.each do |method| -%> <% next unless method.name.start_with?('Create') -%> +<%= method.comment_with_indent %> static native long native<%= method.name %>(<%= JavaHelper.parameters(method.parameters) %>); <% end -%> <%# Destructor declarations -%> @@ -35,9 +36,9 @@ public class <%= entity.name %> { <% next unless method.name.start_with?('Delete') -%> static native void native<%= method.name %>(long handle); <% end -%> - <%# Static property declarations -%> <% entity.static_properties.each do |property| -%> +<%= property.comment_with_indent %> <% if should_return_data(property) -%> public static native byte[] <%= JavaHelper.format_name(property.name) %>(<%= JavaHelper.parameters(property.parameters) %>); <% elsif should_return_string(property) -%> @@ -49,6 +50,7 @@ public class <%= entity.name %> { <%# Static method declarations -%> <% entity.static_methods.each do |method| -%> <% next if method.name.start_with?('Create') -%> +<%= method.comment_with_indent %> <% if should_return_data(method) -%> public static native byte[] <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters) %>); <% elsif should_return_string(method) -%> @@ -59,6 +61,7 @@ public class <%= entity.name %> { <% end -%> <%# Property declarations -%> <% entity.properties.each do |property| -%> +<%= property.comment_with_indent %> <% if should_return_data(property) -%> public native byte[] <%= JavaHelper.format_name(property.name) %>(<%= JavaHelper.parameters(property.parameters.drop(1)) %>); <% elsif should_return_string(property) -%> @@ -70,6 +73,7 @@ public class <%= entity.name %> { <%# Method declarations -%> <% entity.methods.each do |method| -%> <% next if method.name.start_with?('Delete') -%> +<%= method.comment_with_indent %> <% if should_return_data(method) -%> public native byte[] <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters.drop(1)) %>); <% elsif should_return_string(method) -%> @@ -82,10 +86,10 @@ public class <%= entity.name %> { <% compareMethod = JNIHelper.compareMethod(entity) -%> public native <%= JavaHelper.type(compareMethod.return_type) %> <%= JavaHelper.format_name(compareMethod.name) %>(<%= JavaHelper.parameters(compareMethod.parameters.drop(1)) %>); <% end -%> - <%# Constructors -%> <%- entity.static_methods.each do |method| -%> <%- next unless method.name.start_with?('Create') -%> +<%= method.comment_with_indent %> public <%= entity.name %>(<%= JavaHelper.parameters(method.parameters) %>) { nativeHandle = native<%= method.name %>(<%= JavaHelper.arguments(method.parameters) %>); if (nativeHandle == 0) { @@ -97,7 +101,6 @@ public class <%= entity.name %> { <%- end -%> } - <% unless entity.methods.select{ |x| x.name == "Delete" }.empty? -%> class <%= entity.name %>PhantomReference extends java.lang.ref.PhantomReference<<%= entity.name %>> { private static java.util.Set<<%= entity.name %>PhantomReference> references = new HashSet<<%= entity.name %>PhantomReference>(); diff --git a/codegen/lib/templates/java/enum.erb b/codegen/lib/templates/java/enum.erb index 27947182cc8..354b7c145a3 100644 --- a/codegen/lib/templates/java/enum.erb +++ b/codegen/lib/templates/java/enum.erb @@ -1,4 +1,5 @@ <% has_string = entity.cases.all? { |c| !c.string.nil? } -%> +<%= entity.comment %> <% type = entity.raw_type ? JavaHelper.type(entity.raw_type) : 'int' -%> public enum <%= entity.name %> { <%# Cases -%> diff --git a/codegen/lib/templates/java/header.erb b/codegen/lib/templates/java/header.erb index e596ae5e9fe..b1b1aeabc86 100644 --- a/codegen/lib/templates/java/header.erb +++ b/codegen/lib/templates/java/header.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/codegen/lib/templates/java/struct.erb b/codegen/lib/templates/java/struct.erb index 5499705670d..bb57cf25017 100644 --- a/codegen/lib/templates/java/struct.erb +++ b/codegen/lib/templates/java/struct.erb @@ -2,6 +2,7 @@ import java.security.InvalidParameterException; <% less = entity.static_methods.detect{ |i| i.name == 'Less' } -%> <% equal = entity.static_methods.detect{ |i| i.name == 'Equal' } -%> +<%= entity.comment %> <% if !less.nil? && !equal.nil? -%> public class <%= entity.name %> implements Comparable<<%= entity.name %>> { <% else -%> @@ -17,15 +18,15 @@ public class <%= entity.name %> { instance.bytes = bytes; return instance; } - <%# Constructor declarations -%> <%- entity.static_methods.each do |method| -%> <%- next unless method.name.start_with?('Init') -%> +<%= method.comment_with_indent %> static native byte[] <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters.drop(1)) %>); <%- end -%> - <%# Static property declarations -%> <%- entity.static_properties.each do |property| -%> +<%= property.comment_with_indent %> <%- if should_return_data(property) -%> public static native byte[] <%= JavaHelper.format_name(property.name) %>(<%= JavaHelper.parameters(property.parameters) %>); <%- else -%> @@ -35,6 +36,7 @@ public class <%= entity.name %> { <%# Static method declarations -%> <%- entity.static_methods.each do |method| -%> <%- next if method.name.start_with?('Init') -%> +<%= method.comment_with_indent %> <%- if should_return_data(method) -%> public static native byte[] <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters) %>); <%- else -%> @@ -43,6 +45,7 @@ public class <%= entity.name %> { <%- end -%> <%# Property declarations -%> <%- entity.properties.each do |property| -%> +<%= property.comment_with_indent %> <%- if should_return_data(property) -%> public native byte[] <%= JavaHelper.format_name(property.name) %>(<%= JavaHelper.parameters(property.parameters.drop(1)) %>); <%- else -%> @@ -52,6 +55,7 @@ public class <%= entity.name %> { <%# Method declarations -%> <%- entity.methods.each do |method| -%> <%- next if method.name.start_with?('Delete') -%> +<%= method.comment_with_indent %> <%- if should_return_data(method) -%> public native byte[] <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.parameters(method.parameters.drop(1)) %>); <%- else -%> @@ -62,16 +66,15 @@ public class <%= entity.name %> { <% compareMethod = JNIHelper.compareMethod(entity) -%> public native <%= JavaHelper.type(compareMethod.return_type) %> <%= JavaHelper.format_name(compareMethod.name) %>(<%= JavaHelper.parameters(compareMethod.parameters.drop(1)) %>); <% end -%> - <%# Constructors -%> <%- entity.static_methods.each do |method| -%> <%- next unless method.name.start_with?('Init') -%> +<%= method.comment_with_indent %> public <%= entity.name %>(<%= JavaHelper.parameters(method.parameters.drop(1)) %>) { bytes = <%= JavaHelper.format_name(method.name) %>(<%= JavaHelper.arguments(method.parameters.drop(1)) %>); if (bytes == null) { throw new InvalidParameterException(); } } - <%- end -%> } diff --git a/codegen/lib/templates/swift/class.erb b/codegen/lib/templates/swift/class.erb index 4d090e7bc70..3404e02778d 100644 --- a/codegen/lib/templates/swift/class.erb +++ b/codegen/lib/templates/swift/class.erb @@ -1,9 +1,11 @@ import Foundation <% protocols = SwiftHelper.protocol(entity) -%> +<%= entity.comment %> public final class <%= entity.name %><% unless protocols.empty? %>: <%= protocols.join(', ') %><% end %> { <%# Static properties -%> <% entity.static_properties.each do |property| -%> +<%= property.comment_with_indent %> public static var <%= SwiftHelper.format_name(property.name) %>: <%= SwiftHelper.type(property.return_type) %> { <%- if property.return_type.is_class || property.return_type.is_struct -%> return <%= SwiftHelper.type(property.return_type) %>(rawValue: TW<%= entity.name %><%= property.name %>()) diff --git a/codegen/lib/templates/swift/class_properties.erb b/codegen/lib/templates/swift/class_properties.erb index c36feb40cb7..25c9a7c4c9d 100644 --- a/codegen/lib/templates/swift/class_properties.erb +++ b/codegen/lib/templates/swift/class_properties.erb @@ -1,5 +1,6 @@ <%# Properties -%> <%- entity.properties.each do |property| -%> +<%= property.comment_with_indent %> public var <%= SwiftHelper.format_name(property.name) %>: <%= SwiftHelper.type(property.return_type) %> { <%= render('swift/method_forward.erb', { method: property }) -%> } diff --git a/codegen/lib/templates/swift/enum.erb b/codegen/lib/templates/swift/enum.erb index e54c283f148..6c1165edab5 100644 --- a/codegen/lib/templates/swift/enum.erb +++ b/codegen/lib/templates/swift/enum.erb @@ -1,4 +1,5 @@ <% has_string = entity.cases.all? { |c| !c.string.nil? } -%> +<%= entity.comment %> <% type = entity.raw_type ? SwiftHelper.type(entity.raw_type) : 'UInt32' -%> public enum <%= entity.name %>: <%= type %>, CaseIterable<% if has_string %>, CustomStringConvertible <% end %> { <%# Cases -%> diff --git a/codegen/lib/templates/swift/enum_extension.erb b/codegen/lib/templates/swift/enum_extension.erb index 133a6028953..c5f4f2d3f0c 100644 --- a/codegen/lib/templates/swift/enum_extension.erb +++ b/codegen/lib/templates/swift/enum_extension.erb @@ -1,7 +1,7 @@ extension <%= entity.name %> { <%# Properties -%> <%- entity.properties.each do |property| -%> - +<%= property.comment_with_indent %> public var <%= SwiftHelper.format_name(property.name) %>: <%= SwiftHelper.type(property.return_type) %> { <%= render('swift/method_forward.erb', { method: property, arguments: ["TW#{entity.name}(rawValue: rawValue)"] }) -%> } diff --git a/codegen/lib/templates/swift/method.erb b/codegen/lib/templates/swift/method.erb index d50b6a0629a..d9700123165 100644 --- a/codegen/lib/templates/swift/method.erb +++ b/codegen/lib/templates/swift/method.erb @@ -1,4 +1,5 @@ <% method = locals[:method] -%> +<%= method.comment_with_indent %> <% arguments = locals[:arguments] || ['rawValue'] + SwiftHelper.arguments(method.parameters.drop(1)) -%> <% if method.discardable_result -%> @discardableResult diff --git a/codegen/lib/templates/swift/static_method.erb b/codegen/lib/templates/swift/static_method.erb index 5a9638220cf..8ecd73229be 100644 --- a/codegen/lib/templates/swift/static_method.erb +++ b/codegen/lib/templates/swift/static_method.erb @@ -1,4 +1,5 @@ <% method = locals[:method] -%> +<%= method.comment_with_indent %> <% arguments = SwiftHelper.arguments(method.parameters) -%> <% if method.discardable_result -%> @discardableResult diff --git a/codegen/lib/templates/swift/struct.erb b/codegen/lib/templates/swift/struct.erb index e7c3b2ca7ea..518588bd0ac 100644 --- a/codegen/lib/templates/swift/struct.erb +++ b/codegen/lib/templates/swift/struct.erb @@ -1,9 +1,11 @@ import Foundation <% protocols = SwiftHelper.protocol(entity) -%> +<%= entity.comment %> public struct <%= entity.name %><% unless protocols.empty? %>: <%= protocols.join(', ') %><% end %> { <%# Static properties -%> <% entity.static_properties.each do |property| -%> +<%= property.comment_with_indent %> public static var <%= SwiftHelper.format_name(property.name) %>: <%= SwiftHelper.type(property.return_type) %> { <%- if property.return_type.is_class || property.return_type.is_struct -%> return <%= SwiftHelper.type(property.return_type) %>(rawValue: TW<%= entity.name %><%= property.name %>()) diff --git a/codegen/lib/templates/swift/struct_properties.erb b/codegen/lib/templates/swift/struct_properties.erb index ebd50de5629..10d896df1e4 100644 --- a/codegen/lib/templates/swift/struct_properties.erb +++ b/codegen/lib/templates/swift/struct_properties.erb @@ -1,6 +1,7 @@ <%# Properties -%> <%- entity.properties.each do |property| -%> +<%= property.comment_with_indent %> public var <%= SwiftHelper.format_name(property.name) %>: <%= SwiftHelper.type(property.return_type) %> { <%= render('swift/method_forward.erb', { method: property }) -%> } diff --git a/codegen/test/test_jni_helper.rb b/codegen/test/test_jni_helper.rb index 766c8dfdcf7..595ff1e53e2 100644 --- a/codegen/test/test_jni_helper.rb +++ b/codegen/test/test_jni_helper.rb @@ -8,7 +8,7 @@ def test_format_name end def test_function_name - entity = EntityDecl.new(name: 'Test', is_struct: false) + entity = EntityDecl.new(name: 'Test', is_struct: false, comment: '') method = FunctionDecl.new(name: 'Function', entity: entity, is_method: true) name = JNIHelper.function_name(entity: entity, function: method) assert_equal(name, 'Java_wallet_core_jni_Test_function') diff --git a/codegen/test/test_parser.rb b/codegen/test/test_parser.rb index 6f51a726695..7ec0af335e8 100644 --- a/codegen/test/test_parser.rb +++ b/codegen/test/test_parser.rb @@ -44,22 +44,26 @@ def test_parse_invalid_method def test_parse_method_discardable_result parser = Parser.new(path: '', string: ' + // This is a sample file TW_EXTERN_C_BEGIN struct TWEthereumAbiFunction; + // Ethereuem ABI helpers TW_EXPORT_CLASS struct TWEthereumAbiEncoder; - /// Encode function to Eth ABI binary + // Encode function to Eth ABI binary TW_EXPORT_STATIC_METHOD TW_METHOD_DISCARDABLE_RESULT TWData*_Nonnull TWEthereumAbiEncoderEncode(struct TWEthereumAbiFunction *_Nonnull func_in); TW_EXTERN_C_END ') parser.parse + assert_equal(parser.entity.name, 'EthereumAbiEncoder') method = parser.entity.static_methods[0] assert_equal(method.return_type.name, :data) assert_equal(method.name, 'Encode') assert_equal(method.discardable_result, true) + assert_equal(method.comment, '// Encode function to Eth ABI binary') end def test_init diff --git a/include/TrustWalletCore/TWAES.h b/include/TrustWalletCore/TWAES.h index 510d2f32291..b44041f36f2 100644 --- a/include/TrustWalletCore/TWAES.h +++ b/include/TrustWalletCore/TWAES.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,40 +12,47 @@ TW_EXTERN_C_BEGIN +/// AES encryption/decryption methods. TW_EXPORT_STRUCT struct TWAES { uint8_t unused; // C doesn't allow zero-sized struct }; -/// Encrypts a block of data using AES in Cipher Block Chaining (CBC) mode. +/// Encrypts a block of Data using AES in Cipher Block Chaining (CBC) mode. /// -/// \param key encryption key, must be 16, 24, or 32 bytes long. -/// \param data data to encrypt. +/// \param key encryption key Data, must be 16, 24, or 32 bytes long. +/// \param data Data to encrypt. /// \param iv initialization vector. +/// \param mode padding mode. +/// \return encrypted Data. TW_EXPORT_STATIC_METHOD TWData *_Nullable TWAESEncryptCBC(TWData *_Nonnull key, TWData *_Nonnull data, TWData *_Nonnull iv, enum TWAESPaddingMode mode); /// Decrypts a block of data using AES in Cipher Block Chaining (CBC) mode. /// -/// \param key decryption key, must be 16, 24, or 32 bytes long. -/// \param data data to decrypt. -/// \param iv initialization vector. +/// \param key decryption key Data, must be 16, 24, or 32 bytes long. +/// \param data Data to decrypt. +/// \param iv initialization vector Data. +/// \param mode padding mode. +/// \return decrypted Data. TW_EXPORT_STATIC_METHOD TWData *_Nullable TWAESDecryptCBC(TWData *_Nonnull key, TWData *_Nonnull data, TWData *_Nonnull iv, enum TWAESPaddingMode mode); /// Encrypts a block of data using AES in Counter (CTR) mode. /// -/// \param key encryption key, must be 16, 24, or 32 bytes long. -/// \param data data to encrypt. -/// \param iv initialization vector. +/// \param key encryption key Data, must be 16, 24, or 32 bytes long. +/// \param data Data to encrypt. +/// \param iv initialization vector Data. +/// \return encrypted Data. TW_EXPORT_STATIC_METHOD TWData *_Nullable TWAESEncryptCTR(TWData *_Nonnull key, TWData *_Nonnull data, TWData *_Nonnull iv); /// Decrypts a block of data using AES in Counter (CTR) mode. /// -/// \param key decryption key, must be 16, 24, or 32 bytes long. -/// \param data data to decrypt. -/// \param iv initialization vector. +/// \param key decryption key Data, must be 16, 24, or 32 bytes long. +/// \param data Data to decrypt. +/// \param iv initialization vector Data. +/// \return decrypted Data. TW_EXPORT_STATIC_METHOD TWData *_Nullable TWAESDecryptCTR(TWData *_Nonnull key, TWData *_Nonnull data, TWData *_Nonnull iv); diff --git a/include/TrustWalletCore/TWAESPaddingMode.h b/include/TrustWalletCore/TWAESPaddingMode.h index 9e4713d0ed6..5cfe2103172 100644 --- a/include/TrustWalletCore/TWAESPaddingMode.h +++ b/include/TrustWalletCore/TWAESPaddingMode.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,6 +10,7 @@ TW_EXTERN_C_BEGIN +/// Padding mode used in AES encryption. TW_EXPORT_ENUM(uint32_t) enum TWAESPaddingMode { TWAESPaddingModeZero = 0, // padding value is zero diff --git a/include/TrustWalletCore/TWAccount.h b/include/TrustWalletCore/TWAccount.h index 591005d5ceb..c5d6f5e33ce 100644 --- a/include/TrustWalletCore/TWAccount.h +++ b/include/TrustWalletCore/TWAccount.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,38 +7,72 @@ #pragma once #include "TWBase.h" -#include "TWString.h" #include "TWCoinType.h" #include "TWDerivation.h" +#include "TWString.h" TW_EXTERN_C_BEGIN -/// Account for a particular coin within a wallet. +/// Represents an Account in C++ with address, coin type and public key info, an item within a keystore. TW_EXPORT_CLASS struct TWAccount; +/// Creates a new Account with an address, a coin type, derivation enum, derivationPath, publicKey, +/// and extendedPublicKey. Must be deleted with TWAccountDelete after use. +/// +/// \param address The address of the Account. +/// \param coin The coin type of the Account. +/// \param derivation The derivation of the Account. +/// \param derivationPath The derivation path of the Account. +/// \param publicKey hex encoded public key. +/// \param extendedPublicKey Base58 encoded extended public key. +/// \return A new Account. TW_EXPORT_STATIC_METHOD -struct TWAccount *_Nonnull TWAccountCreate(TWString *_Nonnull address, enum TWCoinType coin, enum TWDerivation derivation, TWString *_Nonnull derivationPath, TWString *_Nonnull publicKey, TWString *_Nonnull extendedPublicKey); - +struct TWAccount* _Nonnull TWAccountCreate(TWString* _Nonnull address, enum TWCoinType coin, + enum TWDerivation derivation, + TWString* _Nonnull derivationPath, + TWString* _Nonnull publicKey, + TWString* _Nonnull extendedPublicKey); +/// Deletes an account. +/// +/// \param account Account to delete. TW_EXPORT_METHOD void TWAccountDelete(struct TWAccount *_Nonnull account); +/// Returns the address of an account. +/// +/// \param account Account to get the address of. TW_EXPORT_PROPERTY TWString *_Nonnull TWAccountAddress(struct TWAccount *_Nonnull account); +/// Returns the derivation enum of an account. +/// +/// \param account Account to get the derivation enum of. TW_EXPORT_PROPERTY enum TWDerivation TWAccountDerivation(struct TWAccount *_Nonnull account); +/// Returns derivationPath of an account. +/// +/// \param account Account to get the derivation path of. TW_EXPORT_PROPERTY TWString *_Nonnull TWAccountDerivationPath(struct TWAccount *_Nonnull account); +/// Returns hex encoded publicKey of an account. +/// +/// \param account Account to get the public key of. TW_EXPORT_PROPERTY -TWString *_Nonnull TWAccountPublicKey(struct TWAccount *_Nonnull account); +TWString* _Nonnull TWAccountPublicKey(struct TWAccount* _Nonnull account); +/// Returns Base58 encoded extendedPublicKey of an account. +/// +/// \param account Account to get the extended public key of. TW_EXPORT_PROPERTY -TWString *_Nonnull TWAccountExtendedPublicKey(struct TWAccount *_Nonnull account); +TWString* _Nonnull TWAccountExtendedPublicKey(struct TWAccount* _Nonnull account); +/// Return CoinType enum of an account. +/// +/// \param account Account to get the coin type of. TW_EXPORT_PROPERTY -enum TWCoinType TWAccountCoin(struct TWAccount *_Nonnull account); +enum TWCoinType TWAccountCoin(struct TWAccount* _Nonnull account); TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWAnyAddress.h b/include/TrustWalletCore/TWAnyAddress.h index ff84d55e907..a815607989e 100644 --- a/include/TrustWalletCore/TWAnyAddress.h +++ b/include/TrustWalletCore/TWAnyAddress.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -15,38 +15,63 @@ TW_EXTERN_C_BEGIN struct TWPublicKey; -/// Represents Any blockchain address. +/// Represents an address in C++ for almost any blockchain. TW_EXPORT_CLASS struct TWAnyAddress; /// Compares two addresses for equality. +/// +/// \param lhs The first address to compare. +/// \param rhs The second address to compare. +/// \return bool indicating the addresses are equal. TW_EXPORT_STATIC_METHOD bool TWAnyAddressEqual(struct TWAnyAddress* _Nonnull lhs, struct TWAnyAddress* _Nonnull rhs); /// Determines if the string is a valid Any address. +/// +/// \param string address to validate. +/// \param coin coin type of the address. +/// \return bool indicating if the address is valid. TW_EXPORT_STATIC_METHOD bool TWAnyAddressIsValid(TWString* _Nonnull string, enum TWCoinType coin); -/// Creates an address from a string representation. +/// Creates an address from a string representation and a coin type. Must be deleted with TWAnyAddressDelete after use. +/// +/// \param string address to create. +/// \param coin coin type of the address. +/// \return TWAnyAddress pointer or nullptr if address and coin are invalid. TW_EXPORT_STATIC_METHOD struct TWAnyAddress* _Nullable TWAnyAddressCreateWithString(TWString* _Nonnull string, enum TWCoinType coin); /// Creates an address from a public key. +/// +/// \param publicKey derivates the address from the public key. +/// \param coin coin type of the address. +/// \return TWAnyAddress pointer or nullptr if public key is invalid. TW_EXPORT_STATIC_METHOD struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKey(struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin); +/// Deletes an address. +/// +/// \param address address to delete. TW_EXPORT_METHOD void TWAnyAddressDelete(struct TWAnyAddress* _Nonnull address); /// Returns the address string representation. +/// +/// \param address address to get the string representation of. TW_EXPORT_PROPERTY TWString* _Nonnull TWAnyAddressDescription(struct TWAnyAddress* _Nonnull address); /// Returns coin type of address. +/// +/// \param address address to get the coin type of. TW_EXPORT_PROPERTY enum TWCoinType TWAnyAddressCoin(struct TWAnyAddress* _Nonnull address); /// Returns underlaying data (public key or key hash) +/// +/// \param address address to get the data of. TW_EXPORT_PROPERTY TWData* _Nonnull TWAnyAddressData(struct TWAnyAddress* _Nonnull address); diff --git a/include/TrustWalletCore/TWAnySigner.h b/include/TrustWalletCore/TWAnySigner.h index f4246843baf..f3864bcfa83 100644 --- a/include/TrustWalletCore/TWAnySigner.h +++ b/include/TrustWalletCore/TWAnySigner.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,18 +12,35 @@ TW_EXTERN_C_BEGIN -/// Helper class to sign any transactions. +/// Represents a signer to sign transactions for any blockchain. struct TWAnySigner; -/// Signs a transaction. +/// Signs a transaction specified by the signing input and coin type. +/// +/// \param input The serialized data of a signing input (e.g. TW.Bitcoin.Proto.SigningInput). +/// \param coin The given coin type to sign the transaction for. +/// \return The serialized data of a `SigningOutput` proto object. (e.g. TW.Bitcoin.Proto.SigningOutput). extern TWData *_Nonnull TWAnySignerSign(TWData *_Nonnull input, enum TWCoinType coin); -/// Signs a json transaction with private key. +/// Signs a transaction specified by the JSON representation of signing input, coin type and a private key, returning the JSON representation of the signing output. +/// +/// \param json JSON representation of a signing input +/// \param key The private key to sign with. +/// \param coin The given coin type to sign the transaction for. +/// \return The JSON representation of a `SigningOutput` proto object. extern TWString *_Nonnull TWAnySignerSignJSON(TWString *_Nonnull json, TWData *_Nonnull key, enum TWCoinType coin); +/// Check if AnySigner supports signing JSON representation of signing input. +/// +/// \param coin The given coin type to sign the transaction for. +/// \return true if AnySigner supports signing JSON representation of signing input for a given coin. extern bool TWAnySignerSupportsJSON(enum TWCoinType coin); -/// Plan a transaction (for UTXO chains). +/// Plans a transaction (for UTXO chains only). +/// +/// \param input The serialized data of a signing input +/// \param coin The given coin type to plan the transaction for. +/// \return The serialized data of a `TransactionPlan` proto object. extern TWData *_Nonnull TWAnySignerPlan(TWData *_Nonnull input, enum TWCoinType coin); TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWBase32.h b/include/TrustWalletCore/TWBase32.h index b69500e1a62..871bbf8b561 100644 --- a/include/TrustWalletCore/TWBase32.h +++ b/include/TrustWalletCore/TWBase32.h @@ -12,6 +12,7 @@ TW_EXTERN_C_BEGIN +/// Base32 encode / decode functions TW_EXPORT_STRUCT struct TWBase32; diff --git a/include/TrustWalletCore/TWBase58.h b/include/TrustWalletCore/TWBase58.h index a37e14e06d3..6e5dbd30a48 100644 --- a/include/TrustWalletCore/TWBase58.h +++ b/include/TrustWalletCore/TWBase58.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,22 +12,35 @@ TW_EXTERN_C_BEGIN +/// Base58 encode / decode functions TW_EXPORT_STRUCT struct TWBase58; /// Encodes data as a Base58 string, including the checksum. +/// +/// \param data The data to encode. +/// \return the encoded Base58 string with checksum. TW_EXPORT_STATIC_METHOD TWString *_Nonnull TWBase58Encode(TWData *_Nonnull data); /// Encodes data as a Base58 string, not including the checksum. +/// +/// \param data The data to encode. +/// \return then encoded Base58 string without checksum. TW_EXPORT_STATIC_METHOD TWString *_Nonnull TWBase58EncodeNoCheck(TWData *_Nonnull data); -/// Decodes a Base58 string checking the checksum. +/// Decodes a Base58 string, checking the checksum. Returns null if the string is not a valid Base58 string. +/// +/// \param string The Base58 string to decode. +/// \return the decoded data, empty if the string is not a valid Base58 string with checksum. TW_EXPORT_STATIC_METHOD TWData *_Nullable TWBase58Decode(TWString *_Nonnull string); -/// Decodes a Base58 string with no checksum. +/// Decodes a Base58 string, w/o checking the checksum. Returns null if the string is not a valid Base58 string. +/// +/// \param string The Base58 string to decode. +/// \return the decoded data, empty if the string is not a valid Base58 string without checksum. TW_EXPORT_STATIC_METHOD TWData *_Nullable TWBase58DecodeNoCheck(TWString *_Nonnull string); diff --git a/include/TrustWalletCore/TWBase64.h b/include/TrustWalletCore/TWBase64.h index 5dbaa20fcf7..fa1c29173d1 100644 --- a/include/TrustWalletCore/TWBase64.h +++ b/include/TrustWalletCore/TWBase64.h @@ -12,21 +12,21 @@ TW_EXTERN_C_BEGIN +/// Base64 encode / decode functions TW_EXPORT_STRUCT struct TWBase64; - /// Decode a Base64 input with the default alphabet (RFC4648 with '+', '/') /// /// \param string Encoded input to be decoded -/// \return The decoded data +/// \return The decoded data, empty if decoding failed. TW_EXPORT_STATIC_METHOD TWData* _Nullable TWBase64Decode(TWString* _Nonnull string); /// Decode a Base64 input with the alphabet safe for URL-s and filenames (RFC4648 with '-', '_') /// /// \param string Encoded base64 input to be decoded -/// \return The decoded data +/// \return The decoded data, empty if decoding failed. TW_EXPORT_STATIC_METHOD TWData* _Nullable TWBase64DecodeUrl(TWString* _Nonnull string); diff --git a/include/TrustWalletCore/TWBitcoinAddress.h b/include/TrustWalletCore/TWBitcoinAddress.h index b42bdba717f..77ae6bf1d5d 100644 --- a/include/TrustWalletCore/TWBitcoinAddress.h +++ b/include/TrustWalletCore/TWBitcoinAddress.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -14,46 +14,75 @@ TW_EXTERN_C_BEGIN struct TWPublicKey; -/// Represents a legacy Bitcoin address. +/// Represents a legacy Bitcoin address in C++. TW_EXPORT_CLASS struct TWBitcoinAddress; /// Compares two addresses for equality. +/// +/// \param lhs The first address to compare. +/// \param rhs The second address to compare. +/// \return bool indicating the addresses are equal. TW_EXPORT_STATIC_METHOD bool TWBitcoinAddressEqual(struct TWBitcoinAddress *_Nonnull lhs, struct TWBitcoinAddress *_Nonnull rhs); /// Determines if the data is a valid Bitcoin address. +/// +/// \param data data to validate. +/// \return bool indicating if the address data is valid. TW_EXPORT_STATIC_METHOD bool TWBitcoinAddressIsValid(TWData *_Nonnull data); /// Determines if the string is a valid Bitcoin address. +/// +/// \param string string to validate. +/// \return bool indicating if the address string is valid. TW_EXPORT_STATIC_METHOD bool TWBitcoinAddressIsValidString(TWString *_Nonnull string); -/// Initializes an address from a base58 sring representaion. +/// Initializes an address from a Base58 sring. Must be deleted with TWBitcoinAddressDelete after use. +/// +/// \param string Base58 string to initialize the address from. +/// \return TWBitcoinAddress pointer or nullptr if string is invalid. TW_EXPORT_STATIC_METHOD struct TWBitcoinAddress *_Nullable TWBitcoinAddressCreateWithString(TWString *_Nonnull string); /// Initializes an address from raw data. +/// +/// \param data Raw data to initialize the address from. Must be deleted with TWBitcoinAddressDelete after use. +/// \return TWBitcoinAddress pointer or nullptr if data is invalid. TW_EXPORT_STATIC_METHOD struct TWBitcoinAddress *_Nullable TWBitcoinAddressCreateWithData(TWData *_Nonnull data); /// Initializes an address from a public key and a prefix byte. +/// +/// \param publicKey Public key to initialize the address from. +/// \param prefix Prefix byte (p2pkh, p2sh, etc). +/// \return TWBitcoinAddress pointer or nullptr if public key is invalid. TW_EXPORT_STATIC_METHOD struct TWBitcoinAddress *_Nullable TWBitcoinAddressCreateWithPublicKey(struct TWPublicKey *_Nonnull publicKey, uint8_t prefix); +/// Deletes a legacy Bitcoin address. +/// +/// \param address Address to delete. TW_EXPORT_METHOD void TWBitcoinAddressDelete(struct TWBitcoinAddress *_Nonnull address); -/// Returns the address base58 string representation. +/// Returns the address in Base58 string representation. +/// +/// \param address Address to get the string representation of. TW_EXPORT_PROPERTY TWString *_Nonnull TWBitcoinAddressDescription(struct TWBitcoinAddress *_Nonnull address); /// Returns the address prefix. +/// +/// \param address Address to get the prefix of. TW_EXPORT_PROPERTY uint8_t TWBitcoinAddressPrefix(struct TWBitcoinAddress *_Nonnull address); -/// Returns the keyhash data. +/// Returns the key hash data. +/// +/// \param address Address to get the keyhash data of. TW_EXPORT_PROPERTY TWData *_Nonnull TWBitcoinAddressKeyhash(struct TWBitcoinAddress *_Nonnull address); diff --git a/include/TrustWalletCore/TWBitcoinScript.h b/include/TrustWalletCore/TWBitcoinScript.h index 701d6ad4243..c04611ab166 100644 --- a/include/TrustWalletCore/TWBitcoinScript.h +++ b/include/TrustWalletCore/TWBitcoinScript.h @@ -7,119 +7,205 @@ #pragma once #include "TWBase.h" +#include "TWBitcoinSigHashType.h" +#include "TWCoinType.h" #include "TWData.h" #include "TWPublicKey.h" -#include "TWCoinType.h" -#include "TWBitcoinSigHashType.h" TW_EXTERN_C_BEGIN +/// Bitcoin script manipulating functions TW_EXPORT_CLASS struct TWBitcoinScript; /// Creates an empty script. +/// +/// \return A pointer to the script TW_EXPORT_STATIC_METHOD -struct TWBitcoinScript *_Nonnull TWBitcoinScriptCreate(); +struct TWBitcoinScript* _Nonnull TWBitcoinScriptCreate(); /// Creates a script from a raw data representation. +/// +/// \param data The data buffer +/// \note Must be deleted with \TWBitcoinScriptDelete +/// \return A pointer to the script TW_EXPORT_STATIC_METHOD -struct TWBitcoinScript *_Nonnull TWBitcoinScriptCreateWithData(TWData *_Nonnull data); -struct TWBitcoinScript *_Nonnull TWBitcoinScriptCreateWithBytes(uint8_t *_Nonnull bytes, size_t size); +struct TWBitcoinScript* _Nonnull TWBitcoinScriptCreateWithData(TWData* _Nonnull data); -/// Creates a script by copying an existring script. +/// Creates a script from a raw bytes and size. +/// +/// \param bytes The buffer +/// \param size The size of the buffer +/// \note Must be deleted with \TWBitcoinScriptDelete +/// \return A pointer to the script +struct TWBitcoinScript* _Nonnull TWBitcoinScriptCreateWithBytes(uint8_t* _Nonnull bytes, size_t size); + +/// Creates a script by copying an existing script. +/// +/// \param script Non-null pointer to a script +/// \note Must be deleted with \TWBitcoinScriptDelete +/// \return A pointer to the script TW_EXPORT_STATIC_METHOD -struct TWBitcoinScript *_Nonnull TWBitcoinScriptCreateCopy(const struct TWBitcoinScript *_Nonnull script); +struct TWBitcoinScript* _Nonnull TWBitcoinScriptCreateCopy(const struct TWBitcoinScript* _Nonnull script); +/// Delete/Deallocate a given script. +/// +/// \param script Non-null pointer to a script TW_EXPORT_METHOD -void TWBitcoinScriptDelete(struct TWBitcoinScript *_Nonnull script); +void TWBitcoinScriptDelete(struct TWBitcoinScript* _Nonnull script); +/// Get size of a script +/// +/// \param script Non-null pointer to a script +/// \return size of the script TW_EXPORT_PROPERTY -size_t TWBitcoinScriptSize(const struct TWBitcoinScript *_Nonnull script); +size_t TWBitcoinScriptSize(const struct TWBitcoinScript* _Nonnull script); +/// Get data of a script +/// +/// \param script Non-null pointer to a script +/// \return data of the given script TW_EXPORT_PROPERTY -TWData *_Nonnull TWBitcoinScriptData(const struct TWBitcoinScript *_Nonnull script); +TWData* _Nonnull TWBitcoinScriptData(const struct TWBitcoinScript* _Nonnull script); +/// Return script hash of a script +/// +/// \param script Non-null pointer to a script +/// \return script hash of the given script TW_EXPORT_PROPERTY -TWData *_Nonnull TWBitcoinScriptScriptHash(const struct TWBitcoinScript *_Nonnull script); +TWData* _Nonnull TWBitcoinScriptScriptHash(const struct TWBitcoinScript* _Nonnull script); /// Determines whether this is a pay-to-script-hash (P2SH) script. +/// +/// \param script Non-null pointer to a script +/// \return true if this is a pay-to-script-hash (P2SH) script, false otherwise TW_EXPORT_PROPERTY -bool TWBitcoinScriptIsPayToScriptHash(const struct TWBitcoinScript *_Nonnull script); +bool TWBitcoinScriptIsPayToScriptHash(const struct TWBitcoinScript* _Nonnull script); /// Determines whether this is a pay-to-witness-script-hash (P2WSH) script. +/// +/// \param script Non-null pointer to a script +/// \return true if this is a pay-to-witness-script-hash (P2WSH) script, false otherwise TW_EXPORT_PROPERTY -bool TWBitcoinScriptIsPayToWitnessScriptHash(const struct TWBitcoinScript *_Nonnull script); +bool TWBitcoinScriptIsPayToWitnessScriptHash(const struct TWBitcoinScript* _Nonnull script); /// Determines whether this is a pay-to-witness-public-key-hash (P2WPKH) script. +/// +/// \param script Non-null pointer to a script +/// \return true if this is a pay-to-witness-public-key-hash (P2WPKH) script, false otherwise TW_EXPORT_PROPERTY -bool TWBitcoinScriptIsPayToWitnessPublicKeyHash(const struct TWBitcoinScript *_Nonnull script); +bool TWBitcoinScriptIsPayToWitnessPublicKeyHash(const struct TWBitcoinScript* _Nonnull script); -/// Determines whether this is a witness programm script. +/// Determines whether this is a witness program script. +/// +/// \param script Non-null pointer to a script +/// \return true if this is a witness program script, false otherwise TW_EXPORT_PROPERTY -bool TWBitcoinScriptIsWitnessProgram(const struct TWBitcoinScript *_Nonnull script); +bool TWBitcoinScriptIsWitnessProgram(const struct TWBitcoinScript* _Nonnull script); +/// Determines whether 2 scripts have the same content +/// +/// \param lhs Non-null pointer to the first script +/// \param rhs Non-null pointer to the second script +/// \return true if both script have the same content TW_EXPORT_STATIC_METHOD -bool TWBitcoinScriptEqual(const struct TWBitcoinScript *_Nonnull lhs, const struct TWBitcoinScript *_Nonnull rhs); +bool TWBitcoinScriptEqual(const struct TWBitcoinScript* _Nonnull lhs, const struct TWBitcoinScript* _Nonnull rhs); /// Matches the script to a pay-to-public-key (P2PK) script. /// -/// - Returns: the public key. +/// \param script Non-null pointer to a script +/// \return The public key. TW_EXPORT_METHOD -TWData *_Nullable TWBitcoinScriptMatchPayToPubkey(const struct TWBitcoinScript *_Nonnull script); +TWData* _Nullable TWBitcoinScriptMatchPayToPubkey(const struct TWBitcoinScript* _Nonnull script); /// Matches the script to a pay-to-public-key-hash (P2PKH). /// -/// - Returns: the key hash. +/// \param script Non-null pointer to a script +/// \return the key hash. TW_EXPORT_METHOD -TWData *_Nullable TWBitcoinScriptMatchPayToPubkeyHash(const struct TWBitcoinScript *_Nonnull script); +TWData* _Nullable TWBitcoinScriptMatchPayToPubkeyHash(const struct TWBitcoinScript* _Nonnull script); /// Matches the script to a pay-to-script-hash (P2SH). /// -/// - Returns: the script hash. +/// \param script Non-null pointer to a script +/// \return the script hash. TW_EXPORT_METHOD -TWData *_Nullable TWBitcoinScriptMatchPayToScriptHash(const struct TWBitcoinScript *_Nonnull script); +TWData* _Nullable TWBitcoinScriptMatchPayToScriptHash(const struct TWBitcoinScript* _Nonnull script); /// Matches the script to a pay-to-witness-public-key-hash (P2WPKH). /// -/// - Returns: the key hash. +/// \param script Non-null pointer to a script +/// \return the key hash. TW_EXPORT_METHOD -TWData *_Nullable TWBitcoinScriptMatchPayToWitnessPublicKeyHash(const struct TWBitcoinScript *_Nonnull script); +TWData* _Nullable TWBitcoinScriptMatchPayToWitnessPublicKeyHash(const struct TWBitcoinScript* _Nonnull script); /// Matches the script to a pay-to-witness-script-hash (P2WSH). /// -/// - Returns: the script hash, a SHA256 of the witness script. +/// \param script Non-null pointer to a script +/// \return the script hash, a SHA256 of the witness script.. TW_EXPORT_METHOD -TWData *_Nullable TWBitcoinScriptMatchPayToWitnessScriptHash(const struct TWBitcoinScript *_Nonnull script); +TWData* _Nullable TWBitcoinScriptMatchPayToWitnessScriptHash(const struct TWBitcoinScript* _Nonnull script); /// Encodes the script. +/// +/// \param script Non-null pointer to a script +/// \return The encoded script TW_EXPORT_METHOD -TWData *_Nonnull TWBitcoinScriptEncode(const struct TWBitcoinScript *_Nonnull script); +TWData* _Nonnull TWBitcoinScriptEncode(const struct TWBitcoinScript* _Nonnull script); /// Builds a standard 'pay to public key' script. +/// +/// \param pubkey Non-null pointer to a pubkey +/// \note Must be deleted with \TWBitcoinScriptDelete +/// \return A pointer to the built script TW_EXPORT_STATIC_METHOD -struct TWBitcoinScript *_Nonnull TWBitcoinScriptBuildPayToPublicKey(TWData *_Nonnull pubkey); +struct TWBitcoinScript* _Nonnull TWBitcoinScriptBuildPayToPublicKey(TWData* _Nonnull pubkey); /// Builds a standard 'pay to public key hash' script. +/// +/// \param hash Non-null pointer to a PublicKey hash +/// \note Must be deleted with \TWBitcoinScriptDelete +/// \return A pointer to the built script TW_EXPORT_STATIC_METHOD -struct TWBitcoinScript *_Nonnull TWBitcoinScriptBuildPayToPublicKeyHash(TWData *_Nonnull hash); +struct TWBitcoinScript* _Nonnull TWBitcoinScriptBuildPayToPublicKeyHash(TWData* _Nonnull hash); /// Builds a standard 'pay to script hash' script. +/// +/// \param scriptHash Non-null pointer to a script hash +/// \note Must be deleted with \TWBitcoinScriptDelete +/// \return A pointer to the built script TW_EXPORT_STATIC_METHOD -struct TWBitcoinScript *_Nonnull TWBitcoinScriptBuildPayToScriptHash(TWData *_Nonnull scriptHash); +struct TWBitcoinScript* _Nonnull TWBitcoinScriptBuildPayToScriptHash(TWData* _Nonnull scriptHash); -/// Builds a pay-to-witness-public-key-hash (P2WPKH) script. +/// Builds a pay-to-witness-public-key-hash (P2WPKH) script.. +/// +/// \param hash Non-null pointer to a witness public key hash +/// \note Must be deleted with \TWBitcoinScriptDelete +/// \return A pointer to the built script TW_EXPORT_STATIC_METHOD -struct TWBitcoinScript *_Nonnull TWBitcoinScriptBuildPayToWitnessPubkeyHash(TWData *_Nonnull hash); +struct TWBitcoinScript* _Nonnull TWBitcoinScriptBuildPayToWitnessPubkeyHash(TWData* _Nonnull hash); /// Builds a pay-to-witness-script-hash (P2WSH) script. +/// +/// \param scriptHash Non-null pointer to a script hash +/// \note Must be deleted with \TWBitcoinScriptDelete +/// \return A pointer to the built script TW_EXPORT_STATIC_METHOD -struct TWBitcoinScript *_Nonnull TWBitcoinScriptBuildPayToWitnessScriptHash(TWData *_Nonnull scriptHash); +struct TWBitcoinScript* _Nonnull TWBitcoinScriptBuildPayToWitnessScriptHash(TWData* _Nonnull scriptHash); -/// Builds a appropriate lock script for the given address. +/// Builds a appropriate lock script for the given address.. +/// +/// \param address Non-null pointer to an address +/// \param coin coin type +/// \note Must be deleted with \TWBitcoinScriptDelete +/// \return A pointer to the built script TW_EXPORT_STATIC_METHOD -struct TWBitcoinScript *_Nonnull TWBitcoinScriptLockScriptForAddress(TWString *_Nonnull address, enum TWCoinType coin); +struct TWBitcoinScript* _Nonnull TWBitcoinScriptLockScriptForAddress(TWString* _Nonnull address, enum TWCoinType coin); -// Return the default HashType for the given coin, such as TWBitcoinSigHashTypeAll. +/// Return the default HashType for the given coin, such as TWBitcoinSigHashTypeAll. +/// +/// \param coinType coin type +/// \return default HashType for the given coin TW_EXPORT_STATIC_METHOD uint32_t TWBitcoinScriptHashTypeForCoin(enum TWCoinType coinType); diff --git a/include/TrustWalletCore/TWBitcoinSigHashType.h b/include/TrustWalletCore/TWBitcoinSigHashType.h index 33fba1992d2..b2682d67074 100644 --- a/include/TrustWalletCore/TWBitcoinSigHashType.h +++ b/include/TrustWalletCore/TWBitcoinSigHashType.h @@ -10,6 +10,7 @@ TW_EXTERN_C_BEGIN +/// Bitcoin SIGHASH type. TW_EXPORT_ENUM(uint32_t) enum TWBitcoinSigHashType { TWBitcoinSigHashTypeAll = 0x01, @@ -20,9 +21,17 @@ enum TWBitcoinSigHashType { TWBitcoinSigHashTypeAnyoneCanPay = 0x80 }; +/// Determines if the given sig hash is single +/// +/// \param type sig hash type +/// \return true if the sigh hash type is single, false otherwise TW_EXPORT_METHOD bool TWBitcoinSigHashTypeIsSingle(enum TWBitcoinSigHashType type); +/// Determines if the given sig hash is none +/// +/// \param type sig hash type +/// \return true if the sigh hash type is none, false otherwise TW_EXPORT_METHOD bool TWBitcoinSigHashTypeIsNone(enum TWBitcoinSigHashType type); diff --git a/include/TrustWalletCore/TWBlockchain.h b/include/TrustWalletCore/TWBlockchain.h index 12c6e8f3201..9fdc83f7727 100644 --- a/include/TrustWalletCore/TWBlockchain.h +++ b/include/TrustWalletCore/TWBlockchain.h @@ -10,6 +10,7 @@ TW_EXTERN_C_BEGIN +/// Blockchain enum type TW_EXPORT_ENUM(uint32_t) enum TWBlockchain { TWBlockchainBitcoin = 0, diff --git a/include/TrustWalletCore/TWCardano.h b/include/TrustWalletCore/TWCardano.h index 601d2edf2f9..74d9c7a4e43 100644 --- a/include/TrustWalletCore/TWCardano.h +++ b/include/TrustWalletCore/TWCardano.h @@ -11,11 +11,15 @@ TW_EXTERN_C_BEGIN +/// Cardano helper functions TW_EXPORT_STRUCT struct TWCardano; -// The minimum ADA amount needed for a UTXO. See https://docs.cardano.org/native-tokens/minimum-ada-value-requirement -// Input is serialized TokenBundle protobuf object. +/// Calculates the minimum ADA amount needed for a UTXO. +/// +/// \see reference https://docs.cardano.org/native-tokens/minimum-ada-value-requirement +/// \param tokenBundle serialized data of TW.Cardano.Proto.TokenBundle. +/// \return the minimum ADA amount. TW_EXPORT_STATIC_METHOD uint64_t TWCardanoMinAdaAmount(TWData *_Nonnull tokenBundle) TW_VISIBILITY_DEFAULT; diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index e23bb380685..4d473c64dc1 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -20,7 +20,7 @@ TW_EXTERN_C_BEGIN /// Coin type for Level 2 of BIP44. /// -/// - SeeAlso: https://github.com/satoshilabs/slips/blob/master/slip-0044.md +/// \see https://github.com/satoshilabs/slips/blob/master/slip-0044.md TW_EXPORT_ENUM(uint32_t) enum TWCoinType { TWCoinTypeAeternity = 457, @@ -118,72 +118,128 @@ enum TWCoinType { }; /// Returns the blockchain for a coin type. +/// +/// \param coin A coin type +/// \return blockchain associated to the given coin type TW_EXPORT_PROPERTY enum TWBlockchain TWCoinTypeBlockchain(enum TWCoinType coin); /// Returns the purpose for a coin type. +/// +/// \param coin A coin type +/// \return purpose associated to the given coin type TW_EXPORT_PROPERTY enum TWPurpose TWCoinTypePurpose(enum TWCoinType coin); /// Returns the curve that should be used for a coin type. +/// +/// \param coin A coin type +/// \return curve that should be used for the given coin type TW_EXPORT_PROPERTY enum TWCurve TWCoinTypeCurve(enum TWCoinType coin); /// Returns the xpub HD version that should be used for a coin type. +/// +/// \param coin A coin type +/// \return xpub HD version that should be used for the given coin type TW_EXPORT_PROPERTY enum TWHDVersion TWCoinTypeXpubVersion(enum TWCoinType coin); /// Returns the xprv HD version that should be used for a coin type. +/// +/// \param coin A coin type +/// \return the xprv HD version that should be used for the given coin type. TW_EXPORT_PROPERTY enum TWHDVersion TWCoinTypeXprvVersion(enum TWCoinType coin); /// Validates an address string. +/// +/// \param coin A coin type +/// \param address A public address +/// \return true if the address is a valid public address of the given coin, false otherwise. TW_EXPORT_METHOD bool TWCoinTypeValidate(enum TWCoinType coin, TWString* _Nonnull address); /// Returns the default derivation path for a particular coin. +/// +/// \param coin A coin type +/// \return the default derivation path for the given coin type. TW_EXPORT_METHOD TWString* _Nonnull TWCoinTypeDerivationPath(enum TWCoinType coin); /// Returns the derivation path for a particular coin with the explicit given derivation. +/// +/// \param coin A coin type +/// \param derivation A derivation type +/// \return the derivation path for the given coin with the explicit given derivation TW_EXPORT_METHOD TWString* _Nonnull TWCoinTypeDerivationPathWithDerivation(enum TWCoinType coin, enum TWDerivation derivation); /// Derives the address for a particular coin from the private key. +/// +/// \param coin A coin type +/// \param privateKey A valid private key +/// \return Derived address for the given coin from the private key. TW_EXPORT_METHOD TWString* _Nonnull TWCoinTypeDeriveAddress(enum TWCoinType coin, struct TWPrivateKey* _Nonnull privateKey); /// Derives the address for a particular coin from the public key. +/// +/// \param coin A coin type +/// \param publicKey A valid public key +/// \return Derived address for the given coin from the public key. TW_EXPORT_METHOD TWString* _Nonnull TWCoinTypeDeriveAddressFromPublicKey(enum TWCoinType coin, struct TWPublicKey* _Nonnull publicKey); /// HRP for this coin type +/// +/// \param coin A coin type +/// \return HRP of the given coin type. TW_EXPORT_PROPERTY enum TWHRP TWCoinTypeHRP(enum TWCoinType coin); /// P2PKH prefix for this coin type +/// +/// \param coin A coin type +/// \return P2PKH prefix for the given coin type TW_EXPORT_PROPERTY uint8_t TWCoinTypeP2pkhPrefix(enum TWCoinType coin); /// P2SH prefix for this coin type +/// +/// \param coin A coin type +/// \return P2SH prefix for the given coin type TW_EXPORT_PROPERTY uint8_t TWCoinTypeP2shPrefix(enum TWCoinType coin); /// Static prefix for this coin type +/// +/// \param coin A coin type +/// \return Static prefix for the given coin type TW_EXPORT_PROPERTY uint8_t TWCoinTypeStaticPrefix(enum TWCoinType coin); -/// ChainID for this coin type. Caller must free return object. +/// ChainID for this coin type. +/// +/// \param coin A coin type +/// \return ChainID for the given coin type. +/// \note Caller must free returned object. TW_EXPORT_PROPERTY TWString* _Nonnull TWCoinTypeChainId(enum TWCoinType coin); /// SLIP-0044 id for this coin type +/// +/// \param coin A coin type +/// \return SLIP-0044 id for the given coin type TW_EXPORT_PROPERTY uint32_t TWCoinTypeSlip44Id(enum TWCoinType coin); /// public key type for this coin type +/// +/// \param coin A coin type +/// \return public key type for the given coin type TW_EXPORT_PROPERTY enum TWPublicKeyType TWCoinTypePublicKeyType(enum TWCoinType coin); diff --git a/include/TrustWalletCore/TWCoinTypeConfiguration.h b/include/TrustWalletCore/TWCoinTypeConfiguration.h index 47458179ac5..1a04fab57d8 100644 --- a/include/TrustWalletCore/TWCoinTypeConfiguration.h +++ b/include/TrustWalletCore/TWCoinTypeConfiguration.h @@ -12,32 +12,54 @@ TW_EXTERN_C_BEGIN +/// CoinTypeConfiguration functions TW_EXPORT_STRUCT struct TWCoinTypeConfiguration { uint8_t unused; // C doesn't allow zero-sized struct }; /// Returns stock symbol of coin +/// +/// \param type A coin type +/// \return A non-null TWString stock symbol of coin +/// \note Caller must free returned object TW_EXPORT_STATIC_METHOD TWString *_Nonnull TWCoinTypeConfigurationGetSymbol(enum TWCoinType type); /// Returns max count decimal places for minimal coin unit +/// +/// \param type A coin type +/// \return Returns max count decimal places for minimal coin unit TW_EXPORT_STATIC_METHOD int TWCoinTypeConfigurationGetDecimals(enum TWCoinType type); /// Returns transaction url in blockchain explorer +/// +/// \param type A coin type +/// \param transactionID A transaction identifier +/// \return Returns a non-null TWString transaction url in blockchain explorer TW_EXPORT_STATIC_METHOD TWString *_Nonnull TWCoinTypeConfigurationGetTransactionURL(enum TWCoinType type, TWString *_Nonnull transactionID); /// Returns account url in blockchain explorer +/// +/// \param type A coin type +/// \param accountID an Account identifier +/// \return Returns a non-null TWString account url in blockchain explorer TW_EXPORT_STATIC_METHOD TWString *_Nonnull TWCoinTypeConfigurationGetAccountURL(enum TWCoinType type, TWString *_Nonnull accountID); /// Returns full name of coin in lower case +/// +/// \param type A coin type +/// \return Returns a non-null TWString, full name of coin in lower case TW_EXPORT_STATIC_METHOD TWString *_Nonnull TWCoinTypeConfigurationGetID(enum TWCoinType type); /// Returns full name of coin +/// +/// \param type A coin type +/// \return Returns a non-null TWString, full name of coin TW_EXPORT_STATIC_METHOD TWString *_Nonnull TWCoinTypeConfigurationGetName(enum TWCoinType type); diff --git a/include/TrustWalletCore/TWData.h b/include/TrustWalletCore/TWData.h index 3a4334c8f05..2eebf174c39 100644 --- a/include/TrustWalletCore/TWData.h +++ b/include/TrustWalletCore/TWData.h @@ -19,54 +19,111 @@ typedef const void TWString; typedef const void TWData; /// Creates a block of data from a byte array. +/// +/// \param bytes Non-null raw bytes buffer +/// \param size size of the buffer +/// \return Non-null filled block of data. TWData *_Nonnull TWDataCreateWithBytes(const uint8_t *_Nonnull bytes, size_t size) TW_VISIBILITY_DEFAULT; /// Creates an uninitialized block of data with the provided size. +/// +/// \param size size for the block of data +/// \return Non-null uninitialized block of data with the provided size TWData *_Nonnull TWDataCreateWithSize(size_t size) TW_VISIBILITY_DEFAULT; /// Creates a block of data by copying another block of data. +/// +/// \param data buffer that need to be copied +/// \return Non-null filled block of data. TWData *_Nonnull TWDataCreateWithData(TWData *_Nonnull data) TW_VISIBILITY_DEFAULT; /// Creates a block of data from a hexadecimal string. Odd length is invalid (intended grouping to bytes is not obvious). +/// +/// \param hex input hex string +/// \return Non-null filled block of data TWData *_Nullable TWDataCreateWithHexString(const TWString *_Nonnull hex) TW_VISIBILITY_DEFAULT; /// Returns the size in bytes. +/// +/// \param data A non-null valid block of data +/// \return the size of the given block of data size_t TWDataSize(TWData *_Nonnull data) TW_VISIBILITY_DEFAULT; /// Returns the raw pointer to the contents of data. +/// +/// \param data A non-null valid block of data +/// \return the raw pointer to the contents of data uint8_t *_Nonnull TWDataBytes(TWData *_Nonnull data) TW_VISIBILITY_DEFAULT; /// Returns the byte at the provided index. +/// +/// \param data A non-null valid block of data +/// \param index index of the byte that we want to fetch - index need to be < TWDataSize(data) +/// \return the byte at the provided index uint8_t TWDataGet(TWData *_Nonnull data, size_t index) TW_VISIBILITY_DEFAULT; /// Sets the byte at the provided index. +/// +/// \param data A non-null valid block of data +/// \param index index of the byte that we want to set - index need to be < TWDataSize(data) +/// \param byte Given byte to be written in data void TWDataSet(TWData *_Nonnull data, size_t index, uint8_t byte) TW_VISIBILITY_DEFAULT; /// Copies a range of bytes into the provided buffer. +/// +/// \param data A non-null valid block of data +/// \param start starting index of the range - index need to be < TWDataSize(data) +/// \param size size of the range we want to copy - size need to be < TWDataSize(data) - start +/// \param output The output buffer where we want to copy the data. void TWDataCopyBytes(TWData *_Nonnull data, size_t start, size_t size, uint8_t *_Nonnull output) TW_VISIBILITY_DEFAULT; /// Replaces a range of bytes with the contents of the provided buffer. +/// +/// \param data A non-null valid block of data +/// \param start starting index of the range - index need to be < TWDataSize(data) +/// \param size size of the range we want to replace - size need to be < TWDataSize(data) - start +/// \param bytes The buffer that will replace the range of data void TWDataReplaceBytes(TWData *_Nonnull data, size_t start, size_t size, const uint8_t *_Nonnull bytes) TW_VISIBILITY_DEFAULT; /// Appends data from a byte array. +/// +/// \param data A non-null valid block of data +/// \param bytes Non-null byte array +/// \param size The size of the byte array void TWDataAppendBytes(TWData *_Nonnull data, const uint8_t *_Nonnull bytes, size_t size) TW_VISIBILITY_DEFAULT; /// Appends a single byte. +/// +/// \param data A non-null valid block of data +/// \param byte A single byte void TWDataAppendByte(TWData *_Nonnull data, uint8_t byte) TW_VISIBILITY_DEFAULT; /// Appends a block of data. +/// +/// \param data A non-null valid block of data +/// \param append A non-null valid block of data void TWDataAppendData(TWData *_Nonnull data, TWData *_Nonnull append) TW_VISIBILITY_DEFAULT; -/// Revereses the bytes. +/// Reverse the bytes. +/// +/// \param data A non-null valid block of data void TWDataReverse(TWData *_Nonnull data) TW_VISIBILITY_DEFAULT; /// Sets all bytes to the given value. +/// +/// \param data A non-null valid block of data void TWDataReset(TWData *_Nonnull data) TW_VISIBILITY_DEFAULT; /// Deletes a block of data created with a `TWDataCreate*` method. +/// +/// \param data A non-null valid block of data void TWDataDelete(TWData *_Nonnull data) TW_VISIBILITY_DEFAULT; /// Determines whether two data blocks are equal. +/// +/// \param lhs left non null block of data to be compared +/// \param rhs right non null block of data to be compared +/// \return true if both block of data are equal, false otherwise bool TWDataEqual(TWData *_Nonnull lhs, TWData *_Nonnull rhs) TW_VISIBILITY_DEFAULT; TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWDataVector.h b/include/TrustWalletCore/TWDataVector.h index 7000268757b..7df60c8f1a1 100644 --- a/include/TrustWalletCore/TWDataVector.h +++ b/include/TrustWalletCore/TWDataVector.h @@ -15,26 +15,47 @@ TW_EXTERN_C_BEGIN TW_EXPORT_CLASS struct TWDataVector; +/// Creates a Vector of Data. +/// +/// \note Must be deleted with \TWDataVectorDelete +/// \return a non-null Vector of Data. TW_EXPORT_STATIC_METHOD struct TWDataVector *_Nonnull TWDataVectorCreate(); -// Create with one element +/// Creates a Vector of Data with the given element +/// +/// \param data A non-null valid block of data +/// \return A Vector of data with a single given element TW_EXPORT_STATIC_METHOD struct TWDataVector *_Nonnull TWDataVectorCreateWithData(TWData *_Nonnull data); -// Delete must be called at the end +/// Delete/Deallocate a Vector of Data +/// +/// \param dataVector A non-null Vector of data TW_EXPORT_METHOD void TWDataVectorDelete(struct TWDataVector *_Nonnull dataVector); -// Add an element to the vector. Element is cloned (will be deleted with the vector, but input parameter must be deleted on its own) +/// Add an element to a Vector of Data. Element is cloned +/// +/// \param dataVector A non-null Vector of data +/// \param data A non-null valid block of data +/// \note data input parameter must be deleted on its own TW_EXPORT_METHOD void TWDataVectorAdd(struct TWDataVector *_Nonnull dataVector, TWData *_Nonnull data); -// Retrieve the number of elements +/// Retrieve the number of elements +/// +/// \param dataVector A non-null Vector of data +/// \return the size of the given vector. TW_EXPORT_PROPERTY size_t TWDataVectorSize(const struct TWDataVector *_Nonnull dataVector); -// Retrieve the n-th element. A clone is returned (must be freed). +/// Retrieve the n-th element. +/// +/// \param dataVector A non-null Vector of data +/// \param index index element of the vector to be retrieved, need to be < TWDataVectorSize +/// \note Returned element must be freed with \TWDataDelete +/// \return A non-null block of data TW_EXPORT_METHOD TWData *_Nullable TWDataVectorGet(const struct TWDataVector *_Nonnull dataVector, size_t index); diff --git a/include/TrustWalletCore/TWEthereumAbi.h b/include/TrustWalletCore/TWEthereumAbi.h index 0430ea07a3c..5baf7161942 100644 --- a/include/TrustWalletCore/TWEthereumAbi.h +++ b/include/TrustWalletCore/TWEthereumAbi.h @@ -10,24 +10,34 @@ #include "TWString.h" #include "TWData.h" -// Wrapper class for Ethereum ABI encoding & decoding. - TW_EXTERN_C_BEGIN +/// Wrapper class for Ethereum ABI encoding & decoding. struct TWEthereumAbiFunction; TW_EXPORT_STRUCT struct TWEthereumAbi; /// Encode function to Eth ABI binary +/// +/// \param fn Non-null Eth abi function +/// \return Non-null encoded block of data TW_EXPORT_STATIC_METHOD TWData* _Nonnull TWEthereumAbiEncode(struct TWEthereumAbiFunction* _Nonnull fn); /// Decode function output from Eth ABI binary, fill output parameters +/// +/// \param[in] fn Non-null Eth abi function +/// \param[out] encoded Non-null block of data +/// \return true if encoded have been filled correctly, false otherwise TW_EXPORT_STATIC_METHOD bool TWEthereumAbiDecodeOutput(struct TWEthereumAbiFunction* _Nonnull fn, TWData* _Nonnull encoded); /// Decode function call data to human readable json format, according to input abi json +/// +/// \param data Non-null block of data +/// \param abi Non-null string +/// \return Non-null json string function call data TW_EXPORT_STATIC_METHOD TWString* _Nullable TWEthereumAbiDecodeCall(TWData* _Nonnull data, TWString* _Nonnull abi); @@ -66,6 +76,9 @@ TWString* _Nullable TWEthereumAbiDecodeCall(TWData* _Nonnull data, TWString* _No /// })"); /// On error, empty Data is returned. /// Returned data must be deleted (hint: use WRAPD() macro). +/// +/// \param messageJson Non-null json abi input +/// \return Non-null block of data, encoded abi input TW_EXPORT_STATIC_METHOD TWData* _Nonnull TWEthereumAbiEncodeTyped(TWString* _Nonnull messageJson); diff --git a/include/TrustWalletCore/TWEthereumAbiFunction.h b/include/TrustWalletCore/TWEthereumAbiFunction.h index 81daa7b3e7e..4034ade5180 100644 --- a/include/TrustWalletCore/TWEthereumAbiFunction.h +++ b/include/TrustWalletCore/TWEthereumAbiFunction.h @@ -7,182 +7,450 @@ #pragma once #include "TWBase.h" -#include "TWString.h" #include "TWData.h" +#include "TWString.h" TW_EXTERN_C_BEGIN +/// Represents Ethereum ABI function TW_EXPORT_CLASS struct TWEthereumAbiFunction; /// Creates a function object, with the given name and empty parameter list. It must be deleted at the end. +/// +/// \param name function name +/// \return Non-null Ethereum abi function TW_EXPORT_STATIC_METHOD -struct TWEthereumAbiFunction *_Nonnull TWEthereumAbiFunctionCreateWithString(TWString *_Nonnull name); +struct TWEthereumAbiFunction* _Nonnull TWEthereumAbiFunctionCreateWithString(TWString* _Nonnull name); /// Deletes a function object created with a 'TWEthereumAbiFunctionCreateWithString' method. +/// +/// \param fn Non-null Ethereum abi function TW_EXPORT_METHOD -void TWEthereumAbiFunctionDelete(struct TWEthereumAbiFunction *_Nonnull fn); +void TWEthereumAbiFunctionDelete(struct TWEthereumAbiFunction* _Nonnull fn); /// Return the function type signature, of the form "baz(int32,uint256)" +/// +/// \param fn A Non-null eth abi function +/// \return function type signature as a Non-null string. TW_EXPORT_METHOD -TWString *_Nonnull TWEthereumAbiFunctionGetType(struct TWEthereumAbiFunction *_Nonnull fn); +TWString* _Nonnull TWEthereumAbiFunctionGetType(struct TWEthereumAbiFunction* _Nonnull fn); + +/// Methods for adding parameters of the given type (input or output). +/// For output parameters (isOutput=true) a value has to be specified, although usually not need; -/// Methods for adding parameters of the given type (input or output). -/// For output parameters (isOutput=true) a value has to be specified, although usually not needd. -/// Returns the index of the parameter (0-based). +/// Add a uint8 type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamUInt8(struct TWEthereumAbiFunction *_Nonnull fn, uint8_t val, bool isOutput); +int TWEthereumAbiFunctionAddParamUInt8(struct TWEthereumAbiFunction* _Nonnull fn, uint8_t val, bool isOutput); +/// Add a uint16 type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamUInt16(struct TWEthereumAbiFunction *_Nonnull fn, uint16_t val, bool isOutput); +int TWEthereumAbiFunctionAddParamUInt16(struct TWEthereumAbiFunction* _Nonnull fn, uint16_t val, bool isOutput); +/// Add a uint32 type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamUInt32(struct TWEthereumAbiFunction *_Nonnull fn, uint32_t val, bool isOutput); +int TWEthereumAbiFunctionAddParamUInt32(struct TWEthereumAbiFunction* _Nonnull fn, uint32_t val, bool isOutput); +/// Add a uint64 type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamUInt64(struct TWEthereumAbiFunction *_Nonnull fn, uint64_t val, bool isOutput); +int TWEthereumAbiFunctionAddParamUInt64(struct TWEthereumAbiFunction* _Nonnull fn, uint64_t val, bool isOutput); +/// Add a uint256 type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamUInt256(struct TWEthereumAbiFunction *_Nonnull fn, TWData *_Nonnull val, bool isOutput); +int TWEthereumAbiFunctionAddParamUInt256(struct TWEthereumAbiFunction* _Nonnull fn, TWData* _Nonnull val, bool isOutput); +/// Add a uint(bits) type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamUIntN(struct TWEthereumAbiFunction *_Nonnull fn, int bits, TWData *_Nonnull val, bool isOutput); +int TWEthereumAbiFunctionAddParamUIntN(struct TWEthereumAbiFunction* _Nonnull fn, int bits, TWData* _Nonnull val, bool isOutput); +/// Add a int8 type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamInt8(struct TWEthereumAbiFunction *_Nonnull fn, int8_t val, bool isOutput); +int TWEthereumAbiFunctionAddParamInt8(struct TWEthereumAbiFunction* _Nonnull fn, int8_t val, bool isOutput); +/// Add a int16 type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamInt16(struct TWEthereumAbiFunction *_Nonnull fn, int16_t val, bool isOutput); +int TWEthereumAbiFunctionAddParamInt16(struct TWEthereumAbiFunction* _Nonnull fn, int16_t val, bool isOutput); +/// Add a int32 type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamInt32(struct TWEthereumAbiFunction *_Nonnull fn, int32_t val, bool isOutput); +int TWEthereumAbiFunctionAddParamInt32(struct TWEthereumAbiFunction* _Nonnull fn, int32_t val, bool isOutput); +/// Add a int64 type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamInt64(struct TWEthereumAbiFunction *_Nonnull fn, int64_t val, bool isOutput); +int TWEthereumAbiFunctionAddParamInt64(struct TWEthereumAbiFunction* _Nonnull fn, int64_t val, bool isOutput); +/// Add a int256 type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified (stored in a block of data) +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamInt256(struct TWEthereumAbiFunction *_Nonnull fn, TWData *_Nonnull val, bool isOutput); +int TWEthereumAbiFunctionAddParamInt256(struct TWEthereumAbiFunction* _Nonnull fn, TWData* _Nonnull val, bool isOutput); +/// Add a int(bits) type parameter +/// +/// \param fn A Non-null eth abi function +/// \param bits Number of bits of the integer parameter +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamIntN(struct TWEthereumAbiFunction *_Nonnull fn, int bits, TWData *_Nonnull val, bool isOutput); +int TWEthereumAbiFunctionAddParamIntN(struct TWEthereumAbiFunction* _Nonnull fn, int bits, TWData* _Nonnull val, bool isOutput); + +/// Add a bool type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamBool(struct TWEthereumAbiFunction *_Nonnull fn, bool val, bool isOutput); +int TWEthereumAbiFunctionAddParamBool(struct TWEthereumAbiFunction* _Nonnull fn, bool val, bool isOutput); +/// Add a string type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamString(struct TWEthereumAbiFunction *_Nonnull fn, TWString *_Nonnull val, bool isOutput); +int TWEthereumAbiFunctionAddParamString(struct TWEthereumAbiFunction* _Nonnull fn, TWString* _Nonnull val, bool isOutput); +/// Add an address type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamAddress(struct TWEthereumAbiFunction *_Nonnull fn, TWData *_Nonnull val, bool isOutput); +int TWEthereumAbiFunctionAddParamAddress(struct TWEthereumAbiFunction* _Nonnull fn, TWData* _Nonnull val, bool isOutput); +/// Add a bytes type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamBytes(struct TWEthereumAbiFunction *_Nonnull fn, TWData *_Nonnull val, bool isOutput); +int TWEthereumAbiFunctionAddParamBytes(struct TWEthereumAbiFunction* _Nonnull fn, TWData* _Nonnull val, bool isOutput); +/// Add a bytes[N] type parameter +/// +/// \param fn A Non-null eth abi function +/// \param size fixed size of the bytes array parameter (val). +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamBytesFix(struct TWEthereumAbiFunction *_Nonnull fn, size_t size, TWData *_Nonnull val, bool isOutput); +int TWEthereumAbiFunctionAddParamBytesFix(struct TWEthereumAbiFunction* _Nonnull fn, size_t size, TWData* _Nonnull val, bool isOutput); +/// Add a type[] type parameter +/// +/// \param fn A Non-null eth abi function +/// \param val for output parameters, value has to be specified +/// \param isOutput determines if the parameter is an input or output +/// \return the index of the parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddParamArray(struct TWEthereumAbiFunction *_Nonnull fn, bool isOutput); +int TWEthereumAbiFunctionAddParamArray(struct TWEthereumAbiFunction* _Nonnull fn, bool isOutput); /// Methods for accessing the value of an output or input parameter, of different types. + +/// Get a uint8 type parameter at the given index +/// +/// \param fn A Non-null eth abi function +/// \param idx index for the parameter (0-based). +/// \param isOutput determines if the parameter is an input or output +/// \return the value of the parameter. TW_EXPORT_METHOD -uint8_t TWEthereumAbiFunctionGetParamUInt8(struct TWEthereumAbiFunction *_Nonnull fn, int idx, bool isOutput); +uint8_t TWEthereumAbiFunctionGetParamUInt8(struct TWEthereumAbiFunction* _Nonnull fn, int idx, bool isOutput); + +/// Get a uint64 type parameter at the given index +/// +/// \param fn A Non-null eth abi function +/// \param idx index for the parameter (0-based). +/// \param isOutput determines if the parameter is an input or output +/// \return the value of the parameter. TW_EXPORT_METHOD -uint64_t TWEthereumAbiFunctionGetParamUInt64(struct TWEthereumAbiFunction *_Nonnull fn, int idx, bool isOutput); +uint64_t TWEthereumAbiFunctionGetParamUInt64(struct TWEthereumAbiFunction* _Nonnull fn, int idx, bool isOutput); + +/// Get a uint256 type parameter at the given index +/// +/// \param fn A Non-null eth abi function +/// \param idx index for the parameter (0-based). +/// \param isOutput determines if the parameter is an input or output +/// \return the value of the parameter stored in a block of data. TW_EXPORT_METHOD -TWData *_Nonnull TWEthereumAbiFunctionGetParamUInt256(struct TWEthereumAbiFunction *_Nonnull fn, int idx, bool isOutput); +TWData* _Nonnull TWEthereumAbiFunctionGetParamUInt256(struct TWEthereumAbiFunction* _Nonnull fn, int idx, bool isOutput); + +/// Get a bool type parameter at the given index +/// +/// \param fn A Non-null eth abi function +/// \param idx index for the parameter (0-based). +/// \param isOutput determines if the parameter is an input or output +/// \return the value of the parameter. TW_EXPORT_METHOD -bool TWEthereumAbiFunctionGetParamBool(struct TWEthereumAbiFunction *_Nonnull fn, int idx, bool isOutput); +bool TWEthereumAbiFunctionGetParamBool(struct TWEthereumAbiFunction* _Nonnull fn, int idx, bool isOutput); + +/// Get a string type parameter at the given index +/// +/// \param fn A Non-null eth abi function +/// \param idx index for the parameter (0-based). +/// \param isOutput determines if the parameter is an input or output +/// \return the value of the parameter. TW_EXPORT_METHOD -TWString *_Nonnull TWEthereumAbiFunctionGetParamString(struct TWEthereumAbiFunction *_Nonnull fn, int idx, bool isOutput); +TWString* _Nonnull TWEthereumAbiFunctionGetParamString(struct TWEthereumAbiFunction* _Nonnull fn, int idx, bool isOutput); + +/// Get an address type parameter at the given index +/// +/// \param fn A Non-null eth abi function +/// \param idx index for the parameter (0-based). +/// \param isOutput determines if the parameter is an input or output +/// \return the value of the parameter. TW_EXPORT_METHOD -TWData *_Nonnull TWEthereumAbiFunctionGetParamAddress(struct TWEthereumAbiFunction *_Nonnull fn, int idx, bool isOutput); +TWData* _Nonnull TWEthereumAbiFunctionGetParamAddress(struct TWEthereumAbiFunction* _Nonnull fn, int idx, bool isOutput); /// Methods for adding a parameter of the given type to a top-level input parameter array. Returns the index of the parameter (0-based). /// Note that nested ParamArrays are not possible through this API, could be done by using index paths like "1/0" + +/// Adding a uint8 type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamUInt8(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, uint8_t val); +int TWEthereumAbiFunctionAddInArrayParamUInt8(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, uint8_t val); +/// Adding a uint16 type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamUInt16(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, uint16_t val); +int TWEthereumAbiFunctionAddInArrayParamUInt16(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, uint16_t val); +/// Adding a uint32 type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamUInt32(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, uint32_t val); +int TWEthereumAbiFunctionAddInArrayParamUInt32(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, uint32_t val); +/// Adding a uint64 type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamUInt64(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, uint64_t val); +int TWEthereumAbiFunctionAddInArrayParamUInt64(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, uint64_t val); +/// Adding a uint256 type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter stored in a block of data +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamUInt256(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, TWData *_Nonnull val); +int TWEthereumAbiFunctionAddInArrayParamUInt256(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, TWData* _Nonnull val); +/// Adding a uint[N] type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param bits Number of bits of the integer parameter +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter stored in a block of data +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamUIntN(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, int bits, TWData *_Nonnull val); +int TWEthereumAbiFunctionAddInArrayParamUIntN(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, int bits, TWData* _Nonnull val); +/// Adding a int8 type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamInt8(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, int8_t val); +int TWEthereumAbiFunctionAddInArrayParamInt8(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, int8_t val); +/// Adding a int16 type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamInt16(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, int16_t val); +int TWEthereumAbiFunctionAddInArrayParamInt16(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, int16_t val); +/// Adding a int32 type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamInt32(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, int32_t val); +int TWEthereumAbiFunctionAddInArrayParamInt32(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, int32_t val); +/// Adding a int64 type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamInt64(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, int64_t val); +int TWEthereumAbiFunctionAddInArrayParamInt64(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, int64_t val); +/// Adding a int256 type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter stored in a block of data +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamInt256(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, TWData *_Nonnull val); +int TWEthereumAbiFunctionAddInArrayParamInt256(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, TWData* _Nonnull val); +/// Adding a int[N] type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param bits Number of bits of the integer parameter +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter stored in a block of data +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamIntN(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, int bits, TWData *_Nonnull val); +int TWEthereumAbiFunctionAddInArrayParamIntN(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, int bits, TWData* _Nonnull val); +/// Adding a bool type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamBool(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, bool val); +int TWEthereumAbiFunctionAddInArrayParamBool(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, bool val); +/// Adding a string type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamString(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, TWString *_Nonnull val); +int TWEthereumAbiFunctionAddInArrayParamString(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, TWString* _Nonnull val); +/// Adding an address type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamAddress(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, TWData *_Nonnull val); +int TWEthereumAbiFunctionAddInArrayParamAddress(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, TWData* _Nonnull val); +/// Adding a bytes type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamBytes(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, TWData *_Nonnull val); +int TWEthereumAbiFunctionAddInArrayParamBytes(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, TWData* _Nonnull val); +/// Adding a int64 type parameter of to the top-level input parameter array +/// +/// \param fn A Non-null eth abi function +/// \param arrayIdx array index for the abi function (0-based). +/// \param size fixed size of the bytes array parameter (val). +/// \param val the value of the parameter +/// \return the index of the added parameter (0-based). TW_EXPORT_METHOD TW_METHOD_DISCARDABLE_RESULT -int TWEthereumAbiFunctionAddInArrayParamBytesFix(struct TWEthereumAbiFunction *_Nonnull fn, int arrayIdx, size_t size, TWData *_Nonnull val); +int TWEthereumAbiFunctionAddInArrayParamBytesFix(struct TWEthereumAbiFunction* _Nonnull fn, int arrayIdx, size_t size, TWData* _Nonnull val); TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWEthereumAbiValue.h b/include/TrustWalletCore/TWEthereumAbiValue.h index 58a2f7e74d5..9bbf6ce34eb 100644 --- a/include/TrustWalletCore/TWEthereumAbiValue.h +++ b/include/TrustWalletCore/TWEthereumAbiValue.h @@ -12,55 +12,93 @@ TW_EXTERN_C_BEGIN +/// Represents Ethereum ABI value TW_EXPORT_STRUCT struct TWEthereumAbiValue; -/// Returned data must be deleted (hint: use WRAPD() macro). -/// Encode a type according to Ethereum ABI, into 32 bytes. Values are padded by 0 on the left, unless specified otherwise. - +/// Encode a bool according to Ethereum ABI, into 32 bytes. Values are padded by 0 on the left, unless specified otherwise +/// +/// \param value a boolean value +/// \return Encoded value stored in a block of data TW_EXPORT_STATIC_METHOD TWData* _Nonnull TWEthereumAbiValueEncodeBool(bool value); +/// Encode a int32 according to Ethereum ABI, into 32 bytes. Values are padded by 0 on the left, unless specified otherwise +/// +/// \param value a int32 value +/// \return Encoded value stored in a block of data TW_EXPORT_STATIC_METHOD TWData* _Nonnull TWEthereumAbiValueEncodeInt32(int32_t value); +/// Encode a uint32 according to Ethereum ABI, into 32 bytes. Values are padded by 0 on the left, unless specified otherwise +/// +/// \param value a uint32 value +/// \return Encoded value stored in a block of data TW_EXPORT_STATIC_METHOD TWData* _Nonnull TWEthereumAbiValueEncodeUInt32(uint32_t value); -/// Encode an int256. Input value is represented as a 32-byte value +/// Encode a int256 according to Ethereum ABI, into 32 bytes. Values are padded by 0 on the left, unless specified otherwise +/// +/// \param value a int256 value stored in a block of data +/// \return Encoded value stored in a block of data TW_EXPORT_STATIC_METHOD TWData* _Nonnull TWEthereumAbiValueEncodeInt256(TWData* _Nonnull value); -/// Encode an uint256. Input value is represented as a 32-byte binary value +/// Encode an int256 according to Ethereum ABI, into 32 bytes. Values are padded by 0 on the left, unless specified otherwise +/// +/// \param value a int256 value stored in a block of data +/// \return Encoded value stored in a block of data TW_EXPORT_STATIC_METHOD TWData* _Nonnull TWEthereumAbiValueEncodeUInt256(TWData* _Nonnull value); -/// Encode the 20 bytes of an address +/// Encode an address according to Ethereum ABI, 20 bytes of the address. +/// +/// \param value an address value stored in a block of data +/// \return Encoded value stored in a block of data TW_EXPORT_STATIC_METHOD TWData* _Nonnull TWEthereumAbiValueEncodeAddress(TWData* _Nonnull value); -/// Encode a string by encoding its hash +/// Encode a string according to Ethereum ABI by encoding its hash. +/// +/// \param value a string value +/// \return Encoded value stored in a block of data TW_EXPORT_STATIC_METHOD TWData* _Nonnull TWEthereumAbiValueEncodeString(TWString* _Nonnull value); /// Encode a number of bytes, up to 32 bytes, padded on the right. Longer arrays are truncated. +/// +/// \param value bunch of bytes +/// \return Encoded value stored in a block of data TW_EXPORT_STATIC_METHOD TWData* _Nonnull TWEthereumAbiValueEncodeBytes(TWData* _Nonnull value); /// Encode a dynamic number of bytes by encoding its hash +/// +/// \param value bunch of bytes +/// \return Encoded value stored in a block of data TW_EXPORT_STATIC_METHOD TWData* _Nonnull TWEthereumAbiValueEncodeBytesDyn(TWData* _Nonnull value); - /// Decodes input data (bytes longer than 32 will be truncated) as uint256 +/// +/// \param input Data to be decoded +/// \return Non-null decoded string value TW_EXPORT_STATIC_METHOD TWString* _Nonnull TWEthereumAbiValueDecodeUInt256(TWData* _Nonnull input); /// Decode an arbitrary type, return value as string +/// +/// \param input Data to be decoded +/// \param type the underlying type that need to be decoded +/// \return Non-null decoded string value TW_EXPORT_STATIC_METHOD TWString* _Nonnull TWEthereumAbiValueDecodeValue(TWData* _Nonnull input, TWString* _Nonnull type); /// Decode an array of given simple types. Return a '\n'-separated string of elements +/// +/// \param input Data to be decoded +/// \param type the underlying type that need to be decoded +/// \return Non-null decoded string value TW_EXPORT_STATIC_METHOD TWString* _Nonnull TWEthereumAbiValueDecodeArray(TWData* _Nonnull input, TWString* _Nonnull type); diff --git a/include/TrustWalletCore/TWFIOAccount.h b/include/TrustWalletCore/TWFIOAccount.h index 8012cbf0faf..876aabbda7d 100644 --- a/include/TrustWalletCore/TWFIOAccount.h +++ b/include/TrustWalletCore/TWFIOAccount.h @@ -15,13 +15,24 @@ TW_EXTERN_C_BEGIN TW_EXPORT_CLASS struct TWFIOAccount; +/// Create a FIO Account +/// +/// \param string Account name +/// \note Must be deleted with \TWFIOAccountDelete +/// \return Pointer to a nullable FIO Account TW_EXPORT_STATIC_METHOD struct TWFIOAccount *_Nullable TWFIOAccountCreateWithString(TWString *_Nonnull string); +/// Delete a FIO Account +/// +/// \param account Pointer to a non-null FIO Account TW_EXPORT_METHOD void TWFIOAccountDelete(struct TWFIOAccount *_Nonnull account); /// Returns the short account string representation. +/// +/// \param account Pointer to a non-null FIO Account +/// \return Account non-null string representation TW_EXPORT_PROPERTY TWString *_Nonnull TWFIOAccountDescription(struct TWFIOAccount *_Nonnull account); diff --git a/include/TrustWalletCore/TWGroestlcoinAddress.h b/include/TrustWalletCore/TWGroestlcoinAddress.h index 37edc0e8eb5..b35ce21ee64 100644 --- a/include/TrustWalletCore/TWGroestlcoinAddress.h +++ b/include/TrustWalletCore/TWGroestlcoinAddress.h @@ -19,25 +19,47 @@ TW_EXPORT_CLASS struct TWGroestlcoinAddress; /// Compares two addresses for equality. +/// +/// \param lhs left Non-null GroestlCoin address to be compared +/// \param rhs right Non-null GroestlCoin address to be compared +/// \return true if both address are equal, false otherwise TW_EXPORT_STATIC_METHOD bool TWGroestlcoinAddressEqual(struct TWGroestlcoinAddress *_Nonnull lhs, struct TWGroestlcoinAddress *_Nonnull rhs); /// Determines if the string is a valid Groestlcoin address. +/// +/// \param string Non-null string. +/// \return true if it's a valid address, false otherwise TW_EXPORT_STATIC_METHOD bool TWGroestlcoinAddressIsValidString(TWString *_Nonnull string); -/// Create an address from a base58 sring representaion. +/// Create an address from a base58 string representation. +/// +/// \param string Non-null string +/// \note Must be deleted with \TWGroestlcoinAddressDelete +/// \return Non-null GroestlcoinAddress TW_EXPORT_STATIC_METHOD struct TWGroestlcoinAddress *_Nullable TWGroestlcoinAddressCreateWithString(TWString *_Nonnull string); /// Create an address from a public key and a prefix byte. +/// +/// \param publicKey Non-null public key +/// \param prefix public key prefix +/// \note Must be deleted with \TWGroestlcoinAddressDelete +/// \return Non-null GroestlcoinAddress TW_EXPORT_STATIC_METHOD struct TWGroestlcoinAddress *_Nonnull TWGroestlcoinAddressCreateWithPublicKey(struct TWPublicKey *_Nonnull publicKey, uint8_t prefix); +/// Delete a Groestlcoin address +/// +/// \param address Non-null GroestlcoinAddress TW_EXPORT_METHOD void TWGroestlcoinAddressDelete(struct TWGroestlcoinAddress *_Nonnull address); /// Returns the address base58 string representation. +/// +/// \param address Non-null GroestlcoinAddress +/// \return Address description as a non-null string TW_EXPORT_PROPERTY TWString *_Nonnull TWGroestlcoinAddressDescription(struct TWGroestlcoinAddress *_Nonnull address); diff --git a/include/TrustWalletCore/TWHDVersion.h b/include/TrustWalletCore/TWHDVersion.h index 9e93aed3aa7..dec82a60ebc 100644 --- a/include/TrustWalletCore/TWHDVersion.h +++ b/include/TrustWalletCore/TWHDVersion.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,9 +10,9 @@ TW_EXTERN_C_BEGIN -/// Registered HD version bytes +/// Registered HD version bytes /// -/// - SeeAlso: https://github.com/satoshilabs/slips/blob/master/slip-0132.md +/// \see https://github.com/satoshilabs/slips/blob/master/slip-0132.md TW_EXPORT_ENUM(uint32_t) enum TWHDVersion { TWHDVersionNone = 0, @@ -40,9 +40,17 @@ enum TWHDVersion { TWHDVersionDGPV = 0x02fac398, }; +/// Determine if the HD Version is public +/// +/// \param version HD version +/// \return true if the version is public, false otherwise TW_EXPORT_PROPERTY bool TWHDVersionIsPublic(enum TWHDVersion version); +/// Determine if the HD Version is private +/// +/// \param version HD version +/// \return true if the version is private, false otherwise TW_EXPORT_PROPERTY bool TWHDVersionIsPrivate(enum TWHDVersion version); diff --git a/include/TrustWalletCore/TWHDWallet.h b/include/TrustWalletCore/TWHDWallet.h index 9ab93773c3a..55ab3e13b4a 100644 --- a/include/TrustWalletCore/TWHDWallet.h +++ b/include/TrustWalletCore/TWHDWallet.h @@ -10,8 +10,8 @@ #include "TWCoinType.h" #include "TWCurve.h" #include "TWData.h" -#include "TWHDVersion.h" #include "TWDerivation.h" +#include "TWHDVersion.h" #include "TWPrivateKey.h" #include "TWPublicKey.h" #include "TWPurpose.h" @@ -19,99 +19,218 @@ TW_EXTERN_C_BEGIN +/// Hierarchical Deterministic (HD) Wallet TW_EXPORT_CLASS struct TWHDWallet; -/// TWHDWalletIsValid has been deprecated; use TWMnemonicIsValid(). - /// Creates a new HDWallet with a new random mnemonic with the provided strength in bits. -/// Null is returned on invalid strength. Returned object needs to be deleted. +/// +/// \param strength strength in bits +/// \param passphrase non-null passphrase +/// \note Null is returned on invalid strength +/// \note Returned object needs to be deleted with \TWHDWalletDelete +/// \return Nullable TWHDWallet TW_EXPORT_STATIC_METHOD -struct TWHDWallet *_Nullable TWHDWalletCreate(int strength, TWString *_Nonnull passphrase); +struct TWHDWallet* _Nullable TWHDWalletCreate(int strength, TWString* _Nonnull passphrase); /// Creates an HDWallet from a valid BIP39 English mnemonic and a passphrase. -/// Null is returned on invalid mnemonic. Returned object needs to be deleted. +/// +/// \param mnemonic non-null Valid BIP39 mnemonic +/// \param passphrase non-null passphrase +/// \note Null is returned on invalid mnemonic +/// \note Returned object needs to be deleted with \TWHDWalletDelete +/// \return Nullable TWHDWallet TW_EXPORT_STATIC_METHOD -struct TWHDWallet *_Nullable TWHDWalletCreateWithMnemonic(TWString *_Nonnull mnemonic, TWString *_Nonnull passphrase); +struct TWHDWallet* _Nullable TWHDWalletCreateWithMnemonic(TWString* _Nonnull mnemonic, TWString* _Nonnull passphrase); /// Creates an HDWallet from a BIP39 mnemonic, a passphrase and validation flag. -/// Null is returned on invalid mnemonic. Returned object needs to be deleted. +/// +/// \param mnemonic non-null Valid BIP39 mnemonic +/// \param passphrase non-null passphrase +/// \param check validation flag +/// \note Null is returned on invalid mnemonic +/// \note Returned object needs to be deleted with \TWHDWalletDelete +/// \return Nullable TWHDWallet TW_EXPORT_STATIC_METHOD -struct TWHDWallet *_Nullable TWHDWalletCreateWithMnemonicCheck(TWString *_Nonnull mnemonic, TWString *_Nonnull passphrase, bool check); +struct TWHDWallet* _Nullable TWHDWalletCreateWithMnemonicCheck(TWString* _Nonnull mnemonic, TWString* _Nonnull passphrase, bool check); /// Creates an HDWallet from entropy (corresponding to a mnemonic). -/// Null is returned on invalid input. Returned object needs to be deleted. +/// +/// \param entropy Non-null entropy data (corresponding to a mnemonic) +/// \param passphrase non-null passphrase +/// \note Null is returned on invalid input +/// \note Returned object needs to be deleted with \TWHDWalletDelete +/// \return Nullable TWHDWallet TW_EXPORT_STATIC_METHOD -struct TWHDWallet *_Nullable TWHDWalletCreateWithEntropy(TWData *_Nonnull entropy, TWString *_Nonnull passphrase); +struct TWHDWallet* _Nullable TWHDWalletCreateWithEntropy(TWData* _Nonnull entropy, TWString* _Nonnull passphrase); /// Deletes a wallet. +/// +/// \param wallet non-null TWHDWallet TW_EXPORT_METHOD -void TWHDWalletDelete(struct TWHDWallet *_Nonnull wallet); +void TWHDWalletDelete(struct TWHDWallet* _Nonnull wallet); /// Wallet seed. +/// +/// \param wallet non-null TWHDWallet +/// \return The wallet seed as a Non-null block of data. TW_EXPORT_PROPERTY -TWData *_Nonnull TWHDWalletSeed(struct TWHDWallet *_Nonnull wallet); +TWData* _Nonnull TWHDWalletSeed(struct TWHDWallet* _Nonnull wallet); -// Wallet Mnemonic +/// Wallet Mnemonic +/// +/// \param wallet non-null TWHDWallet +/// \return The wallet mnemonic as a non-null TWString TW_EXPORT_PROPERTY -TWString *_Nonnull TWHDWalletMnemonic(struct TWHDWallet *_Nonnull wallet); +TWString* _Nonnull TWHDWalletMnemonic(struct TWHDWallet* _Nonnull wallet); -// Wallet entropy +/// Wallet entropy +/// +/// \param wallet non-null TWHDWallet +/// \return The wallet entropy as a non-null block of data. TW_EXPORT_PROPERTY -TWData *_Nonnull TWHDWalletEntropy(struct TWHDWallet *_Nonnull wallet); +TWData* _Nonnull TWHDWalletEntropy(struct TWHDWallet* _Nonnull wallet); -/// Returns master key. Returned object needs to be deleted. +/// Returns master key. +/// +/// \param wallet non-null TWHDWallet +/// \param curve a curve +/// \note Returned object needs to be deleted with \TWPrivateKeyDelete +/// \return Non-null corresponding private key TW_EXPORT_METHOD -struct TWPrivateKey *_Nonnull TWHDWalletGetMasterKey(struct TWHDWallet *_Nonnull wallet, enum TWCurve curve); +struct TWPrivateKey* _Nonnull TWHDWalletGetMasterKey(struct TWHDWallet* _Nonnull wallet, enum TWCurve curve); -/// Generates the default private key for the specified coin. Returned object needs to be deleted. +/// Generates the default private key for the specified coin. +/// +/// \param wallet non-null TWHDWallet +/// \param coin a coin type +/// \note Returned object needs to be deleted with \TWPrivateKeyDelete +/// \return return the default private key for the specified coin TW_EXPORT_METHOD -struct TWPrivateKey *_Nonnull TWHDWalletGetKeyForCoin(struct TWHDWallet *_Nonnull wallet, enum TWCoinType coin); +struct TWPrivateKey* _Nonnull TWHDWalletGetKeyForCoin(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin); /// Generates the default address for the specified coin (without exposing intermediary private key). +/// +/// \param wallet non-null TWHDWallet +/// \param coin a coin type +/// \return return the default address for the specified coin as a non-null TWString TW_EXPORT_METHOD -TWString *_Nonnull TWHDWalletGetAddressForCoin(struct TWHDWallet *_Nonnull wallet, enum TWCoinType coin); +TWString* _Nonnull TWHDWalletGetAddressForCoin(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin); -/// Generates the private key for the specified derivation path. Returned object needs to be deleted. +/// Generates the private key for the specified derivation path. +/// +/// \param wallet non-null TWHDWallet +/// \param coin a coin type +/// \param derivationPath a non-null derivation path +/// \note Returned object needs to be deleted with \TWPrivateKeyDelete +/// \return The private key for the specified derivation path/coin TW_EXPORT_METHOD -struct TWPrivateKey *_Nonnull TWHDWalletGetKey(struct TWHDWallet *_Nonnull wallet, enum TWCoinType coin, TWString *_Nonnull derivationPath); +struct TWPrivateKey* _Nonnull TWHDWalletGetKey(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin, TWString* _Nonnull derivationPath); -/// Generates the private key for the specified derivation path and curve. Returned object needs to be deleted. +/// Generates the private key for the specified derivation path and curve. +/// +/// \param wallet non-null TWHDWallet +/// \param curve a curve +/// \param derivationPath a non-null derivation path +/// \note Returned object needs to be deleted with \TWPrivateKeyDelete +/// \return The private key for the specified derivation path/curve TW_EXPORT_METHOD -struct TWPrivateKey *_Nonnull TWHDWalletGetKeyByCurve(struct TWHDWallet *_Nonnull wallet, enum TWCurve curve, TWString *_Nonnull derivationPath); +struct TWPrivateKey* _Nonnull TWHDWalletGetKeyByCurve(struct TWHDWallet* _Nonnull wallet, enum TWCurve curve, TWString* _Nonnull derivationPath); -/// Shortcut method to generate private key with the specified account/change/address (bip44 standard). Returned object needs to be deleted. +/// Shortcut method to generate private key with the specified account/change/address (bip44 standard). +/// +/// \see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki /// -/// @see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki +/// \param wallet non-null TWHDWallet +/// \param coin a coin type +/// \param account valid bip44 account +/// \param change valid bip44 change +/// \param address valid bip44 address +/// \note Returned object needs to be deleted with \TWPrivateKeyDelete +/// \return The private key for the specified bip44 parameters TW_EXPORT_METHOD -struct TWPrivateKey *_Nonnull TWHDWalletGetDerivedKey(struct TWHDWallet *_Nonnull wallet, enum TWCoinType coin, uint32_t account, uint32_t change, uint32_t address); +struct TWPrivateKey* _Nonnull TWHDWalletGetDerivedKey(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin, uint32_t account, uint32_t change, uint32_t address); -/// Returns the extended private key (for default 0 account). Returned object needs to be deleted. +/// Returns the extended private key (for default 0 account). +/// +/// \param wallet non-null TWHDWallet +/// \param purpose a purpose +/// \param coin a coin type +/// \param version hd version +/// \note Returned object needs to be deleted with \TWStringDelete +/// \return Extended private key as a non-null TWString TW_EXPORT_METHOD -TWString *_Nonnull TWHDWalletGetExtendedPrivateKey(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWHDVersion version); +TWString* _Nonnull TWHDWalletGetExtendedPrivateKey(struct TWHDWallet* _Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWHDVersion version); -/// Returns the exteded public key (for default 0 account). Returned object needs to be deleted. +/// Returns the extended public key (for default 0 account). +/// +/// \param wallet non-null TWHDWallet +/// \param purpose a purpose +/// \param coin a coin type +/// \param version hd version +/// \note Returned object needs to be deleted with \TWStringDelete +/// \return Extended public key as a non-null TWString TW_EXPORT_METHOD -TWString *_Nonnull TWHDWalletGetExtendedPublicKey(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWHDVersion version); +TWString* _Nonnull TWHDWalletGetExtendedPublicKey(struct TWHDWallet* _Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWHDVersion version); -/// Returns the extended private key, for custom account. Returned object needs to be deleted. +/// Returns the extended private key, for custom account. +/// +/// \param wallet non-null TWHDWallet +/// \param purpose a purpose +/// \param coin a coin type +/// \param derivation a derivation +/// \param version an hd version +/// \param account valid bip44 account +/// \note Returned object needs to be deleted with \TWStringDelete +/// \return Extended private key as a non-null TWString TW_EXPORT_METHOD -TWString *_Nonnull TWHDWalletGetExtendedPrivateKeyAccount(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWDerivation derivation, enum TWHDVersion version, uint32_t account); +TWString* _Nonnull TWHDWalletGetExtendedPrivateKeyAccount(struct TWHDWallet* _Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWDerivation derivation, enum TWHDVersion version, uint32_t account); -/// Returns the exteded public key, for custom account. Returned object needs to be deleted. +/// Returns the extended public key, for custom account. +/// +/// \param wallet non-null TWHDWallet +/// \param purpose a purpose +/// \param coin a coin type +/// \param derivation a derivation +/// \param version an hd version +/// \param account valid bip44 account +/// \note Returned object needs to be deleted with \TWStringDelete +/// \return Extended public key as a non-null TWString TW_EXPORT_METHOD -TWString *_Nonnull TWHDWalletGetExtendedPublicKeyAccount(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWDerivation derivation, enum TWHDVersion version, uint32_t account); +TWString* _Nonnull TWHDWalletGetExtendedPublicKeyAccount(struct TWHDWallet* _Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWDerivation derivation, enum TWHDVersion version, uint32_t account); -/// Returns the extended private key (for default 0 account with derivation). Returned object needs to be deleted. +/// Returns the extended private key (for default 0 account with derivation). +/// +/// \param wallet non-null TWHDWallet +/// \param purpose a purpose +/// \param coin a coin type +/// \param derivation a derivation +/// \param version an hd version +/// \note Returned object needs to be deleted with \TWStringDelete +/// \return Extended private key as a non-null TWString TW_EXPORT_METHOD -TWString *_Nonnull TWHDWalletGetExtendedPrivateKeyDerivation(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWDerivation derivation, enum TWHDVersion version); +TWString* _Nonnull TWHDWalletGetExtendedPrivateKeyDerivation(struct TWHDWallet* _Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWDerivation derivation, enum TWHDVersion version); -/// Returns the exteded public key (for default 0 account with derivation). Returned object needs to be deleted. +/// Returns the extended public key (for default 0 account with derivation). +/// +/// \param wallet non-null TWHDWallet +/// \param purpose a purpose +/// \param coin a coin type +/// \param derivation a derivation +/// \param version an hd version +/// \note Returned object needs to be deleted with \TWStringDelete +/// \return Extended public key as a non-null TWString TW_EXPORT_METHOD -TWString *_Nonnull TWHDWalletGetExtendedPublicKeyDerivation(struct TWHDWallet *_Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWDerivation derivation, enum TWHDVersion version); +TWString* _Nonnull TWHDWalletGetExtendedPublicKeyDerivation(struct TWHDWallet* _Nonnull wallet, enum TWPurpose purpose, enum TWCoinType coin, enum TWDerivation derivation, enum TWHDVersion version); -/// Computes the public key from an exteded public key representation. Returned object needs to be deleted. +/// Computes the public key from an extended public key representation. +/// +/// \param extended extended public key +/// \param coin a coin type +/// \param derivationPath a derivation path +/// \note Returned object needs to be deleted with \TWPublicKeyDelete +/// \return Nullable TWPublic key TW_EXPORT_STATIC_METHOD -struct TWPublicKey *_Nullable TWHDWalletGetPublicKeyFromExtended(TWString *_Nonnull extended, enum TWCoinType coin, TWString *_Nonnull derivationPath); +struct TWPublicKey* _Nullable TWHDWalletGetPublicKeyFromExtended(TWString* _Nonnull extended, enum TWCoinType coin, TWString* _Nonnull derivationPath); TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWHash.h b/include/TrustWalletCore/TWHash.h index 79bdaffc7c2..ccdb7d0fb9e 100644 --- a/include/TrustWalletCore/TWHash.h +++ b/include/TrustWalletCore/TWHash.h @@ -11,6 +11,7 @@ TW_EXTERN_C_BEGIN +/// Hash functions TW_EXPORT_STRUCT struct TWHash { uint8_t unused; // C doesn't allow zero-sized struct @@ -22,57 +23,128 @@ static const size_t TWHashSHA512Length = 64; static const size_t TWHashRipemdLength = 20; /// Computes the SHA1 of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed SHA1 block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashSHA1(TWData *_Nonnull data); +/// Computes the SHA256 of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed SHA256 block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashSHA256(TWData *_Nonnull data); +/// Computes the SHA512 of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed SHA512 block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashSHA512(TWData *_Nonnull data); +/// Computes the SHA512_256 of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed SHA512_256 block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashSHA512_256(TWData *_Nonnull data); +/// Computes the Keccak256 of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed Keccak256 block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashKeccak256(TWData *_Nonnull data); +/// Computes the Keccak512 of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed Keccak512 block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashKeccak512(TWData *_Nonnull data); +/// Computes the SHA3_256 of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed SHA3_256 block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashSHA3_256(TWData *_Nonnull data); +/// Computes the SHA3_512 of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed SHA3_512 block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashSHA3_512(TWData *_Nonnull data); +/// Computes the RIPEMD of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed RIPEMD block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashRIPEMD(TWData *_Nonnull data); +/// Computes the Blake256 of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed Blake256 block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashBlake256(TWData *_Nonnull data); +/// Computes the Blake2b of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed Blake2b block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashBlake2b(TWData *_Nonnull data, size_t size); +/// Computes the Groestl512 of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed Groestl512 block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashGroestl512(TWData *_Nonnull data); +/// Computes the SHA256D of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed SHA256D block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashSHA256SHA256(TWData *_Nonnull data); +/// Computes the SHA256RIPEMD of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed SHA256RIPEMD block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashSHA256RIPEMD(TWData *_Nonnull data); +/// Computes the SHA3_256RIPEMD of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed SHA3_256RIPEMD block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashSHA3_256RIPEMD(TWData *_Nonnull data); +/// Computes the Blake256D of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed Blake256D block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashBlake256Blake256(TWData *_Nonnull data); +/// Computes the Blake256RIPEMD of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed Blake256RIPEMD block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashBlake256RIPEMD(TWData *_Nonnull data); +/// Computes the Groestl512D of a block of data. +/// +/// \param data Non-null block of data +/// \return Non-null computed Groestl512D block of data TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWHashGroestl512Groestl512(TWData *_Nonnull data); diff --git a/include/TrustWalletCore/TWMnemonic.h b/include/TrustWalletCore/TWMnemonic.h index b8b60d46158..f74b6ad164f 100644 --- a/include/TrustWalletCore/TWMnemonic.h +++ b/include/TrustWalletCore/TWMnemonic.h @@ -11,18 +11,28 @@ TW_EXTERN_C_BEGIN +/// Mnemonic validate / lookup functions TW_EXPORT_STRUCT struct TWMnemonic; /// Determines whether a BIP39 English mnemonic phrase is valid. +/// +/// \param mnemonic Non-null BIP39 english mnemonic +/// \return true if the mnemonic is valid, false otherwise TW_EXPORT_STATIC_METHOD bool TWMnemonicIsValid(TWString *_Nonnull mnemonic); -/// Determines whether word is a valid BIP39 English menemonic word. +/// Determines whether word is a valid BIP39 English mnemonic word. +/// +/// \param word Non-null BIP39 English mnemonic word +/// \return true if the word is a valid BIP39 English mnemonic word, false otherwise TW_EXPORT_STATIC_METHOD bool TWMnemonicIsValidWord(TWString *_Nonnull word); /// Return BIP39 English words that match the given prefix. A single string is returned, with space-separated list of words. +/// +/// \param prefix Non-null string prefix +/// \return Single non-null string, space-separated list of words containing BIP39 words that match the given prefix. TW_EXPORT_STATIC_METHOD TWString* _Nonnull TWMnemonicSuggest(TWString *_Nonnull prefix); diff --git a/include/TrustWalletCore/TWNEARAccount.h b/include/TrustWalletCore/TWNEARAccount.h index 66b4c8ee3ec..73e7662fe34 100644 --- a/include/TrustWalletCore/TWNEARAccount.h +++ b/include/TrustWalletCore/TWNEARAccount.h @@ -15,13 +15,24 @@ TW_EXTERN_C_BEGIN TW_EXPORT_CLASS struct TWNEARAccount; +/// Create a NEAR Account +/// +/// \param string Account name +/// \note Account should be deleted by calling \TWNEARAccountDelete +/// \return Pointer to a nullable NEAR Account. TW_EXPORT_STATIC_METHOD struct TWNEARAccount *_Nullable TWNEARAccountCreateWithString(TWString *_Nonnull string); +/// Delete the given Near Account +/// +/// \param account Pointer to a non-null NEAR Account TW_EXPORT_METHOD void TWNEARAccountDelete(struct TWNEARAccount *_Nonnull account); /// Returns the user friendly string representation. +/// +/// \param account Pointer to a non-null NEAR Account +/// \return Non-null string account description TW_EXPORT_PROPERTY TWString *_Nonnull TWNEARAccountDescription(struct TWNEARAccount *_Nonnull account); diff --git a/include/TrustWalletCore/TWNervosAddress.h b/include/TrustWalletCore/TWNervosAddress.h index cbd095737dc..b12e663aec1 100644 --- a/include/TrustWalletCore/TWNervosAddress.h +++ b/include/TrustWalletCore/TWNervosAddress.h @@ -17,33 +17,54 @@ TW_EXPORT_CLASS struct TWNervosAddress; /// Compares two addresses for equality. +/// +/// \param lhs The first address to compare. +/// \param rhs The second address to compare. +/// \return bool indicating the addresses are equal. TW_EXPORT_STATIC_METHOD bool TWNervosAddressEqual(struct TWNervosAddress *_Nonnull lhs, struct TWNervosAddress *_Nonnull rhs); /// Determines if the string is a valid Nervos address. +/// +/// \param string string to validate. +/// \return bool indicating if the address is valid. TW_EXPORT_STATIC_METHOD bool TWNervosAddressIsValidString(TWString *_Nonnull string); /// Initializes an address from a sring representaion. +/// +/// \param string Bech32 string to initialize the address from. +/// \return TWNervosAddress pointer or nullptr if string is invalid. TW_EXPORT_STATIC_METHOD struct TWNervosAddress *_Nullable TWNervosAddressCreateWithString(TWString *_Nonnull string); +/// Deletes a Nervos address. +/// +/// \param address Address to delete. TW_EXPORT_METHOD void TWNervosAddressDelete(struct TWNervosAddress *_Nonnull address); -/// Returns the address base58 string representation. +/// Returns the address string representation. +/// +/// \param address Address to get the string representation of. TW_EXPORT_PROPERTY TWString *_Nonnull TWNervosAddressDescription(struct TWNervosAddress *_Nonnull address); -/// Returns the keyhash data. +/// Returns the Code hash +/// +/// \param address Address to get the keyhash data of. TW_EXPORT_PROPERTY TWData *_Nonnull TWNervosAddressCodeHash(struct TWNervosAddress *_Nonnull address); -/// Returns the address prefix. +/// Returns the address hash type +/// +/// \param address Address to get the hash type of. TW_EXPORT_PROPERTY TWString *_Nonnull TWNervosAddressHashType(struct TWNervosAddress *_Nonnull address); -/// Returns the keyhash data. +/// Returns the address args data. +/// +/// \param address Address to get the args data of. TW_EXPORT_PROPERTY TWData *_Nonnull TWNervosAddressArgs(struct TWNervosAddress *_Nonnull address); diff --git a/include/TrustWalletCore/TWPBKDF2.h b/include/TrustWalletCore/TWPBKDF2.h index dc3bb4dcf28..a7edcc65380 100644 --- a/include/TrustWalletCore/TWPBKDF2.h +++ b/include/TrustWalletCore/TWPBKDF2.h @@ -11,6 +11,7 @@ TW_EXTERN_C_BEGIN +/// Password-Based Key Derivation Function 2 TW_EXPORT_STRUCT struct TWPBKDF2; @@ -20,6 +21,7 @@ struct TWPBKDF2; /// \param salt is a sequence of bits, known as a cryptographic salt /// \param iterations is the number of iterations desired /// \param dkLen is the desired bit-length of the derived key +/// \return the derived key data. TW_EXPORT_STATIC_METHOD TWData *_Nullable TWPBKDF2HmacSha256(TWData *_Nonnull password, TWData *_Nonnull salt, uint32_t iterations, uint32_t dkLen); @@ -29,6 +31,7 @@ TWData *_Nullable TWPBKDF2HmacSha256(TWData *_Nonnull password, TWData *_Nonnull /// \param salt is a sequence of bits, known as a cryptographic salt /// \param iterations is the number of iterations desired /// \param dkLen is the desired bit-length of the derived key +/// \return the derived key data. TW_EXPORT_STATIC_METHOD TWData *_Nullable TWPBKDF2HmacSha512(TWData *_Nonnull password, TWData *_Nonnull salt, uint32_t iterations, uint32_t dkLen); diff --git a/include/TrustWalletCore/TWPrivateKey.h b/include/TrustWalletCore/TWPrivateKey.h index bf6b4b11016..ee4cf3fc7e2 100644 --- a/include/TrustWalletCore/TWPrivateKey.h +++ b/include/TrustWalletCore/TWPrivateKey.h @@ -13,67 +13,131 @@ TW_EXTERN_C_BEGIN +/// Represents a private key. TW_EXPORT_CLASS struct TWPrivateKey; static const size_t TWPrivateKeySize = 32; +/// Create a random private key +/// +/// \note Should be deleted with \TWPrivateKeyDelete +/// \return Non-null Private key TW_EXPORT_STATIC_METHOD struct TWPrivateKey* _Nonnull TWPrivateKeyCreate(void); +/// Create a private key with the given block of data +/// +/// \param data a block of data +/// \note Should be deleted with \TWPrivateKeyDelete +/// \return Nullable pointer to Private Key TW_EXPORT_STATIC_METHOD struct TWPrivateKey* _Nullable TWPrivateKeyCreateWithData(TWData* _Nonnull data); +/// Deep copy a given private key +/// +/// \param key Non-null private key to be copied +/// \note Should be deleted with \TWPrivateKeyDelete +/// \return Deep copy, Nullable pointer to Private key TW_EXPORT_STATIC_METHOD struct TWPrivateKey* _Nullable TWPrivateKeyCreateCopy(struct TWPrivateKey* _Nonnull key); +/// Delete the given private key +/// +/// \param pk Non-null pointer to private key TW_EXPORT_METHOD void TWPrivateKeyDelete(struct TWPrivateKey* _Nonnull pk); +/// Determines if the given private key is valid or not. +/// +/// \param data block of data (private key bytes) +/// \param curve Eliptic curve of the private key +/// \return true if the private key is valid, false otherwise TW_EXPORT_STATIC_METHOD bool TWPrivateKeyIsValid(TWData* _Nonnull data, enum TWCurve curve); +/// Convert the given private key to raw-bytes block of data +/// +/// \param pk Non-null pointer to the private key +/// \return Non-null block of data (raw bytes) of the given private key TW_EXPORT_PROPERTY TWData* _Nonnull TWPrivateKeyData(struct TWPrivateKey* _Nonnull pk); -/// Returns the public key associated with this private key. +/// Returns the Secp256k1 public key associated with the given private key +/// +/// \param pk Non-null pointer to the private key +/// \param compressed if the given private key is compressed or not +/// \return Non-null pointer to the corresponding public key TW_EXPORT_METHOD struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeySecp256k1(struct TWPrivateKey* _Nonnull pk, bool compressed); -/// Returns the public key associated with this private key. +/// Returns the Nist256p1 public key associated with the given private key +/// +/// \param pk Non-null pointer to the private key +/// \return Non-null pointer to the corresponding public key TW_EXPORT_METHOD struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyNist256p1(struct TWPrivateKey* _Nonnull pk); -/// Returns the public key associated with this private key. +/// Returns the Ed25519 public key associated with the given private key +/// +/// \param pk Non-null pointer to the private key +/// \return Non-null pointer to the corresponding public key TW_EXPORT_METHOD struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyEd25519(struct TWPrivateKey* _Nonnull pk); -/// Returns the public key associated with this private key. +/// Returns the Ed25519Blake2b public key associated with the given private key +/// +/// \param pk Non-null pointer to the private key +/// \return Non-null pointer to the corresponding public key TW_EXPORT_METHOD struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyEd25519Blake2b(struct TWPrivateKey* _Nonnull pk); -/// Returns the Cardano style public key associated with this private key. +/// Returns the Ed25519Cardano public key associated with the given private key +/// +/// \param pk Non-null pointer to the private key +/// \return Non-null pointer to the corresponding public key TW_EXPORT_METHOD struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyEd25519Cardano(struct TWPrivateKey* _Nonnull pk); -/// Returns the public key associated with this private key. +/// Returns the Curve25519 public key associated with the given private key +/// +/// \param pk Non-null pointer to the private key +/// \return Non-null pointer to the corresponding public key TW_EXPORT_METHOD struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyCurve25519(struct TWPrivateKey* _Nonnull pk); /// Computes an EC Diffie-Hellman secret in constant time /// Supported curves: secp256k1 +/// +/// \param pk Non-null pointer to a Private key +/// \param publicKey Non-null pointer to the corresponding public key +/// \param curve Eliptic curve +/// \return The corresponding shared key as a non-null block of data TW_EXPORT_METHOD TWData* _Nullable TWPrivateKeyGetSharedKey(const struct TWPrivateKey* _Nonnull pk, const struct TWPublicKey* _Nonnull publicKey, enum TWCurve curve); /// Signs a digest using ECDSA and given curve. +/// +/// \param pk Non-null pointer to a Private key +/// \param digest Non-null digest block of data +/// \param curve Eliptic curve +/// \return Signature as a Non-null block of data TW_EXPORT_METHOD TWData* _Nullable TWPrivateKeySign(struct TWPrivateKey* _Nonnull pk, TWData* _Nonnull digest, enum TWCurve curve); /// Signs a digest using ECDSA. The result is encoded with DER. +/// +/// \param pk Non-null pointer to a Private key +/// \param digest Non-null digest block of data +/// \return Signature as a Non-null block of data TW_EXPORT_METHOD TWData* _Nullable TWPrivateKeySignAsDER(struct TWPrivateKey* _Nonnull pk, TWData* _Nonnull digest); /// Signs a digest using ECDSA and Zilliqa schnorr signature scheme. +/// +/// \param pk Non-null pointer to a Private key +/// \param message Non-null message +/// \return Signature as a Non-null block of data TW_EXPORT_METHOD TWData* _Nullable TWPrivateKeySignZilliqaSchnorr(struct TWPrivateKey* _Nonnull pk, TWData* _Nonnull message); diff --git a/include/TrustWalletCore/TWPublicKey.h b/include/TrustWalletCore/TWPublicKey.h index 479115ce10b..d9164855382 100644 --- a/include/TrustWalletCore/TWPublicKey.h +++ b/include/TrustWalletCore/TWPublicKey.h @@ -16,46 +16,108 @@ TW_EXTERN_C_BEGIN static const size_t TWPublicKeyCompressedSize = 33; static const size_t TWPublicKeyUncompressedSize = 65; +/// Represents a public key. TW_EXPORT_CLASS struct TWPublicKey; +/// Create a public key from a block of data +/// +/// \param data Non-null block of data representing the public key +/// \param type type of the public key +/// \note Should be deleted with \TWPublicKeyDelete +/// \return Nullable pointer to the public key TW_EXPORT_STATIC_METHOD struct TWPublicKey *_Nullable TWPublicKeyCreateWithData(TWData *_Nonnull data, enum TWPublicKeyType type); +/// Delete the given public key +/// +/// \param pk Non-null pointer to a public key TW_EXPORT_METHOD void TWPublicKeyDelete(struct TWPublicKey *_Nonnull pk); +/// Determines if the given public key is valid or not +/// +/// \param data Non-null block of data representing the public key +/// \param type type of the public key +/// \return true if the block of data is a valid public key, false otherwise TW_EXPORT_STATIC_METHOD bool TWPublicKeyIsValid(TWData *_Nonnull data, enum TWPublicKeyType type); +/// Determines if the given public key is compressed or not +/// +/// \param pk Non-null pointer to a public key +/// \return true if the public key is compressed, false otherwise TW_EXPORT_PROPERTY bool TWPublicKeyIsCompressed(struct TWPublicKey *_Nonnull pk); +/// Give the compressed public key of the given non-compressed public key +/// +/// \param from Non-null pointer to a non-compressed public key +/// \return Non-null pointer to the corresponding compressed public-key TW_EXPORT_PROPERTY struct TWPublicKey *_Nonnull TWPublicKeyCompressed(struct TWPublicKey *_Nonnull from); +/// Give the non-compressed public key of a corresponding compressed public key +/// +/// \param from Non-null pointer to the corresponding compressed public key +/// \return Non-null pointer to the corresponding non-compressed public key TW_EXPORT_PROPERTY struct TWPublicKey *_Nonnull TWPublicKeyUncompressed(struct TWPublicKey *_Nonnull from); +/// Gives the raw data of a given public-key +/// +/// \param pk Non-null pointer to a public key +/// \return Non-null pointer to the raw block of data of the given public key TW_EXPORT_PROPERTY TWData *_Nonnull TWPublicKeyData(struct TWPublicKey *_Nonnull pk); +/// Verify the validity of a signature and a message using the given public key +/// +/// \param pk Non-null pointer to a public key +/// \param signature Non-null pointer to a block of data corresponding to the signature +/// \param message Non-null pointer to a block of data corresponding to the message +/// \return true if the signature and the message belongs to the given public key, false otherwise TW_EXPORT_METHOD bool TWPublicKeyVerify(struct TWPublicKey *_Nonnull pk, TWData *_Nonnull signature, TWData *_Nonnull message); +/// Verify the validity as DER of a signature and a message using the given public key +/// +/// \param pk Non-null pointer to a public key +/// \param signature Non-null pointer to a block of data corresponding to the signature +/// \param message Non-null pointer to a block of data corresponding to the message +/// \return true if the signature and the message belongs to the given public key, false otherwise TW_EXPORT_METHOD bool TWPublicKeyVerifyAsDER(struct TWPublicKey *_Nonnull pk, TWData *_Nonnull signature, TWData *_Nonnull message); /// Verify a Zilliqa schnorr signature with a signature and message. +/// +/// \param pk Non-null pointer to a public key +/// \param signature Non-null pointer to a block of data corresponding to the signature +/// \param message Non-null pointer to a block of data corresponding to the message +/// \return true if the signature and the message belongs to the given public key, false otherwise TW_EXPORT_METHOD bool TWPublicKeyVerifyZilliqaSchnorr(struct TWPublicKey *_Nonnull pk, TWData *_Nonnull signature, TWData *_Nonnull message); +/// Give the public key type (eliptic) of a given public key +/// +/// \param publicKey Non-null pointer to a public key +/// \return The public key type of the given public key (eliptic) TW_EXPORT_PROPERTY enum TWPublicKeyType TWPublicKeyKeyType(struct TWPublicKey *_Nonnull publicKey); +/// Get the public key description from a given public key +/// +/// \param publicKey Non-null pointer to a public key +/// \return Non-null pointer to a string representing the description of the public key TW_EXPORT_PROPERTY TWString *_Nonnull TWPublicKeyDescription(struct TWPublicKey *_Nonnull publicKey); +/// Try to get a public key from a given signature and a message +/// +/// \param signature Non-null pointer to a block of data corresponding to the signature +/// \param message Non-null pointer to a block of data corresponding to the message +/// \return Null pointer if the public key can't be recover from the given signature and message, +/// pointer to the public key otherwise TW_EXPORT_STATIC_METHOD struct TWPublicKey *_Nullable TWPublicKeyRecover(TWData *_Nonnull signature, TWData *_Nonnull message); diff --git a/include/TrustWalletCore/TWPurpose.h b/include/TrustWalletCore/TWPurpose.h index ad4d9206cc7..509b813bbec 100644 --- a/include/TrustWalletCore/TWPurpose.h +++ b/include/TrustWalletCore/TWPurpose.h @@ -12,9 +12,9 @@ TW_EXTERN_C_BEGIN /// HD wallet purpose /// -/// See https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki -/// See https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki -/// See https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki +/// \see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki +/// \see https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki +/// \see https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki TW_EXPORT_ENUM(uint32_t) enum TWPurpose { TWPurposeBIP44 = 44, diff --git a/include/TrustWalletCore/TWRippleXAddress.h b/include/TrustWalletCore/TWRippleXAddress.h index 8b41daf1a82..401b885e554 100644 --- a/include/TrustWalletCore/TWRippleXAddress.h +++ b/include/TrustWalletCore/TWRippleXAddress.h @@ -20,29 +20,54 @@ TW_EXPORT_CLASS struct TWRippleXAddress; /// Compares two addresses for equality. +/// +/// \param lhs left non-null pointer to a Ripple Address +/// \param rhs right non-null pointer to a Ripple Address +/// \return true if both address are equal, false otherwise TW_EXPORT_STATIC_METHOD bool TWRippleXAddressEqual(struct TWRippleXAddress *_Nonnull lhs, struct TWRippleXAddress *_Nonnull rhs); /// Determines if the string is a valid Ripple address. +/// +/// \param string Non-null pointer to a string that represent the Ripple Address to be checked +/// \return true if the given address is a valid Ripple address, false otherwise TW_EXPORT_STATIC_METHOD bool TWRippleXAddressIsValidString(TWString *_Nonnull string); -/// Creates an address from a string representaion. +/// Creates an address from a string representation. +/// +/// \param string Non-null pointer to a string that should be a valid ripple address +/// \note Should be deleted with \TWRippleXAddressDelete +/// \return Null pointer if the given string is an invalid ripple address, pointer to a Ripple address otherwise TW_EXPORT_STATIC_METHOD struct TWRippleXAddress *_Nullable TWRippleXAddressCreateWithString(TWString *_Nonnull string); /// Creates an address from a public key and destination tag. +/// +/// \param publicKey Non-null pointer to a public key +/// \param tag valid ripple destination tag (1-10) +/// \note Should be deleted with \TWRippleXAddressDelete +/// \return Non-null pointer to a Ripple Address TW_EXPORT_STATIC_METHOD struct TWRippleXAddress *_Nonnull TWRippleXAddressCreateWithPublicKey(struct TWPublicKey *_Nonnull publicKey, uint32_t tag); +/// Delete the given ripple address +/// +/// \param address Non-null pointer to a Ripple Address TW_EXPORT_METHOD void TWRippleXAddressDelete(struct TWRippleXAddress *_Nonnull address); /// Returns the address string representation. +/// +/// \param address Non-null pointer to a Ripple Address +/// \return Non-null pointer to the ripple address string representation TW_EXPORT_PROPERTY TWString *_Nonnull TWRippleXAddressDescription(struct TWRippleXAddress *_Nonnull address); /// Returns the destination tag. +/// +/// \param address Non-null pointer to a Ripple Address +/// \return The destination tag of the given Ripple Address (1-10) TW_EXPORT_PROPERTY uint32_t TWRippleXAddressTag(struct TWRippleXAddress *_Nonnull address); diff --git a/include/TrustWalletCore/TWSS58AddressType.h b/include/TrustWalletCore/TWSS58AddressType.h index 13ca9769e39..b6bf7e50927 100644 --- a/include/TrustWalletCore/TWSS58AddressType.h +++ b/include/TrustWalletCore/TWSS58AddressType.h @@ -1,5 +1,5 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,9 +11,9 @@ TW_EXTERN_C_BEGIN -/// Substrate based chains Address Type +/// Substrate based chains Address Type /// -/// - See Also: https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58)#address-type +/// \see https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58)#address-type TW_EXPORT_ENUM(uint8_t) enum TWSS58AddressType { TWSS58AddressTypePolkadot = 0, diff --git a/include/TrustWalletCore/TWSegwitAddress.h b/include/TrustWalletCore/TWSegwitAddress.h index cdc7ece7297..3e106375527 100644 --- a/include/TrustWalletCore/TWSegwitAddress.h +++ b/include/TrustWalletCore/TWSegwitAddress.h @@ -20,38 +20,69 @@ TW_EXPORT_CLASS struct TWSegwitAddress; /// Compares two addresses for equality. +/// +/// \param lhs left non-null pointer to a Bech32 Address +/// \param rhs right non-null pointer to a Bech32 Address +/// \return true if both address are equal, false otherwise TW_EXPORT_STATIC_METHOD bool TWSegwitAddressEqual(struct TWSegwitAddress *_Nonnull lhs, struct TWSegwitAddress *_Nonnull rhs); /// Determines if the string is a valid Bech32 address. +/// +/// \param string Non-null pointer to a Bech32 address as a string +/// \return true if the string is a valid Bech32 address, false otherwise. TW_EXPORT_STATIC_METHOD bool TWSegwitAddressIsValidString(TWString *_Nonnull string); -/// Creates an address from a string representaion. +/// Creates an address from a string representation. +/// +/// \param string Non-null pointer to a Bech32 address as a string +/// \note should be deleted with \TWSegwitAddressDelete +/// \return Pointer to a Bech32 address if the string is a valid Bech32 address, null pointer otherwise TW_EXPORT_STATIC_METHOD struct TWSegwitAddress *_Nullable TWSegwitAddressCreateWithString(TWString *_Nonnull string); /// Creates a segwit-version-0 address from a public key and HRP prefix. /// Taproot (v>=1) is not supported by this method. +/// +/// \param hrp HRP of the utxo coin targeted +/// \param publicKey Non-null pointer to the public key of the targeted coin +/// \note should be deleted with \TWSegwitAddressDelete +/// \return Non-null pointer to the corresponding Segwit address TW_EXPORT_STATIC_METHOD struct TWSegwitAddress *_Nonnull TWSegwitAddressCreateWithPublicKey(enum TWHRP hrp, struct TWPublicKey *_Nonnull publicKey); +/// Delete the given Segwit address +/// +/// \param address Non-null pointer to a Segwit address TW_EXPORT_METHOD void TWSegwitAddressDelete(struct TWSegwitAddress *_Nonnull address); /// Returns the address string representation. +/// +/// \param address Non-null pointer to a Segwit Address +/// \return Non-null pointer to the segwit address string representation TW_EXPORT_PROPERTY TWString *_Nonnull TWSegwitAddressDescription(struct TWSegwitAddress *_Nonnull address); /// Returns the human-readable part. +/// +/// \param address Non-null pointer to a Segwit Address +/// \return the HRP part of the given address TW_EXPORT_PROPERTY enum TWHRP TWSegwitAddressHRP(struct TWSegwitAddress *_Nonnull address); /// Returns the human-readable part. +/// +/// \param address Non-null pointer to a Segwit Address +/// \return returns the witness version of the given segwit address TW_EXPORT_PROPERTY int TWSegwitAddressWitnessVersion(struct TWSegwitAddress *_Nonnull address); /// Returns the witness program +/// +/// \param address Non-null pointer to a Segwit Address +/// \return returns the witness data of the given segwit address as a non-null pointer block of data TW_EXPORT_PROPERTY TWData *_Nonnull TWSegwitAddressWitnessProgram(struct TWSegwitAddress *_Nonnull address); diff --git a/include/TrustWalletCore/TWSolanaAddress.h b/include/TrustWalletCore/TWSolanaAddress.h index 76f7fe863e7..b8a372155e6 100644 --- a/include/TrustWalletCore/TWSolanaAddress.h +++ b/include/TrustWalletCore/TWSolanaAddress.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,21 +11,36 @@ TW_EXTERN_C_BEGIN +/// Solana address helper functions TW_EXPORT_CLASS struct TWSolanaAddress; -/// Creates an address from a string representaion. +/// Creates an address from a string representation. +/// +/// \param string Non-null pointer to a solana address string +/// \note Should be deleted with \TWSolanaAddressDelete +/// \return Non-null pointer to a Solana address data structure TW_EXPORT_STATIC_METHOD struct TWSolanaAddress* _Nullable TWSolanaAddressCreateWithString(TWString* _Nonnull string); +/// Delete the given Solana address +/// +/// \param address Non-null pointer to a Solana Address TW_EXPORT_METHOD void TWSolanaAddressDelete(struct TWSolanaAddress* _Nonnull address); /// Derive default token address for token +/// +/// \param address Non-null pointer to a Solana Address +/// \param tokenMintAddress Non-null pointer to a token mint address as a string +/// \return Null pointer if the Default token address for a token is not found, valid pointer otherwise TW_EXPORT_METHOD TWString* _Nullable TWSolanaAddressDefaultTokenAddress(struct TWSolanaAddress* _Nonnull address, TWString* _Nonnull tokenMintAddress); /// Returns the address string representation. +/// +/// \param address Non-null pointer to a Solana Address +/// \return Non-null pointer to the Solana address string representation TW_EXPORT_PROPERTY TWString *_Nonnull TWSolanaAddressDescription(struct TWSolanaAddress *_Nonnull address); diff --git a/include/TrustWalletCore/TWStellarMemoType.h b/include/TrustWalletCore/TWStellarMemoType.h index 45f9c629206..ef3f42702e4 100644 --- a/include/TrustWalletCore/TWStellarMemoType.h +++ b/include/TrustWalletCore/TWStellarMemoType.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,6 +10,7 @@ TW_EXTERN_C_BEGIN +/// Stellar memo type. TW_EXPORT_ENUM(uint32_t) enum TWStellarMemoType { TWStellarMemoTypeNone = 0, diff --git a/include/TrustWalletCore/TWStellarPassphrase.h b/include/TrustWalletCore/TWStellarPassphrase.h index 630adf3ef83..4854a4d3977 100644 --- a/include/TrustWalletCore/TWStellarPassphrase.h +++ b/include/TrustWalletCore/TWStellarPassphrase.h @@ -10,6 +10,7 @@ TW_EXTERN_C_BEGIN +/// Stellar network passphrase string. TW_EXPORT_ENUM() enum TWStellarPassphrase { TWStellarPassphraseStellar /* "Public Global Stellar Network ; September 2015" */, diff --git a/include/TrustWalletCore/TWStellarVersionByte.h b/include/TrustWalletCore/TWStellarVersionByte.h index b694c80b6bb..4439d1a555a 100644 --- a/include/TrustWalletCore/TWStellarVersionByte.h +++ b/include/TrustWalletCore/TWStellarVersionByte.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,11 +10,12 @@ TW_EXTERN_C_BEGIN +/// Stellar address version byte. TW_EXPORT_ENUM(uint16_t) enum TWStellarVersionByte { - TWStellarVersionByteAccountID = 0x30, // G - TWStellarVersionByteSeed = 0xc0, // S - TWStellarVersionBytePreAuthTX = 0xc8, // T + TWStellarVersionByteAccountID = 0x30, // G + TWStellarVersionByteSeed = 0xc0, // S + TWStellarVersionBytePreAuthTX = 0xc8, // T TWStellarVersionByteSHA256Hash = 0x118, // X }; diff --git a/include/TrustWalletCore/TWStoredKey.h b/include/TrustWalletCore/TWStoredKey.h index 7b23bf0ef50..02bd0ae4dad 100644 --- a/include/TrustWalletCore/TWStoredKey.h +++ b/include/TrustWalletCore/TWStoredKey.h @@ -9,11 +9,11 @@ #include "TWBase.h" #include "TWCoinType.h" #include "TWData.h" +#include "TWDerivation.h" #include "TWHDWallet.h" #include "TWPrivateKey.h" -#include "TWString.h" #include "TWStoredKeyEncryptionLevel.h" -#include "TWDerivation.h" +#include "TWString.h" TW_EXTERN_C_BEGIN @@ -21,114 +21,239 @@ TW_EXTERN_C_BEGIN TW_EXPORT_CLASS struct TWStoredKey; -/// Loads a key from a file. Returned object needs to be deleted. +/// Loads a key from a file. +/// +/// \param path filepath to the key as a non-null string +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return Nullptr if the key can't be load, the stored key otherwise TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nullable TWStoredKeyLoad(TWString* _Nonnull path); -/// Imports a private key. Returned object needs to be deleted. +/// Imports a private key. +/// +/// \param privateKey Non-null Block of data private key +/// \param name The name of the stored key to import as a non-null string +/// \param password Non-null block of data, password of the stored key +/// \param coin the coin type +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return Nullptr if the key can't be imported, the stored key otherwise TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKey(TWData* _Nonnull privateKey, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin); -/// Imports an HD wallet. Returned object needs to be deleted. +/// Imports an HD wallet. +/// +/// \param mnemonic Non-null bip39 mnemonic +/// \param name The name of the stored key to import as a non-null string +/// \param password Non-null block of data, password of the stored key +/// \param coin the coin type +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return Nullptr if the key can't be imported, the stored key otherwise TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nullable TWStoredKeyImportHDWallet(TWString* _Nonnull mnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin); -/// Imports a key from JSON. Returned object needs to be deleted. +/// Imports a key from JSON. +/// +/// \param json Json stored key import format as a non-null block of data +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return Nullptr if the key can't be imported, the stored key otherwise TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nullable TWStoredKeyImportJSON(TWData* _Nonnull json); /// Creates a new key, with given encryption strength level. Returned object needs to be deleted. +/// +/// \param name The name of the key to be stored +/// \param password Non-null block of data, password of the stored key +/// \param encryptionLevel The level of encryption, see \TWStoredKeyEncryptionLevel +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return The stored key as a non-null pointer TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nonnull TWStoredKeyCreateLevel(TWString* _Nonnull name, TWData* _Nonnull password, enum TWStoredKeyEncryptionLevel encryptionLevel); -/// DEPRECATED, use TWStoredKeyCreateLevel. Creates a new key. Returned object needs to be deleted. -TW_EXPORT_STATIC_METHOD -struct TWStoredKey* _Nonnull TWStoredKeyCreate(TWString* _Nonnull name, TWData* _Nonnull password); - +/// Creates a new key. +/// +/// \deprecated use TWStoredKeyCreateLevel. +/// \param name The name of the key to be stored +/// \param password Non-null block of data, password of the stored key +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return The stored key as a non-null pointer +TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nonnull TWStoredKeyCreate(TWString* _Nonnull name, TWData* _Nonnull password); + +/// Delete a stored key +/// +/// \param key The key to be deleted TW_EXPORT_METHOD void TWStoredKeyDelete(struct TWStoredKey* _Nonnull key); -/// Stored key unique identifier. Returned object needs to be deleted. +/// Stored key unique identifier. +/// +/// \param key Non-null pointer to a stored key +/// \note Returned object needs to be deleted with \TWStringDelete +/// \return The stored key unique identifier if it's found, null pointer otherwise. TW_EXPORT_PROPERTY TWString* _Nullable TWStoredKeyIdentifier(struct TWStoredKey* _Nonnull key); -/// Stored key namer. Returned object needs to be deleted. +/// Stored key namer. +/// +/// \param key Non-null pointer to a stored key +/// \note Returned object needs to be deleted with \TWStringDelete +/// \return The stored key name as a non-null string pointer. TW_EXPORT_PROPERTY TWString* _Nonnull TWStoredKeyName(struct TWStoredKey* _Nonnull key); /// Whether this key is a mnemonic phrase for a HD wallet. +/// +/// \param key Non-null pointer to a stored key +/// \return true if the given stored key is a mnemonic, false otherwise TW_EXPORT_PROPERTY bool TWStoredKeyIsMnemonic(struct TWStoredKey* _Nonnull key); /// The number of accounts. +/// +/// \param key Non-null pointer to a stored key +/// \return the number of accounts associated to the given stored key TW_EXPORT_PROPERTY size_t TWStoredKeyAccountCount(struct TWStoredKey* _Nonnull key); -/// Returns the account at a given index. Returned object needs to be deleted. +/// Returns the account at a given index. +/// +/// \param key Non-null pointer to a stored key +/// \param index the account index to be retrieved +/// \note Returned object needs to be deleted with \TWAccountDelete +/// \return Null pointer if the associated account is not found, pointer to the account otherwise. TW_EXPORT_METHOD struct TWAccount* _Nullable TWStoredKeyAccount(struct TWStoredKey* _Nonnull key, size_t index); -/// Returns the account for a specific coin, creating it if necessary. Returned object needs to be deleted. +/// Returns the account for a specific coin, creating it if necessary. +/// +/// \param key Non-null pointer to a stored key +/// \param coin The coin type +/// \param wallet The associated HD wallet, can be null. +/// \note Returned object needs to be deleted with \TWAccountDelete +/// \return Null pointer if the associated account is not found/not created, pointer to the account otherwise. TW_EXPORT_METHOD struct TWAccount* _Nullable TWStoredKeyAccountForCoin(struct TWStoredKey* _Nonnull key, enum TWCoinType coin, struct TWHDWallet* _Nullable wallet); -/// Returns the account for a specific coin + derivation, creating it if necessary. Returned object needs to be deleted. +/// Returns the account for a specific coin + derivation, creating it if necessary. +/// +/// \param key Non-null pointer to a stored key +/// \param coin The coin type +/// \param derivation The derivation for the given coin +/// \param wallet the associated HD wallet, can be null. +/// \note Returned object needs to be deleted with \TWAccountDelete +/// \return Null pointer if the associated account is not found/not created, pointer to the account otherwise. TW_EXPORT_METHOD struct TWAccount* _Nullable TWStoredKeyAccountForCoinDerivation(struct TWStoredKey* _Nonnull key, enum TWCoinType coin, enum TWDerivation derivation, struct TWHDWallet* _Nullable wallet); -/// Adds a new account, using given derivation (usually TWDerivationDefault) and derivation path (usually matches path from derivation, but custom possible). +/// Adds a new account, using given derivation (usually TWDerivationDefault) +/// and derivation path (usually matches path from derivation, but custom possible). +/// +/// \param key Non-null pointer to a stored key +/// \param address Non-null pointer to the address of the coin for this account +/// \param coin coin type +/// \param derivation derivation of the given coin type +/// \param derivationPath HD bip44 derivation path of the given coin +/// \param publicKey Non-null public key of the given coin/address +/// \param extendedPublicKey Non-null extended public key of the given coin/address TW_EXPORT_METHOD void TWStoredKeyAddAccountDerivation(struct TWStoredKey* _Nonnull key, TWString* _Nonnull address, enum TWCoinType coin, enum TWDerivation derivation, TWString* _Nonnull derivationPath, TWString* _Nonnull publicKey, TWString* _Nonnull extendedPublicKey); -/// [Deprecated] Use TWStoredKeyAddAccountDerivation (with TWDerivationDefault) instead. /// Adds a new account, using given derivation path. +/// +/// \deprecated Use TWStoredKeyAddAccountDerivation (with TWDerivationDefault) instead. +/// \param key Non-null pointer to a stored key +/// \param address Non-null pointer to the address of the coin for this account +/// \param coin coin type +/// \param derivationPath HD bip44 derivation path of the given coin +/// \param publicKey Non-null public key of the given coin/address +/// \param extendedPublicKey Non-null extended public key of the given coin/address TW_EXPORT_METHOD void TWStoredKeyAddAccount(struct TWStoredKey* _Nonnull key, TWString* _Nonnull address, enum TWCoinType coin, TWString* _Nonnull derivationPath, TWString* _Nonnull publicKey, TWString* _Nonnull extendedPublicKey); /// Remove the account for a specific coin +/// +/// \param key Non-null pointer to a stored key +/// \param coin Account coin type to be removed TW_EXPORT_METHOD void TWStoredKeyRemoveAccountForCoin(struct TWStoredKey* _Nonnull key, enum TWCoinType coin); /// Remove the account for a specific coin with the given derivation. +/// +/// \param key Non-null pointer to a stored key +/// \param coin Account coin type to be removed +/// \param derivation The derivation of the given coin type TW_EXPORT_METHOD void TWStoredKeyRemoveAccountForCoinDerivation(struct TWStoredKey* _Nonnull key, enum TWCoinType coin, enum TWDerivation derivation); /// Remove the account for a specific coin with the given derivation path. +/// +/// \param key Non-null pointer to a stored key +/// \param coin Account coin type to be removed +/// \param derivationPath The derivation path (bip44) of the given coin type TW_EXPORT_METHOD void TWStoredKeyRemoveAccountForCoinDerivationPath(struct TWStoredKey* _Nonnull key, enum TWCoinType coin, TWString* _Nonnull derivationPath); /// Saves the key to a file. +/// +/// \param key Non-null pointer to a stored key +/// \param path Non-null string filepath where the key will be saved +/// \return true if the key was successfully stored in the given filepath file, false otherwise TW_EXPORT_METHOD bool TWStoredKeyStore(struct TWStoredKey* _Nonnull key, TWString* _Nonnull path); /// Decrypts the private key. +/// +/// \param key Non-null pointer to a stored key +/// \param password Non-null block of data, password of the stored key +/// \return Decrypted private key as a block of data if success, null pointer otherwise TW_EXPORT_METHOD TWData* _Nullable TWStoredKeyDecryptPrivateKey(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password); /// Decrypts the mnemonic phrase. +/// +/// \param key Non-null pointer to a stored key +/// \param password Non-null block of data, password of the stored key +/// \return Bip39 decrypted mnemonic if success, null pointer otherwise TW_EXPORT_METHOD TWString* _Nullable TWStoredKeyDecryptMnemonic(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password); /// Returns the private key for a specific coin. Returned object needs to be deleted. +/// +/// \param key Non-null pointer to a stored key +/// \param coin Account coin type to be queried +/// \note Returned object needs to be deleted with \TWPrivateKeyDelete +/// \return Null pointer on failure, pointer to the private key otherwise TW_EXPORT_METHOD struct TWPrivateKey* _Nullable TWStoredKeyPrivateKey(struct TWStoredKey* _Nonnull key, enum TWCoinType coin, TWData* _Nonnull password); /// Decrypts and returns the HD Wallet for mnemonic phrase keys. Returned object needs to be deleted. +/// +/// \param key Non-null pointer to a stored key +/// \param password Non-null block of data, password of the stored key +/// \note Returned object needs to be deleted with \TWHDWalletDelete +/// \return Null pointer on failure, pointer to the HDWallet otherwise TW_EXPORT_METHOD struct TWHDWallet* _Nullable TWStoredKeyWallet(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password); /// Exports the key as JSON +/// +/// \param key Non-null pointer to a stored key +/// \return Null pointer on failure, pointer to a block of data containing the json otherwise TW_EXPORT_METHOD TWData* _Nullable TWStoredKeyExportJSON(struct TWStoredKey* _Nonnull key); /// Fills in empty and invalid addresses. -/// /// This method needs the encryption password to re-derive addresses from private keys. -/// @returns `false` if the password is incorrect. +/// +/// \param key Non-null pointer to a stored key +/// \param password Non-null block of data, password of the stored key +/// \return `false` if the password is incorrect, true otherwise. TW_EXPORT_METHOD bool TWStoredKeyFixAddresses(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password); /// Retrieve stored key encoding parameters, as JSON string. +/// +/// \param key Non-null pointer to a stored key +/// \return Null pointer on failure, encoding parameter as a json string otherwise. TW_EXPORT_PROPERTY TWString* _Nullable TWStoredKeyEncryptionParameters(struct TWStoredKey* _Nonnull key); diff --git a/include/TrustWalletCore/TWStoredKeyEncryptionLevel.h b/include/TrustWalletCore/TWStoredKeyEncryptionLevel.h index aa75da13771..6b0b79476ea 100644 --- a/include/TrustWalletCore/TWStoredKeyEncryptionLevel.h +++ b/include/TrustWalletCore/TWStoredKeyEncryptionLevel.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/include/TrustWalletCore/TWString.h b/include/TrustWalletCore/TWString.h index db8468f42f4..f02eef86ae3 100644 --- a/include/TrustWalletCore/TWString.h +++ b/include/TrustWalletCore/TWString.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -14,33 +14,52 @@ typedef const void TWData; /// Defines a resizable string. /// -/// The implementantion of these methods should be language-specific to minimize translation overhead. For instance it -/// should be a `jstring` for Java and an `NSString` for Swift. -/// Create allocates memory, the delete call should be called at the end to release memory. +/// The implementantion of these methods should be language-specific to minimize translation +/// overhead. For instance it should be a `jstring` for Java and an `NSString` for Swift. Create +/// allocates memory, the delete call should be called at the end to release memory. typedef const void TWString; -/// Creates a string from a null-terminated UTF8 byte array. It must be deleted at the end. -TWString *_Nonnull TWStringCreateWithUTF8Bytes(const char *_Nonnull bytes) TW_VISIBILITY_DEFAULT; +/// Creates a TWString from a null-terminated UTF8 byte array. It must be deleted at the end. +/// +/// \param bytes a null-terminated UTF8 byte array. +TWString* _Nonnull TWStringCreateWithUTF8Bytes(const char* _Nonnull bytes) TW_VISIBILITY_DEFAULT; -/// Creates a string from a raw byte array and size. -TWString *_Nonnull TWStringCreateWithRawBytes(const uint8_t *_Nonnull bytes, size_t size) TW_VISIBILITY_DEFAULT; +/// Creates a string from a raw byte array and size. It must be deleted at the end. +/// +/// \param bytes a raw byte array. +/// \param size the size of the byte array. +TWString* _Nonnull TWStringCreateWithRawBytes(const uint8_t* _Nonnull bytes, size_t size) TW_VISIBILITY_DEFAULT; /// Creates a hexadecimal string from a block of data. It must be deleted at the end. -TWString *_Nonnull TWStringCreateWithHexData(TWData *_Nonnull data) TW_VISIBILITY_DEFAULT; +/// +/// \param data a block of data. +TWString* _Nonnull TWStringCreateWithHexData(TWData* _Nonnull data) TW_VISIBILITY_DEFAULT; /// Returns the string size in bytes. -size_t TWStringSize(TWString *_Nonnull string) TW_VISIBILITY_DEFAULT; +/// +/// \param string a TWString pointer. +size_t TWStringSize(TWString* _Nonnull string) TW_VISIBILITY_DEFAULT; /// Returns the byte at the provided index. -char TWStringGet(TWString *_Nonnull string, size_t index) TW_VISIBILITY_DEFAULT; +/// +/// \param string a TWString pointer. +/// \param index the index of the byte. +char TWStringGet(TWString* _Nonnull string, size_t index) TW_VISIBILITY_DEFAULT; /// Returns the raw pointer to the string's UTF8 bytes (null-terminated). -const char *_Nonnull TWStringUTF8Bytes(TWString *_Nonnull string) TW_VISIBILITY_DEFAULT; +/// +/// \param string a TWString pointer. +const char* _Nonnull TWStringUTF8Bytes(TWString* _Nonnull string) TW_VISIBILITY_DEFAULT; -/// Deletes a string created with a `TWStringCreate*` method. After delete it must not be used (can segfault)! -void TWStringDelete(TWString *_Nonnull string) TW_VISIBILITY_DEFAULT; +/// Deletes a string created with a `TWStringCreate*` method and frees the memory. +/// +/// \param string a TWString pointer. +void TWStringDelete(TWString* _Nonnull string) TW_VISIBILITY_DEFAULT; /// Determines whether two string blocks are equal. -bool TWStringEqual(TWString *_Nonnull lhs, TWString *_Nonnull rhs) TW_VISIBILITY_DEFAULT; +/// +/// \param lhs a TWString pointer. +/// \param rhs another TWString pointer. +bool TWStringEqual(TWString* _Nonnull lhs, TWString* _Nonnull rhs) TW_VISIBILITY_DEFAULT; TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWTHORChainSwap.h b/include/TrustWalletCore/TWTHORChainSwap.h index 45a54b94cd2..27708cec96f 100644 --- a/include/TrustWalletCore/TWTHORChainSwap.h +++ b/include/TrustWalletCore/TWTHORChainSwap.h @@ -11,10 +11,14 @@ TW_EXTERN_C_BEGIN +/// THORChain swap functions TW_EXPORT_STRUCT struct TWTHORChainSwap; -/// Build a THORChainSwap transaction input. Input is SwapInput protobuf, return is SwapOutput. +/// Builds a THORChainSwap transaction input. +/// +/// \param input The serialized data of SwapInput. +/// \return The serialized data of SwapOutput. TW_EXPORT_STATIC_METHOD TWData *_Nonnull TWTHORChainSwapBuildSwap(TWData *_Nonnull input); diff --git a/include/TrustWalletCore/TWTransactionCompiler.h b/include/TrustWalletCore/TWTransactionCompiler.h index 519424ccade..93e68c65cce 100644 --- a/include/TrustWalletCore/TWTransactionCompiler.h +++ b/include/TrustWalletCore/TWTransactionCompiler.h @@ -18,25 +18,46 @@ TW_EXTERN_C_BEGIN TW_EXPORT_STRUCT struct TWTransactionCompiler; -/// Build a coin-specific SigningInput protobuf transaction input, from simple transaction parameters -/// - amount: decimal number as string -/// - asset: optional asset name, like "BNB" -/// - memo: optional memo -/// - chainId: optional chainId to override default +/// Builds a coin-specific SigningInput (proto object) from a simple transaction. +/// +/// \param coin coin type. +/// \param from sender of the transaction. +/// \param to receiver of the transaction. +/// \param amount transaction amount in string +/// \param asset optional asset name, like "BNB" +/// \param memo optional memo +/// \param chainId optional chainId to override default +/// \return serialized data of the SigningInput proto object. TW_EXPORT_STATIC_METHOD -TWData *_Nonnull TWTransactionCompilerBuildInput(enum TWCoinType coinType, TWString *_Nonnull from, TWString *_Nonnull to, TWString *_Nonnull amount, TWString *_Nonnull asset, TWString *_Nonnull memo, TWString *_Nonnull chainId); - -/// Obtain pre-signing hashes of a transaction. -/// It will return a proto object named `PreSigningOutput` which will include hash. -/// We provide a default `PreSigningOutput` in TransactionCompiler.proto. +TWData* _Nonnull TWTransactionCompilerBuildInput(enum TWCoinType coinType, TWString* _Nonnull from, + TWString* _Nonnull to, TWString* _Nonnull amount, + TWString* _Nonnull asset, TWString* _Nonnull memo, + TWString* _Nonnull chainId); + +/// Obtains pre-signing hashes of a transaction. +/// +/// We provide a default `PreSigningOutput` in TransactionCompiler.proto. /// For some special coins, such as bitcoin, we will create a custom `PreSigningOutput` object in its proto file. +/// \param coin coin type. +/// \param txInputData The serialized data of a signing input +/// \return serialized data of a proto object `PreSigningOutput` includes hash. TW_EXPORT_STATIC_METHOD -TWData *_Nonnull TWTransactionCompilerPreImageHashes(enum TWCoinType coinType, TWData *_Nonnull txInputData); - -/// Compile a complete transation with one or more external signatures, put together from transaction input and provided public keys and signatures. -/// The signatures must match the hashes returned by TWTransactionCompilerPreImageHashes, in the same order. -/// The publicKeyHash attached to the hashes enable identifying the private key needed for signing the hash. +TWData* _Nonnull TWTransactionCompilerPreImageHashes(enum TWCoinType coinType, + TWData* _Nonnull txInputData); + +/// Compiles a complete transation with one or more external signatures. +/// +/// Puts together from transaction input and provided public keys and signatures. The signatures must match the hashes +/// returned by TWTransactionCompilerPreImageHashes, in the same order. The publicKeyHash attached +/// to the hashes enable identifying the private key needed for signing the hash. +/// \param coin coin type. +/// \param txInputData The serialized data of a signing input. +/// \param signatures signatures to compile, using TWDataVector. +/// \param publicKeys public keys for signers to match private keys, using TWDataVector. +/// \return serialized data of a proto object `SigningOutput`. TW_EXPORT_STATIC_METHOD -TWData *_Nonnull TWTransactionCompilerCompileWithSignatures(enum TWCoinType coinType, TWData *_Nonnull txInputData, const struct TWDataVector *_Nonnull signatures, const struct TWDataVector *_Nonnull publicKeys); +TWData* _Nonnull TWTransactionCompilerCompileWithSignatures( + enum TWCoinType coinType, TWData* _Nonnull txInputData, + const struct TWDataVector* _Nonnull signatures, const struct TWDataVector* _Nonnull publicKeys); TW_EXTERN_C_END diff --git a/src/BinaryCoding.h b/src/BinaryCoding.h index 1b7077687c3..971189f2af0 100644 --- a/src/BinaryCoding.h +++ b/src/BinaryCoding.h @@ -62,12 +62,12 @@ uint8_t varIntSize(uint64_t value); /// being encoded. It produces fewer bytes for smaller numbers as opposed to a /// fixed-size encoding. Little endian byte order is used. /// -/// @returns the number of bytes written. +/// \returns the number of bytes written. uint8_t encodeVarInt(uint64_t size, std::vector& data); /// Decodes an integer as a variable-length integer. See encodeVarInt(). /// -/// @returns a tuple with a success indicator and the decoded integer. +/// \returns a tuple with a success indicator and the decoded integer. std::tuple decodeVarInt(const Data& in, size_t& indexInOut); /// Encodes a 16-bit big-endian value into the provided buffer. @@ -109,7 +109,7 @@ uint64_t decode64BE(const uint8_t* _Nonnull src); void encodeString(const std::string& str, std::vector& data); /// Decodes an ASCII string prefixed by its length (varInt) -/// @returns a tuple with a success indicator and the decoded string. +/// \returns a tuple with a success indicator and the decoded string. std::tuple decodeString(const Data& in, size_t& indexInOut); } // namespace TW diff --git a/src/DerivationPath.h b/src/DerivationPath.h index be6b6602d07..c18d90069ac 100644 --- a/src/DerivationPath.h +++ b/src/DerivationPath.h @@ -112,7 +112,7 @@ struct DerivationPath { /// Creates a derivation path with a string description like `m/10/0/2'/3` /// - /// @throws std::invalid_argument if the string is not a valid derivation + /// \throws std::invalid_argument if the string is not a valid derivation /// path. explicit DerivationPath(const std::string& string); diff --git a/src/Ethereum/Signer.h b/src/Ethereum/Signer.h index fb13a9b36c3..29f88105c83 100644 --- a/src/Ethereum/Signer.h +++ b/src/Ethereum/Signer.h @@ -43,19 +43,19 @@ class Signer { /// Signs a hash with the given private key for the given chain identifier. /// - /// @returns the r, s, and v values of the transaction signature + /// \returns the r, s, and v values of the transaction signature static Signature sign(const PrivateKey& privateKey, const Data& hash, bool includeEip155, const uint256_t& chainID) noexcept; /// Break up the signature into the R, S, and V values. - /// @returns the r, s, and v values of the transaction signature + /// \returns the r, s, and v values of the transaction signature static Signature signatureDataToStruct(const Data& signature, bool includeEip155, const uint256_t& chainID) noexcept; /// Break up the signature into the R, S, and V values, with no replay protection. - /// @returns the r, s, and v values of the transaction signature + /// \returns the r, s, and v values of the transaction signature static Signature signatureDataToStructSimple(const Data& signature) noexcept; /// Break up the signature into the R, S, and V values, and include chainID in V for replay protection (Eip155) - /// @returns the r, s, and v values of the transaction signature + /// \returns the r, s, and v values of the transaction signature static Signature signatureDataToStructWithEip155(const uint256_t& chainID, const Data& signature) noexcept; }; diff --git a/src/FIO/Action.h b/src/FIO/Action.h index c79ef65a500..5390175400e 100644 --- a/src/FIO/Action.h +++ b/src/FIO/Action.h @@ -16,7 +16,7 @@ namespace TW::FIO { /// Encodes a value as a variable-length integer. -/// @returns the number of bytes written. +/// \returns the number of bytes written. uint8_t encodeVarInt(uint64_t num, Data& data); /// Encodes an ASCII string prefixed by the length (varInt) diff --git a/src/FIO/Encryption.h b/src/FIO/Encryption.h index ecc7106f8b8..659f099c7e1 100644 --- a/src/FIO/Encryption.h +++ b/src/FIO/Encryption.h @@ -13,28 +13,28 @@ namespace TW::FIO { /// Payload message encryption/decryption. -/// See also https://github.com/fioprotocol/fiojs/blob/master/src/encryption-check.ts +/// \see https://github.com/fioprotocol/fiojs/blob/master/src/encryption-check.ts class Encryption { public: /** * Provides AES-256-CBC encryption and message authentication. * The CBC cipher is used for good platform native compatability. - * @see https://security.stackexchange.com/a/63134 - * @see https://security.stackexchange.com/a/20493 - * @arg secret - Shared secret (64-bytes). - * @arg message - Plaintext message (arbitrary length). - * @arg iv - An unpredictable strong random value (16 bytes) is required + * \see https://security.stackexchange.com/a/63134 + * \see https://security.stackexchange.com/a/20493 + * \param secret - Shared secret (64-bytes). + * \param message - Plaintext message (arbitrary length). + * \param iv - An unpredictable strong random value (16 bytes) is required * and supplied by default. Unit tests may provide a static value to achieve predictable results. - * @throws {Error} invalid IV size + * \throws {Error} invalid IV size */ static Data checkEncrypt(const Data& secret, const Data& message, Data& iv); /** * Provides AES-256-CBC message authentication then decryption. - * @arg secret - Shared secret (64-bytes). - * @arg message - Ciphertext (from checkEncrypt()) - * @throws {Error} Message too short - * @throws {Error} Decrypt failed, HMAC mismatch + * \param secret - Shared secret (64-bytes). + * \param message - Ciphertext (from checkEncrypt()) + * \throws {Error} Message too short + * \throws {Error} Decrypt failed, HMAC mismatch */ static Data checkDecrypt(const Data& secret, const Data& message); diff --git a/src/Harmony/Signer.h b/src/Harmony/Signer.h index a4c80685d0f..b674b953549 100644 --- a/src/Harmony/Signer.h +++ b/src/Harmony/Signer.h @@ -62,13 +62,13 @@ class Signer { /// Signs a hash with the given private key for the given chain identifier. /// - /// @returns the r, s, and v values of the transaction signature + /// \returns the r, s, and v values of the transaction signature static std::tuple sign(const uint256_t &chainID, const PrivateKey &privateKey, const Data& hash) noexcept; /// R, S, and V values for the given chain identifier and signature. /// - /// @returns the r, s, and v values of the transaction signature + /// \returns the r, s, and v values of the transaction signature static std::tuple values(const uint256_t &chainID, const Data& signature) noexcept; diff --git a/src/Keystore/StoredKey.h b/src/Keystore/StoredKey.h index 790ba9206e8..ae76b5bf6a1 100644 --- a/src/Keystore/StoredKey.h +++ b/src/Keystore/StoredKey.h @@ -111,26 +111,26 @@ class StoredKey { /// Returns the private key for a specific coin, using default derivation, creating an account if necessary. /// - /// @throws std::invalid_argument if this key is of a type other than + /// \throws std::invalid_argument if this key is of a type other than /// `mnemonicPhrase` and a coin other than the default is requested. const PrivateKey privateKey(TWCoinType coin, const Data& password); /// Returns the private key for a specific coin, creating an account if necessary. /// - /// @throws std::invalid_argument if this key is of a type other than + /// \throws std::invalid_argument if this key is of a type other than /// `mnemonicPhrase` and a coin other than the default is requested. const PrivateKey privateKey(TWCoinType coin, TWDerivation derivation, const Data& password); /// Loads and decrypts a stored key from a file. /// - /// @param path file path to load from. - /// @returns decrypted key. - /// @throws DecryptionError + /// \param path file path to load from. + /// \returns decrypted key. + /// \throws DecryptionError static StoredKey load(const std::string& path); /// Stores the key into an encrypted file. /// - /// @param path file path to store in. + /// \param path file path to store in. void store(const std::string& path); /// Initializes `StoredKey` with a JSON object. diff --git a/src/PublicKey.cpp b/src/PublicKey.cpp index b1b1e40cc8d..10c2e59d88a 100644 --- a/src/PublicKey.cpp +++ b/src/PublicKey.cpp @@ -47,7 +47,7 @@ bool PublicKey::isValid(const Data& data, enum TWPublicKeyType type) { /// Initializes a public key with a collection of bytes. /// -/// @throws std::invalid_argument if the data is not a valid public key. +/// \throws std::invalid_argument if the data is not a valid public key. PublicKey::PublicKey(const Data& data, enum TWPublicKeyType type) : type(type) { if (!isValid(data, type)) { diff --git a/src/PublicKey.h b/src/PublicKey.h index 705469c0b9d..3b4691cac35 100644 --- a/src/PublicKey.h +++ b/src/PublicKey.h @@ -45,7 +45,7 @@ class PublicKey { /// Initializes a public key with a collection of bytes. /// - /// @throws std::invalid_argument if the data is not a valid public key. + /// \throws std::invalid_argument if the data is not a valid public key. explicit PublicKey(const Data& data, enum TWPublicKeyType type); /// Determines if this is a compressed public key. From eb5f240696f036fc4f03b1a7a5b3c562771fdbd8 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 26 Aug 2022 04:06:44 +0200 Subject: [PATCH 062/497] [Cosmos]: Authz stake/delegate (#2510) * feat(cosmos_authz): start cosmos authz * feat(cosmos_authz): add staking_authz.proto * feat(cosmos_authz): add auth revoke message * feat(cosmos_authz): finalize test for revoke * feat(cosmos_authz): finalize test for auth grant * feat(cosmos_authz): type url agnostic * feat(cosmos_authz): use switch case for future addition * feat(cosmos_authz): remove prefix Authorization Type --- .../cosmos/TestCosmosTransactions.kt | 111 +++++++++++++++++- src/Cosmos/Protobuf/authz_tx.proto | 32 +++++ src/Cosmos/ProtobufSerialization.cpp | 38 +++++- src/proto/Cosmos.proto | 59 +++++++++- swift/Tests/Blockchains/CosmosTests.swift | 72 ++++++++++++ tests/Cosmos/ProtobufTests.cpp | 4 +- tests/Cosmos/StakingTests.cpp | 75 +++++++++++- tests/interface/TWTestUtilities.h | 2 +- 8 files changed, 381 insertions(+), 12 deletions(-) create mode 100644 src/Cosmos/Protobuf/authz_tx.proto diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cosmos/TestCosmosTransactions.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cosmos/TestCosmosTransactions.kt index a81bf62e008..7267138e1da 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cosmos/TestCosmosTransactions.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cosmos/TestCosmosTransactions.kt @@ -19,6 +19,104 @@ class TestCosmosTransactions { System.loadLibrary("TrustWalletCore") } + @Test + fun testAuthStakingTransaction() { + val key = + PrivateKey("c7764249cdf77f8f1d840fa8af431579e5e41cf1af937e1e23afa22f3f4f0ccc".toHexByteArray()) + + val stakeAuth = Cosmos.Message.StakeAuthorization.newBuilder().apply { + allowList = Cosmos.Message.StakeAuthorization.Validators.newBuilder().apply { + addAddress("cosmosvaloper1gjtvly9lel6zskvwtvlg5vhwpu9c9waw7sxzwx") + }.build() + authorizationType = Cosmos.Message.AuthorizationType.DELEGATE + }.build() + + val authStakingMsg = Cosmos.Message.AuthGrant.newBuilder().apply { + grantee = "cosmos1fs7lu28hx5m9akm7rp0c2422cn8r2f7gurujhf" + granter = "cosmos13k0q0l7lg2kr32kvt7ly236ppldy8v9dzwh3gd" + grantStake = stakeAuth + expiration = 1692309600 + }.build() + + val message = Cosmos.Message.newBuilder().apply { + authGrant = authStakingMsg + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "2418" + denom = "uatom" + }.build() + + val cosmosFee = Cosmos.Fee.newBuilder().apply { + gas = 96681 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = SigningMode.Protobuf + accountNumber = 1290826 + chainId = "cosmoshub-4" + memo = "" + sequence = 5 + fee = cosmosFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, COSMOS, SigningOutput.parser()) + + assertEquals( + output.serialized, + "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CvgBCvUBCh4vY29zbW9zLmF1dGh6LnYxYmV0YTEuTXNnR3JhbnQS0gEKLWNvc21vczEzazBxMGw3bGcya3IzMmt2dDdseTIzNnBwbGR5OHY5ZHp3aDNnZBItY29zbW9zMWZzN2x1MjhoeDVtOWFrbTdycDBjMjQyMmNuOHIyZjdndXJ1amhmGnIKaAoqL2Nvc21vcy5zdGFraW5nLnYxYmV0YTEuU3Rha2VBdXRob3JpemF0aW9uEjoSNgo0Y29zbW9zdmFsb3BlcjFnanR2bHk5bGVsNnpza3Z3dHZsZzV2aHdwdTljOXdhdzdzeHp3eCABEgYI4LD6pgYSZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA/fcQw1hCVUx904t+kCXTiiziaLIY8lyssu1ENfzaN1KEgQKAggBGAUSEwoNCgV1YXRvbRIEMjQxOBCp8wUaQIFyfuijGKf87Hz61ZqxasfLI1PZnNge4RDq/tRyB/tZI6p80iGRqHecoV6+84EQkc9GTlNRQOSlApRCsivT9XI=\"}" + ) + assertEquals(output.error, "") + } + + @Test + fun testRemoveAuthStakingTransaction() { + val key = + PrivateKey("c7764249cdf77f8f1d840fa8af431579e5e41cf1af937e1e23afa22f3f4f0ccc".toHexByteArray()) + + val removeAuthStakingMsg = Cosmos.Message.AuthRevoke.newBuilder().apply { + grantee = "cosmos1fs7lu28hx5m9akm7rp0c2422cn8r2f7gurujhf" + granter = "cosmos13k0q0l7lg2kr32kvt7ly236ppldy8v9dzwh3gd" + msgTypeUrl = "/cosmos.staking.v1beta1.MsgDelegate" + }.build() + + val message = Cosmos.Message.newBuilder().apply { + authRevoke = removeAuthStakingMsg + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "2194" + denom = "uatom" + }.build() + + val cosmosFee = Cosmos.Fee.newBuilder().apply { + gas = 87735 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = SigningMode.Protobuf + accountNumber = 1290826 + chainId = "cosmoshub-4" + memo = "" + sequence = 4 + fee = cosmosFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, COSMOS, SigningOutput.parser()) + + assertEquals( + output.serialized, + "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CqoBCqcBCh8vY29zbW9zLmF1dGh6LnYxYmV0YTEuTXNnUmV2b2tlEoMBCi1jb3Ntb3MxM2swcTBsN2xnMmtyMzJrdnQ3bHkyMzZwcGxkeTh2OWR6d2gzZ2QSLWNvc21vczFmczdsdTI4aHg1bTlha203cnAwYzI0MjJjbjhyMmY3Z3VydWpoZhojL2Nvc21vcy5zdGFraW5nLnYxYmV0YTEuTXNnRGVsZWdhdGUSZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA/fcQw1hCVUx904t+kCXTiiziaLIY8lyssu1ENfzaN1KEgQKAggBGAQSEwoNCgV1YXRvbRIEMjE5NBC3rQUaQI7K+W7MMBoD6FbFZxRBqs9VTjErztjWTy57+fvrLaTCIZ+eBs7CuaKqfUZdSN8otjubSHVTQID3k9DpPAX0yDo=\"}" + ) + assertEquals(output.error, "") + } + @Test fun testSigningTransaction() { val key = @@ -64,7 +162,10 @@ class TestCosmosTransactions { val output = AnySigner.sign(signingInput, COSMOS, SigningOutput.parser()) - assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CowBCokBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmkKLWNvc21vczFoc2s2anJ5eXFqZmhwNWRoYzU1dGM5anRja3lneDBlcGg2ZGQwMhItY29zbW9zMXp0NTBhenVwYW5xbGZhbTVhZmh2M2hleHd5dXRudWtlaDRjNTczGgkKBG11b24SATESZQpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3FEgQKAggBGAgSEQoLCgRtdW9uEgMyMDAQwJoMGkD54fQAFlekIAnE62hZYl0uQelh/HLv0oQpCciY5Dn8H1SZFuTsrGdu41PH1Uxa4woptCELi/8Ov9yzdeEFAC9H\"}") + assertEquals( + output.serialized, + "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CowBCokBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmkKLWNvc21vczFoc2s2anJ5eXFqZmhwNWRoYzU1dGM5anRja3lneDBlcGg2ZGQwMhItY29zbW9zMXp0NTBhenVwYW5xbGZhbTVhZmh2M2hleHd5dXRudWtlaDRjNTczGgkKBG11b24SATESZQpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3FEgQKAggBGAgSEQoLCgRtdW9uEgMyMDAQwJoMGkD54fQAFlekIAnE62hZYl0uQelh/HLv0oQpCciY5Dn8H1SZFuTsrGdu41PH1Uxa4woptCELi/8Ov9yzdeEFAC9H\"}" + ) assertEquals(output.error, "") } @@ -94,8 +195,12 @@ class TestCosmosTransactions { }] } """ - val key = "c9b0a273831931aa4a5f8d1a570d5021dda91d3319bd3819becdaabfb7b44e3b".toHexByteArray() + val key = + "c9b0a273831931aa4a5f8d1a570d5021dda91d3319bd3819becdaabfb7b44e3b".toHexByteArray() val result = AnySigner.signJSON(json, key, COSMOS.value()) - assertEquals(result, """{"mode":"block","tx":{"fee":{"amount":[{"amount":"5000","denom":"uatom"}],"gas":"200000"},"memo":"Testing","msg":[{"type":"cosmos-sdk/MsgSend","value":{"amount":[{"amount":"995000","denom":"uatom"}],"from_address":"cosmos1ufwv9ymhqaal6xz47n0jhzm2wf4empfqvjy575","to_address":"cosmos135qla4294zxarqhhgxsx0sw56yssa3z0f78pm0"}}],"signatures":[{"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"A6EsukEXB53GhohQVeDpxtkeH8KQIayd/Co/ApYRYkTm"},"signature":"ULEpUqNzoAnYEx2x22F3ANAiPXquAU9+mqLWoAA/ZOUGTMsdb6vryzsW6AKX2Kqj1pGNdrTcQ58Z09JPyjpgEA=="}]}}""") + assertEquals( + result, + """{"mode":"block","tx":{"fee":{"amount":[{"amount":"5000","denom":"uatom"}],"gas":"200000"},"memo":"Testing","msg":[{"type":"cosmos-sdk/MsgSend","value":{"amount":[{"amount":"995000","denom":"uatom"}],"from_address":"cosmos1ufwv9ymhqaal6xz47n0jhzm2wf4empfqvjy575","to_address":"cosmos135qla4294zxarqhhgxsx0sw56yssa3z0f78pm0"}}],"signatures":[{"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"A6EsukEXB53GhohQVeDpxtkeH8KQIayd/Co/ApYRYkTm"},"signature":"ULEpUqNzoAnYEx2x22F3ANAiPXquAU9+mqLWoAA/ZOUGTMsdb6vryzsW6AKX2Kqj1pGNdrTcQ58Z09JPyjpgEA=="}]}}""" + ) } } diff --git a/src/Cosmos/Protobuf/authz_tx.proto b/src/Cosmos/Protobuf/authz_tx.proto new file mode 100644 index 00000000000..b92c03bd3f8 --- /dev/null +++ b/src/Cosmos/Protobuf/authz_tx.proto @@ -0,0 +1,32 @@ +// Since: cosmos-sdk 0.43 +syntax = "proto3"; +package cosmos.authz.v1beta1; + +import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; + +// Grant gives permissions to execute +// the provide method with expiration time. +message Grant { + google.protobuf.Any authorization = 1; + // time when the grant will expire and will be pruned. If null, then the grant + // doesn't have a time expiration (other conditions in `authorization` + // may apply to invalidate the grant) + google.protobuf.Timestamp expiration = 2; +} + +// MsgGrant is a request type for Grant method. It declares authorization to the grantee +// on behalf of the granter with the provided expiration time. +message MsgGrant { + string granter = 1; + string grantee = 2; + Grant grant = 3; +} + +// MsgRevoke revokes any authorization with the provided sdk.Msg type on the +// granter's account with that has been granted to the grantee. +message MsgRevoke { + string granter = 1; + string grantee = 2; + string msg_type_url = 3; +} diff --git a/src/Cosmos/ProtobufSerialization.cpp b/src/Cosmos/ProtobufSerialization.cpp index 2b1a6709eaa..a59f64463c0 100644 --- a/src/Cosmos/ProtobufSerialization.cpp +++ b/src/Cosmos/ProtobufSerialization.cpp @@ -12,6 +12,7 @@ #include "Protobuf/cosmwasm_wasm_v1_tx.pb.h" #include "Protobuf/distribution_tx.pb.h" #include "Protobuf/staking_tx.pb.h" +#include "Protobuf/authz_tx.pb.h" #include "Protobuf/tx.pb.h" #include "Protobuf/crypto_secp256k1_keys.pb.h" #include "Protobuf/ibc_applications_transfer_tx.pb.h" @@ -207,7 +208,7 @@ google::protobuf::Any convertMessage(const Proto::Message& msg) { } case Proto::Message::kWasmExecuteContractGeneric: { - assert(msg.has_wasm_execute_contract_generic()); + assert(msg.has_wasm_execute_contract_generic()); const auto& wasmExecute = msg.wasm_execute_contract_generic(); auto msgExecute = cosmwasm::wasm::v1::MsgExecuteContract(); msgExecute.set_sender(wasmExecute.sender_address()); @@ -221,6 +222,39 @@ google::protobuf::Any convertMessage(const Proto::Message& msg) { return any; } + case Proto::Message::kAuthGrant: { + assert(msg.has_auth_grant()); + const auto& authGrant = msg.auth_grant(); + auto msgAuthGrant = cosmos::authz::v1beta1::MsgGrant(); + msgAuthGrant.set_grantee(authGrant.grantee()); + msgAuthGrant.set_granter(authGrant.granter()); + auto* mtAuth = msgAuthGrant.mutable_grant()->mutable_authorization(); + // There is multiple grant possibilities, but we add support staking/compounding only for now. + switch (authGrant.grant_type_case()) { + case Proto::Message_AuthGrant::kGrantStake: + mtAuth->PackFrom(authGrant.grant_stake(), ProtobufAnyNamespacePrefix); + mtAuth->set_type_url("/cosmos.staking.v1beta1.StakeAuthorization"); + break; + case Proto::Message_AuthGrant::GRANT_TYPE_NOT_SET: + break; + } + auto* mtExp = msgAuthGrant.mutable_grant()->mutable_expiration(); + mtExp->set_seconds(authGrant.expiration()); + any.PackFrom(msgAuthGrant, ProtobufAnyNamespacePrefix); + return any; + } + + case Proto::Message::kAuthRevoke: { + assert(msg.has_auth_revoke()); + const auto& authRevoke = msg.auth_revoke(); + auto msgAuthRevoke = cosmos::authz::v1beta1::MsgRevoke(); + msgAuthRevoke.set_granter(authRevoke.granter()); + msgAuthRevoke.set_grantee(authRevoke.grantee()); + msgAuthRevoke.set_msg_type_url(authRevoke.msg_type_url()); + any.PackFrom(msgAuthRevoke, ProtobufAnyNamespacePrefix); + return any; + } + default: throw std::invalid_argument(std::string("Message not supported ") + std::to_string(msg.message_oneof_case())); } @@ -331,7 +365,7 @@ static string broadcastMode(Proto::BroadcastMode mode) { } std::string buildProtoTxJson(const Proto::SigningInput& input, const std::string& serializedTx) { - const string serializedBase64 = Base64::encode(TW::data(serializedTx)); + const string serializedBase64 = Base64::encode(TW::data(serializedTx)); const json jsonSerialized = { {"tx_bytes", serializedBase64}, {"mode", broadcastMode(input.mode())} diff --git a/src/proto/Cosmos.proto b/src/proto/Cosmos.proto index 457bdef7c93..64401fac061 100644 --- a/src/proto/Cosmos.proto +++ b/src/proto/Cosmos.proto @@ -202,7 +202,62 @@ message Message { // The prepared serialized TxBody bytes body_bytes = 1; // The prepared serialized AuthInfo - bytes auth_info_bytes = 2; + bytes auth_info_bytes = 2; + } + + // StakeAuthorization defines authorization for delegate/undelegate/redelegate. + // + // Since: cosmos-sdk 0.43 + message StakeAuthorization { + // max_tokens specifies the maximum amount of tokens can be delegate to a validator. If it is + // empty, there is no spend limit and any amount of coins can be delegated. + Amount max_tokens = 1; + // validators is the oneof that represents either allow_list or deny_list + oneof validators { + // allow_list specifies list of validator addresses to whom grantee can delegate tokens on behalf of granter's + // account. + Validators allow_list = 2; + // deny_list specifies list of validator addresses to whom grantee can not delegate tokens. + Validators deny_list = 3; + } + // Validators defines list of validator addresses. + message Validators { + repeated string address = 1; + } + // authorization_type defines one of AuthorizationType. + AuthorizationType authorization_type = 4; + } + + // AuthorizationType defines the type of staking module authorization type + // + // Since: cosmos-sdk 0.43 + enum AuthorizationType { + // AUTHORIZATION_TYPE_UNSPECIFIED specifies an unknown authorization type + UNSPECIFIED = 0; + // AUTHORIZATION_TYPE_DELEGATE defines an authorization type for Msg/Delegate + DELEGATE = 1; + // AUTHORIZATION_TYPE_UNDELEGATE defines an authorization type for Msg/Undelegate + UNDELEGATE = 2; + // AUTHORIZATION_TYPE_REDELEGATE defines an authorization type for Msg/BeginRedelegate + REDELEGATE = 3; + } + + + // cosmos-sdk/MsgGrant + message AuthGrant { + string granter = 1; + string grantee = 2; + oneof grant_type { + StakeAuthorization grant_stake = 3; + } + int64 expiration = 4; + } + + // cosmos-sdk/MsgRevoke + message AuthRevoke { + string granter = 1; + string grantee = 2; + string msg_type_url = 3; } oneof message_oneof { @@ -221,6 +276,8 @@ message Message { WasmExecuteContractSend wasm_execute_contract_send_message = 13; WasmExecuteContractGeneric wasm_execute_contract_generic = 14; SignDirect sign_direct_message = 15; + AuthGrant auth_grant = 16; + AuthRevoke auth_revoke = 17; } } diff --git a/swift/Tests/Blockchains/CosmosTests.swift b/swift/Tests/Blockchains/CosmosTests.swift index 1730a20fadf..3d940fe09d5 100644 --- a/swift/Tests/Blockchains/CosmosTests.swift +++ b/swift/Tests/Blockchains/CosmosTests.swift @@ -67,6 +67,78 @@ class CosmosSignerTests: XCTestCase { XCTAssertJSONEqual(output.serialized, "{\"tx_bytes\": \"CowBCokBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmkKLWNvc21vczFoc2s2anJ5eXFqZmhwNWRoYzU1dGM5anRja3lneDBlcGg2ZGQwMhItY29zbW9zMXp0NTBhenVwYW5xbGZhbTVhZmh2M2hleHd5dXRudWtlaDRjNTczGgkKBG11b24SATESZQpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3FEgQKAggBGAgSEQoLCgRtdW9uEgMyMDAQwJoMGkD54fQAFlekIAnE62hZYl0uQelh/HLv0oQpCciY5Dn8H1SZFuTsrGdu41PH1Uxa4woptCELi/8Ov9yzdeEFAC9H\", \"mode\": \"BROADCAST_MODE_BLOCK\"}") XCTAssertEqual(output.error, "") } + + func testAuthCompounding() { + let authMessage = CosmosMessage.AuthGrant.with { + $0.granter = "cosmos13k0q0l7lg2kr32kvt7ly236ppldy8v9dzwh3gd" + $0.grantee = "cosmos1fs7lu28hx5m9akm7rp0c2422cn8r2f7gurujhf" + $0.grantStake = CosmosMessage.StakeAuthorization.with { + $0.allowList.address = ["cosmosvaloper1gjtvly9lel6zskvwtvlg5vhwpu9c9waw7sxzwx"] + $0.authorizationType = CosmosMessage.AuthorizationType.delegate + } + $0.expiration = 1692309600 + } + let message = CosmosMessage.with { + $0.authGrant = authMessage + } + let fee = CosmosFee.with { + $0.gas = 96681 + $0.amounts = [CosmosAmount.with { + $0.amount = "2418" + $0.denom = "uatom" + }] + } + + let input = CosmosSigningInput.with { + $0.signingMode = .protobuf; + $0.accountNumber = 1290826 + $0.chainID = "cosmoshub-4" + $0.memo = "" + $0.sequence = 5 + $0.messages = [message] + $0.fee = fee + $0.privateKey = PrivateKey(data: Data(hexString: "c7764249cdf77f8f1d840fa8af431579e5e41cf1af937e1e23afa22f3f4f0ccc")!)!.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .cosmos) + + XCTAssertJSONEqual(output.serialized, "{\"tx_bytes\": \"CvgBCvUBCh4vY29zbW9zLmF1dGh6LnYxYmV0YTEuTXNnR3JhbnQS0gEKLWNvc21vczEzazBxMGw3bGcya3IzMmt2dDdseTIzNnBwbGR5OHY5ZHp3aDNnZBItY29zbW9zMWZzN2x1MjhoeDVtOWFrbTdycDBjMjQyMmNuOHIyZjdndXJ1amhmGnIKaAoqL2Nvc21vcy5zdGFraW5nLnYxYmV0YTEuU3Rha2VBdXRob3JpemF0aW9uEjoSNgo0Y29zbW9zdmFsb3BlcjFnanR2bHk5bGVsNnpza3Z3dHZsZzV2aHdwdTljOXdhdzdzeHp3eCABEgYI4LD6pgYSZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA/fcQw1hCVUx904t+kCXTiiziaLIY8lyssu1ENfzaN1KEgQKAggBGAUSEwoNCgV1YXRvbRIEMjQxOBCp8wUaQIFyfuijGKf87Hz61ZqxasfLI1PZnNge4RDq/tRyB/tZI6p80iGRqHecoV6+84EQkc9GTlNRQOSlApRCsivT9XI=\", \"mode\": \"BROADCAST_MODE_BLOCK\"}") + XCTAssertEqual(output.error, "") + } + + func testRevokeAuthCompounding() { + let revokeAuthMessage = CosmosMessage.AuthRevoke.with { + $0.granter = "cosmos13k0q0l7lg2kr32kvt7ly236ppldy8v9dzwh3gd" + $0.grantee = "cosmos1fs7lu28hx5m9akm7rp0c2422cn8r2f7gurujhf" + $0.msgTypeURL = "/cosmos.staking.v1beta1.MsgDelegate" + } + let message = CosmosMessage.with { + $0.authRevoke = revokeAuthMessage + } + let fee = CosmosFee.with { + $0.gas = 87735 + $0.amounts = [CosmosAmount.with { + $0.amount = "2194" + $0.denom = "uatom" + }] + } + + let input = CosmosSigningInput.with { + $0.signingMode = .protobuf; + $0.accountNumber = 1290826 + $0.chainID = "cosmoshub-4" + $0.memo = "" + $0.sequence = 4 + $0.messages = [message] + $0.fee = fee + $0.privateKey = PrivateKey(data: Data(hexString: "c7764249cdf77f8f1d840fa8af431579e5e41cf1af937e1e23afa22f3f4f0ccc")!)!.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .cosmos) + + XCTAssertJSONEqual(output.serialized, "{\"tx_bytes\": \"CqoBCqcBCh8vY29zbW9zLmF1dGh6LnYxYmV0YTEuTXNnUmV2b2tlEoMBCi1jb3Ntb3MxM2swcTBsN2xnMmtyMzJrdnQ3bHkyMzZwcGxkeTh2OWR6d2gzZ2QSLWNvc21vczFmczdsdTI4aHg1bTlha203cnAwYzI0MjJjbjhyMmY3Z3VydWpoZhojL2Nvc21vcy5zdGFraW5nLnYxYmV0YTEuTXNnRGVsZWdhdGUSZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA/fcQw1hCVUx904t+kCXTiiziaLIY8lyssu1ENfzaN1KEgQKAggBGAQSEwoNCgV1YXRvbRIEMjE5NBC3rQUaQI7K+W7MMBoD6FbFZxRBqs9VTjErztjWTy57+fvrLaTCIZ+eBs7CuaKqfUZdSN8otjubSHVTQID3k9DpPAX0yDo=\", \"mode\": \"BROADCAST_MODE_BLOCK\"}") + XCTAssertEqual(output.error, "") + } func testStaking() { let stakeMessage = CosmosMessage.Delegate.with { diff --git a/tests/Cosmos/ProtobufTests.cpp b/tests/Cosmos/ProtobufTests.cpp index 9066f6c1394..a31b662ac5e 100644 --- a/tests/Cosmos/ProtobufTests.cpp +++ b/tests/Cosmos/ProtobufTests.cpp @@ -4,12 +4,13 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include "Base64.h" #include "Cosmos/Address.h" +#include "Cosmos/Protobuf/authz_tx.pb.h" #include "Cosmos/Protobuf/bank_tx.pb.h" #include "Cosmos/Protobuf/tx.pb.h" #include "Data.h" #include "HexCoding.h" -#include "Base64.h" #include "Protobuf/Article.pb.h" #include "../interface/TWTestUtilities.h" @@ -23,7 +24,6 @@ using namespace TW::Cosmos; using namespace TW; using json = nlohmann::json; - TEST(CosmosProtobuf, SendMsg) { auto msgSend = cosmos::bank::v1beta1::MsgSend(); msgSend.set_from_address("cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02"); diff --git a/tests/Cosmos/StakingTests.cpp b/tests/Cosmos/StakingTests.cpp index bde53cb1322..c7148d6c147 100644 --- a/tests/Cosmos/StakingTests.cpp +++ b/tests/Cosmos/StakingTests.cpp @@ -4,12 +4,12 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Coin.h" -#include "HexCoding.h" #include "Base64.h" -#include "proto/Cosmos.pb.h" +#include "Coin.h" #include "Cosmos/Address.h" #include "Cosmos/Signer.h" +#include "HexCoding.h" +#include "proto/Cosmos.pb.h" #include "../interface/TWTestUtilities.h" #include @@ -17,6 +17,75 @@ using namespace TW; using namespace TW::Cosmos; +TEST(CosmosStaking, CompoundingAuthz) { + // Successfully broadcasted https://www.mintscan.io/cosmos/txs/C4629BC7C88690518D8F448E7A8D239C9D63975B11F8E1CE2F95CC2ADA3CCF67 + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(1290826); + input.set_chain_id("cosmoshub-4"); + input.set_memo(""); + input.set_sequence(5); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_auth_grant(); + message.set_granter("cosmos13k0q0l7lg2kr32kvt7ly236ppldy8v9dzwh3gd"); + message.set_grantee("cosmos1fs7lu28hx5m9akm7rp0c2422cn8r2f7gurujhf"); + auto& grant_stake = *message.mutable_grant_stake(); + grant_stake.mutable_allow_list()->add_address("cosmosvaloper1gjtvly9lel6zskvwtvlg5vhwpu9c9waw7sxzwx"); + grant_stake.set_authorization_type(TW::Cosmos::Proto::Message_AuthorizationType_DELEGATE); + message.set_expiration(1692309600); + + auto& fee = *input.mutable_fee(); + fee.set_gas(96681); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uatom"); + amountOfFee->set_amount("2418"); + + auto privateKey = parse_hex("c7764249cdf77f8f1d840fa8af431579e5e41cf1af937e1e23afa22f3f4f0ccc"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeCosmos); + auto expected = R"( + { + "mode":"BROADCAST_MODE_BLOCK", + "tx_bytes":"CvgBCvUBCh4vY29zbW9zLmF1dGh6LnYxYmV0YTEuTXNnR3JhbnQS0gEKLWNvc21vczEzazBxMGw3bGcya3IzMmt2dDdseTIzNnBwbGR5OHY5ZHp3aDNnZBItY29zbW9zMWZzN2x1MjhoeDVtOWFrbTdycDBjMjQyMmNuOHIyZjdndXJ1amhmGnIKaAoqL2Nvc21vcy5zdGFraW5nLnYxYmV0YTEuU3Rha2VBdXRob3JpemF0aW9uEjoSNgo0Y29zbW9zdmFsb3BlcjFnanR2bHk5bGVsNnpza3Z3dHZsZzV2aHdwdTljOXdhdzdzeHp3eCABEgYI4LD6pgYSZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA/fcQw1hCVUx904t+kCXTiiziaLIY8lyssu1ENfzaN1KEgQKAggBGAUSEwoNCgV1YXRvbRIEMjQxOBCp8wUaQIFyfuijGKf87Hz61ZqxasfLI1PZnNge4RDq/tRyB/tZI6p80iGRqHecoV6+84EQkc9GTlNRQOSlApRCsivT9XI=" + })"; + assertJSONEqual(output.serialized(), expected); +} + +TEST(CosmosStaking, RevokeCompoundingAuthz) { + // Successfully broadcasted: https://www.mintscan.io/cosmos/txs/E3218F634BB6A1BE256545EBE38275D5B02D41E88F504A43F97CD9CD2B624D44 + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(1290826); + input.set_chain_id("cosmoshub-4"); + input.set_memo(""); + input.set_sequence(4); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_auth_revoke(); + message.set_grantee("cosmos1fs7lu28hx5m9akm7rp0c2422cn8r2f7gurujhf"); + message.set_granter("cosmos13k0q0l7lg2kr32kvt7ly236ppldy8v9dzwh3gd"); + message.set_msg_type_url("/cosmos.staking.v1beta1.MsgDelegate"); + + auto& fee = *input.mutable_fee(); + fee.set_gas(87735); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uatom"); + amountOfFee->set_amount("2194"); + + auto privateKey = parse_hex("c7764249cdf77f8f1d840fa8af431579e5e41cf1af937e1e23afa22f3f4f0ccc"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeCosmos); + auto expected = R"( + { + "mode":"BROADCAST_MODE_BLOCK", + "tx_bytes":"CqoBCqcBCh8vY29zbW9zLmF1dGh6LnYxYmV0YTEuTXNnUmV2b2tlEoMBCi1jb3Ntb3MxM2swcTBsN2xnMmtyMzJrdnQ3bHkyMzZwcGxkeTh2OWR6d2gzZ2QSLWNvc21vczFmczdsdTI4aHg1bTlha203cnAwYzI0MjJjbjhyMmY3Z3VydWpoZhojL2Nvc21vcy5zdGFraW5nLnYxYmV0YTEuTXNnRGVsZWdhdGUSZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA/fcQw1hCVUx904t+kCXTiiziaLIY8lyssu1ENfzaN1KEgQKAggBGAQSEwoNCgV1YXRvbRIEMjE5NBC3rQUaQI7K+W7MMBoD6FbFZxRBqs9VTjErztjWTy57+fvrLaTCIZ+eBs7CuaKqfUZdSN8otjubSHVTQID3k9DpPAX0yDo=" + })"; + assertJSONEqual(output.serialized(), expected); +} + TEST(CosmosStaking, Staking) { auto input = Proto::SigningInput(); input.set_signing_mode(Proto::Protobuf); diff --git a/tests/interface/TWTestUtilities.h b/tests/interface/TWTestUtilities.h index 1adc36b9ac0..a03691dc7e4 100644 --- a/tests/interface/TWTestUtilities.h +++ b/tests/interface/TWTestUtilities.h @@ -33,7 +33,7 @@ inline void assertHexEqual(const std::shared_ptr& data, const char* expe inline void assertJSONEqual(const std::string& lhs, const char* expected) { auto lhsJson = nlohmann::json::parse(lhs); auto rhsJson = nlohmann::json::parse(std::string(expected)); - ASSERT_EQ(lhsJson.dump(), rhsJson.dump()); + ASSERT_EQ(lhsJson, rhsJson); } inline std::vector* dataFromTWData(TWData* data) { From e2dc902e119780fc5f2c570e92149fd00df8d650 Mon Sep 17 00:00:00 2001 From: rongyi Date: Fri, 26 Aug 2022 10:08:28 +0800 Subject: [PATCH 063/497] [Ontology] Add OEP4 token support (#2514) * Support ontology oep4 * Drop using namespace * Add mainnet transaction test * Rename helper method to make it more readable * Add oep4 entry in signer * Add ctor accept Data * Drop unused variables * Update license for all Ontology file --- src/Ontology/Address.cpp | 2 +- src/Ontology/Address.h | 2 +- src/Ontology/Asset.h | 2 +- src/Ontology/Entry.cpp | 2 +- src/Ontology/Entry.h | 2 +- src/Ontology/Oep4.cpp | 69 +++++++++++++ src/Ontology/Oep4.h | 41 ++++++++ src/Ontology/Oep4TxBuilder.cpp | 51 ++++++++++ src/Ontology/Oep4TxBuilder.h | 29 ++++++ src/Ontology/Ong.cpp | 2 +- src/Ontology/Ong.h | 2 +- src/Ontology/OngTxBuilder.cpp | 2 +- src/Ontology/OngTxBuilder.h | 2 +- src/Ontology/Ont.cpp | 2 +- src/Ontology/Ont.h | 2 +- src/Ontology/OntTxBuilder.cpp | 2 +- src/Ontology/OntTxBuilder.h | 2 +- src/Ontology/OpCode.h | 5 +- src/Ontology/ParamsBuilder.cpp | 18 +++- src/Ontology/ParamsBuilder.h | 12 ++- src/Ontology/SigData.cpp | 2 +- src/Ontology/SigData.h | 2 +- src/Ontology/Signer.cpp | 19 ++-- src/Ontology/Signer.h | 12 +-- src/Ontology/Transaction.cpp | 2 +- src/Ontology/Transaction.h | 2 +- tests/Ontology/AccountTests.cpp | 2 +- tests/Ontology/AddressTests.cpp | 2 +- tests/Ontology/Oep4Tests.cpp | 140 ++++++++++++++++++++++++++ tests/Ontology/OngTests.cpp | 2 +- tests/Ontology/OntTests.cpp | 2 +- tests/Ontology/ParamsBuilderTests.cpp | 44 +++++++- tests/Ontology/TWAnySignerTests.cpp | 49 ++++++++- tests/Ontology/TWCoinTypeTests.cpp | 2 +- tests/Ontology/TransactionTests.cpp | 2 +- 35 files changed, 489 insertions(+), 46 deletions(-) create mode 100644 src/Ontology/Oep4.cpp create mode 100644 src/Ontology/Oep4.h create mode 100644 src/Ontology/Oep4TxBuilder.cpp create mode 100644 src/Ontology/Oep4TxBuilder.h create mode 100644 tests/Ontology/Oep4Tests.cpp diff --git a/src/Ontology/Address.cpp b/src/Ontology/Address.cpp index 9167c9eebf9..40333d62217 100644 --- a/src/Ontology/Address.cpp +++ b/src/Ontology/Address.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/Address.h b/src/Ontology/Address.h index 5b9e640ea56..b55ebf1f3dc 100644 --- a/src/Ontology/Address.h +++ b/src/Ontology/Address.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/Asset.h b/src/Ontology/Asset.h index 1b1b0895094..95e15a1f9cc 100644 --- a/src/Ontology/Asset.h +++ b/src/Ontology/Asset.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/Entry.cpp b/src/Ontology/Entry.cpp index 0b6e1349c52..648cd7ddf9a 100644 --- a/src/Ontology/Entry.cpp +++ b/src/Ontology/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/Entry.h b/src/Ontology/Entry.h index e4d9ab17597..db8ae468192 100644 --- a/src/Ontology/Entry.h +++ b/src/Ontology/Entry.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/Oep4.cpp b/src/Ontology/Oep4.cpp new file mode 100644 index 00000000000..2152c186274 --- /dev/null +++ b/src/Ontology/Oep4.cpp @@ -0,0 +1,69 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Oep4.h" +#include + +namespace TW::Ontology { +Oep4::Oep4(const Address addr) noexcept + : oep4Contract(addr._data.begin(), addr._data.end()) { +} + +Oep4::Oep4(const Data bin) noexcept + : oep4Contract(bin) { +} + +Transaction Oep4::readOnlyMethod(std::string method_name, uint32_t nonce) { + Address addr(oep4Contract); + std::vector args{}; + auto invokeCode = ParamsBuilder::buildOep4InvokeCode(addr, method_name, args); + + return Transaction(0, 0xD1, nonce, 0, 0, "", invokeCode); +} + +Transaction Oep4::name(uint32_t nonce) { + return Oep4::readOnlyMethod("name", nonce); +} + +Transaction Oep4::symbol(uint32_t nonce) { + return Oep4::readOnlyMethod("symbol", nonce); +} + +Transaction Oep4::decimals(uint32_t nonce) { + return Oep4::readOnlyMethod("decimals", nonce); +} + +Transaction Oep4::totalSupply(uint32_t nonce) { + return Oep4::readOnlyMethod("totalSupply", nonce); +} + +Transaction Oep4::balanceOf(const Address& user, uint32_t nonce) { + Address contract(oep4Contract); + Data d(std::begin(user._data), std::end(user._data)); + std::vector args{d}; + auto invokeCode = ParamsBuilder::buildOep4InvokeCode(contract, "balanceOf", args); + return Transaction(0, 0xD1, nonce, 0, 0, "", invokeCode); +} + +Transaction Oep4::transfer(const Signer& from, const Address& to, uint64_t amount, + const Signer& payer, uint64_t gasPrice, uint64_t gasLimit, + uint32_t nonce) { + Address contract(oep4Contract); + + auto fromAddr = from.getAddress(); + std::vector args{fromAddr._data, to._data, amount}; + // yes, invoke neovm is not like ont transfer + std::reverse(args.begin(), args.end()); + auto invokeCode = ParamsBuilder::buildOep4InvokeCode(contract, "transfer", args); + + auto tx = Transaction(0, 0xD1, nonce, gasPrice, gasLimit, payer.getAddress().string(), invokeCode); + from.sign(tx); + payer.addSign(tx); + + return tx; +} + +} // namespace TW::Ontology diff --git a/src/Ontology/Oep4.h b/src/Ontology/Oep4.h new file mode 100644 index 00000000000..f3b8ebdc3bc --- /dev/null +++ b/src/Ontology/Oep4.h @@ -0,0 +1,41 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Address.h" +#include "Asset.h" +#include "ParamsBuilder.h" +#include "Transaction.h" +#include "../Data.h" + +namespace TW::Ontology { + +class Oep4 { +private: + static constexpr uint8_t version = 0x00; + + Data oep4Contract; + // building neovm instruction for oep4 readonly method(name, symbol...) + // are all the same except the method name + Transaction readOnlyMethod(std::string methodName, uint32_t nonce); + +public: + explicit Oep4(const Address addr) noexcept; + explicit Oep4(const Data bin) noexcept; + Oep4() = delete; + Data contractAddress() { return oep4Contract; } + Transaction name(uint32_t nonce); + Transaction symbol(uint32_t nonce); + Transaction decimals(uint32_t nonce); + Transaction totalSupply(uint32_t nonce); + Transaction balanceOf(const Address& address, uint32_t nonce); + Transaction transfer(const Signer& from, const Address& to, uint64_t amount, + const Signer& payer, uint64_t gasPrice, uint64_t gasLimit, + uint32_t nonce); +}; + +} // namespace TW::Ontology diff --git a/src/Ontology/Oep4TxBuilder.cpp b/src/Ontology/Oep4TxBuilder.cpp new file mode 100644 index 00000000000..04e5f2c108c --- /dev/null +++ b/src/Ontology/Oep4TxBuilder.cpp @@ -0,0 +1,51 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Oep4TxBuilder.h" +#include "../HexCoding.h" + +namespace TW::Ontology { + +Data Oep4TxBuilder::decimals(const Ontology::Proto::SigningInput& input) { + Oep4 oep4(parse_hex(input.contract())); + auto transaction = oep4.decimals(input.nonce()); + auto encoded = transaction.serialize(); + return encoded; +} + +Data Oep4TxBuilder::balanceOf(const Ontology::Proto::SigningInput& input) { + Oep4 oep4(parse_hex(input.contract())); + auto queryAddress = Address(input.query_address()); + auto transaction = oep4.balanceOf(queryAddress, input.nonce()); + auto encoded = transaction.serialize(); + return encoded; +} + +Data Oep4TxBuilder::transfer(const Ontology::Proto::SigningInput& input) { + Oep4 oep4(parse_hex(input.contract())); + auto payerSigner = Signer(PrivateKey(input.payer_private_key())); + auto fromSigner = Signer(PrivateKey(input.owner_private_key())); + auto toAddress = Address(input.to_address()); + auto tranferTx = oep4.transfer(fromSigner, toAddress, input.amount(), payerSigner, + input.gas_price(), input.gas_limit(), input.nonce()); + auto encoded = tranferTx.serialize(); + return encoded; +} + +Data Oep4TxBuilder::build(const Ontology::Proto::SigningInput& input) { + auto method = std::string(input.method().begin(), input.method().end()); + if (method == "transfer") { + return Oep4TxBuilder::transfer(input); + } else if (method == "balanceOf") { + return Oep4TxBuilder::balanceOf(input); + } else if (method == "decimals") { + return Oep4TxBuilder::decimals(input); + } + + return Data(); +} + +} // namespace TW::Ontology diff --git a/src/Ontology/Oep4TxBuilder.h b/src/Ontology/Oep4TxBuilder.h new file mode 100644 index 00000000000..138f955aa82 --- /dev/null +++ b/src/Ontology/Oep4TxBuilder.h @@ -0,0 +1,29 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Oep4.h" + +#include "../proto/Ontology.pb.h" + +#include + +namespace TW::Ontology { + +class Oep4TxBuilder { + +public: + static Data decimals(const Ontology::Proto::SigningInput& input); + + static Data balanceOf(const Ontology::Proto::SigningInput& input); + + static Data transfer(const Ontology::Proto::SigningInput& input); + + static Data build(const Ontology::Proto::SigningInput& input); +}; + +} // namespace TW::Ontology diff --git a/src/Ontology/Ong.cpp b/src/Ontology/Ong.cpp index 209e4b21e0a..ab9c4eacd7c 100644 --- a/src/Ontology/Ong.cpp +++ b/src/Ontology/Ong.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/Ong.h b/src/Ontology/Ong.h index 27de0c1d108..d4d616bc47b 100644 --- a/src/Ontology/Ong.h +++ b/src/Ontology/Ong.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/OngTxBuilder.cpp b/src/Ontology/OngTxBuilder.cpp index 8fc3c7f89d0..4f9865e4304 100644 --- a/src/Ontology/OngTxBuilder.cpp +++ b/src/Ontology/OngTxBuilder.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/OngTxBuilder.h b/src/Ontology/OngTxBuilder.h index e5843a0909b..a97c169c5fd 100644 --- a/src/Ontology/OngTxBuilder.h +++ b/src/Ontology/OngTxBuilder.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/Ont.cpp b/src/Ontology/Ont.cpp index 6f279c9f38c..51f9bc76864 100644 --- a/src/Ontology/Ont.cpp +++ b/src/Ontology/Ont.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/Ont.h b/src/Ontology/Ont.h index d0dce26e64d..567c9f97625 100644 --- a/src/Ontology/Ont.h +++ b/src/Ontology/Ont.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/OntTxBuilder.cpp b/src/Ontology/OntTxBuilder.cpp index 9b727313fae..d96a33317d5 100644 --- a/src/Ontology/OntTxBuilder.cpp +++ b/src/Ontology/OntTxBuilder.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/OntTxBuilder.h b/src/Ontology/OntTxBuilder.h index aabc1cc8e40..5cf64cbe16c 100644 --- a/src/Ontology/OntTxBuilder.h +++ b/src/Ontology/OntTxBuilder.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/OpCode.h b/src/Ontology/OpCode.h index 6c44454b1a3..3f7904242fd 100644 --- a/src/Ontology/OpCode.h +++ b/src/Ontology/OpCode.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -25,5 +25,6 @@ static const uint8_t TO_ALT_STACK{0x6B}; static const uint8_t FROM_ALT_STACK{0x6C}; static const uint8_t SWAP{0x7C}; static const uint8_t HAS_KEY{0xC8}; +static const uint8_t APP_CALL{0x67}; -} // namespace TW::Ontology \ No newline at end of file +} // namespace TW::Ontology diff --git a/src/Ontology/ParamsBuilder.cpp b/src/Ontology/ParamsBuilder.cpp index 367863b085e..47d050cd0a5 100644 --- a/src/Ontology/ParamsBuilder.cpp +++ b/src/Ontology/ParamsBuilder.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,8 +12,8 @@ #include #include -#include #include +#include using namespace TW; using namespace TW::Ontology; @@ -231,4 +231,16 @@ Data ParamsBuilder::buildNativeInvokeCode(const Data& contractAddress, uint8_t v std::string nativeInvoke = "Ontology.Native.Invoke"; builder.push(Data(nativeInvoke.begin(), nativeInvoke.end())); return builder.getBytes(); -} \ No newline at end of file +} + +Data ParamsBuilder::buildOep4InvokeCode(const Address& contractAddress, const std::string& method, const boost::any& params) { + ParamsBuilder builder; + ParamsBuilder::buildNeoVmParam(builder, params); + builder.push(method); + builder.pushBack(APP_CALL); + Address clone = contractAddress; + std::reverse(std::begin(clone._data), std::end(clone._data)); + builder.pushBack(clone._data); + + return builder.getBytes(); +} diff --git a/src/Ontology/ParamsBuilder.h b/src/Ontology/ParamsBuilder.h index cf2b3202003..7f7ab9404d5 100644 --- a/src/Ontology/ParamsBuilder.h +++ b/src/Ontology/ParamsBuilder.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -16,14 +16,16 @@ #include #include +#include "Address.h" + namespace TW::Ontology { class ParamsBuilder { - private: +private: std::vector bytes; - public: +public: static const size_t MAX_PK_SIZE = 16; std::vector getBytes() { return bytes; } @@ -78,6 +80,8 @@ class ParamsBuilder { static std::vector buildNativeInvokeCode(const std::vector& contractAddress, uint8_t version, const std::string& method, const boost::any& params); + + static std::vector buildOep4InvokeCode(const Address& contractAddress, const std::string& method, const boost::any& params); }; -} // namespace TW::Ontology \ No newline at end of file +} // namespace TW::Ontology diff --git a/src/Ontology/SigData.cpp b/src/Ontology/SigData.cpp index e1f52e1b1e2..782f6dda84b 100644 --- a/src/Ontology/SigData.cpp +++ b/src/Ontology/SigData.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/SigData.h b/src/Ontology/SigData.h index eaa054c4115..dd76b9d54cb 100644 --- a/src/Ontology/SigData.h +++ b/src/Ontology/SigData.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/Signer.cpp b/src/Ontology/Signer.cpp index 70fbc9e0661..50bceecd6b9 100644 --- a/src/Ontology/Signer.cpp +++ b/src/Ontology/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,6 +7,7 @@ #include "Signer.h" #include "HexCoding.h" #include "SigData.h" +#include "../Ontology/Oep4TxBuilder.h" #include "../Ontology/OngTxBuilder.h" #include "../Ontology/OntTxBuilder.h" @@ -14,8 +15,7 @@ #include -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto contract = std::string(input.contract().begin(), input.contract().end()); @@ -27,20 +27,25 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { } else if (contract == "ONG") { auto encoded = OngTxBuilder::build(input); output.set_encoded(encoded.data(), encoded.size()); + } else { + // then assume it's oep4 address + auto encoded = Oep4TxBuilder::build(input); + output.set_encoded(encoded.data(), encoded.size()); } } catch (...) { } return output; } -Signer::Signer(TW::PrivateKey priKey) : privateKey(std::move(priKey)) { - auto pubKey = privateKey.getPublicKey(TWPublicKeyTypeNIST256p1); +Signer::Signer(TW::PrivateKey priKey) + : privKey(std::move(priKey)) { + auto pubKey = privKey.getPublicKey(TWPublicKeyTypeNIST256p1); publicKey = pubKey.bytes; address = Address(pubKey).string(); } PrivateKey Signer::getPrivateKey() const { - return privateKey; + return privKey; } PublicKey Signer::getPublicKey() const { @@ -68,3 +73,5 @@ void Signer::addSign(Transaction& tx) const { signature.pop_back(); tx.sigVec.emplace_back(publicKey, signature, 1); } + +} // namespace TW::Ontology diff --git a/src/Ontology/Signer.h b/src/Ontology/Signer.h index bf5e21f83ca..4f2dc8459ca 100644 --- a/src/Ontology/Signer.h +++ b/src/Ontology/Signer.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -15,19 +15,19 @@ #include #include - namespace TW::Ontology { class Signer { - public: +public: /// Signs a Proto::SigningInput transaction static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept; - private: + +private: Data publicKey; - TW::PrivateKey privateKey; + TW::PrivateKey privKey; std::string address; - public: +public: explicit Signer(TW::PrivateKey priKey); PrivateKey getPrivateKey() const; diff --git a/src/Ontology/Transaction.cpp b/src/Ontology/Transaction.cpp index 8a78e478735..e5c8cc30a15 100644 --- a/src/Ontology/Transaction.cpp +++ b/src/Ontology/Transaction.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Ontology/Transaction.h b/src/Ontology/Transaction.h index e4f9796b4f6..0f1388b3eb7 100644 --- a/src/Ontology/Transaction.h +++ b/src/Ontology/Transaction.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/tests/Ontology/AccountTests.cpp b/tests/Ontology/AccountTests.cpp index ddd717f483b..1fdf49f4806 100644 --- a/tests/Ontology/AccountTests.cpp +++ b/tests/Ontology/AccountTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/tests/Ontology/AddressTests.cpp b/tests/Ontology/AddressTests.cpp index f27c2cdd691..7945dae19be 100644 --- a/tests/Ontology/AddressTests.cpp +++ b/tests/Ontology/AddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/tests/Ontology/Oep4Tests.cpp b/tests/Ontology/Oep4Tests.cpp new file mode 100644 index 00000000000..be49303bd69 --- /dev/null +++ b/tests/Ontology/Oep4Tests.cpp @@ -0,0 +1,140 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" + +#include "Ontology/Oep4.h" +#include "Ontology/Signer.h" +#include +#include + +namespace TW::Ontology::tests { + +TEST(OntologyOep4, name) { + std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; + auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + Oep4 wing(wing_addr); + + uint32_t nonce = 0x1234; + auto tx = wing.name(nonce); + auto rawTx = hex(tx.serialize()); + EXPECT_EQ("00d1341200000000000000000000000000000000000000000000000000000000000000000000000000001c00c1046e616d656733def739225d0f93dd2aed457d7b1fd074ec31ff0000", rawTx); +} + +TEST(OntologyOep4, symbol) { + std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; + auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + Oep4 wing(wing_addr); + + uint32_t nonce = 0x1234; + auto tx = wing.symbol(nonce); + auto rawTx = hex(tx.serialize()); + EXPECT_EQ("00d1341200000000000000000000000000000000000000000000000000000000000000000000000000001e00c10673796d626f6c6733def739225d0f93dd2aed457d7b1fd074ec31ff0000", rawTx); +} + +TEST(OntologyOep4, decimals) { + std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; + auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + Oep4 wing(wing_addr); + + uint32_t nonce = 0x1234; + auto tx = wing.decimals(nonce); + auto rawTx = hex(tx.serialize()); + EXPECT_EQ("00d1341200000000000000000000000000000000000000000000000000000000000000000000000000002000c108646563696d616c736733def739225d0f93dd2aed457d7b1fd074ec31ff0000", rawTx); +} + +TEST(OntologyOep4, totalSupply) { + std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; + auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + Oep4 wing(wing_addr); + + uint32_t nonce = 0x1234; + auto tx = wing.totalSupply(nonce); + auto rawTx = hex(tx.serialize()); + EXPECT_EQ("00d1341200000000000000000000000000000000000000000000000000000000000000000000000000002300c10b746f74616c537570706c796733def739225d0f93dd2aed457d7b1fd074ec31ff0000", rawTx); +} + +TEST(OntologyOep4, balanceOf) { + std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; + auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + Oep4 wing(wing_addr); + auto user = Address("AeaThtPwh5kAYnjHavzwmvxPd725nVTvbM"); + + uint32_t nonce = 0x1234; + auto tx = wing.balanceOf(user, nonce); + auto rawTx = hex(tx.serialize()); + EXPECT_EQ("00d1341200000000000000000000000000000000000000000000000000000000000000000000000000003614fa2254ffaee3c3e1172e8e98f800e4105c74988e51c10962616c616e63654f666733def739225d0f93dd2aed457d7b1fd074ec31ff0000", rawTx); +} + +TEST(OntologyOep4, addressHack) { + auto ownerbin = parse_hex("4646464646464646464646464646464646464646464646464646464646464646"); + auto payerbin = parse_hex("4646464646464646464646464646464646464646464646464646464646464652"); + + PrivateKey owner(ownerbin); + PrivateKey payer(payerbin); + + auto pubKey = owner.getPublicKey(TWPublicKeyTypeNIST256p1); + Address addr(pubKey); + + EXPECT_EQ("AeicEjZyiXKgUeSBbYQHxsU1X3V5Buori5", addr.string()); + + auto payerpub_key = payer.getPublicKey(TWPublicKeyTypeNIST256p1); + Address payer_addr(payerpub_key); + EXPECT_EQ("APniYDGozkhUh8Tk7pe35aah2HGJ4fJfVd", payer_addr.string()); +} + +TEST(OntologyOep4, transfer) { + auto from = Signer( + PrivateKey(parse_hex("4646464646464646464646464646464646464646464646464646464646464652"))); + + auto payer = Signer( + PrivateKey(parse_hex("4646464646464646464646464646464646464646464646464646464646464646"))); + + auto toAddress = Address("AVY6LfvxauVQAVHDV9hC3ZCv7cQqzfDotH"); + + uint32_t nonce = 0x1234; + uint64_t amount = 233; + uint64_t gasPrice = 2500; + uint64_t gasLimit = 50000; + + std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; + auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + Oep4 wing(wing_addr); + + auto tx = wing.transfer(from, toAddress, amount, payer, gasPrice, gasLimit, nonce); + auto rawTx = hex(tx.serialize()); + // Transaction Hex tab + // https://explorer.ont.io/testnet/tx/710266b8d497e794ecd47e01e269e4aeb6f4ff2b01eaeafc4cd371e062b13757 + EXPECT_EQ("00d134120000c40900000000000050c3000000000000fbacc8214765d457c8e3f2b5a1d3c4981a2e9d2a4d02e9001496f688657b95be51c11a87b51adfda4ab69e9cbb1457e9d1a61f9aafa798b6c7fbeae35639681d7df653c1087472616e736665726733def739225d0f93dd2aed457d7b1fd074ec31ff00024140bd2923854d7b84b97a107bb3cddf18c8e3dddd2f36b41a1f5f5b23366484daa22871cfb819923fe01e9cb1e9ed16baa2b05c2feb76bcbe2ec125f72701c5e965232103d9fd62df332403d9114f3fa3da0d5aec9dfa42948c2f50738d52470469a1a1eeac41406d638653597774ce45812ea2653250806b657b32b7c6ad3e027ddeba91e9a9da4bb5dacd23dafba868cb31bacb38b4a6ff2607682a426c1dc09b05a1e158d6cd2321031bec1250aa8f78275f99a6663688f31085848d0ed92f1203e447125f927b7486ac", rawTx); +} + +TEST(OntologyOep4, transferMainnet) { + auto from = Signer( + PrivateKey(parse_hex("4646464646464646464646464646464646464646464646464646464646464652"))); + + auto payer = Signer( + PrivateKey(parse_hex("4646464646464646464646464646464646464646464646464646464646464646"))); + + auto toAddress = Address("AUJJhwRNi4RsNfvuexLETxXEb6szu9D5Ad"); + + uint32_t nonce = 0x1234; + uint64_t amount = 233; + uint64_t gasPrice = 2500; + uint64_t gasLimit = 50000; + + // wing oep4 mainnet address + std::string wing_hex{"00c59fcd27a562d6397883eab1f2fff56e58ef80"}; + auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + Oep4 wing(wing_addr); + + auto tx = wing.transfer(from, toAddress, amount, payer, gasPrice, gasLimit, nonce); + auto rawTx = hex(tx.serialize()); + // Transaction Hex tab + // https://explorer.ont.io/tx/70b276aaeb6b4578237390ec339b6a196f4620bdef8df1717032d32576ccef4a + EXPECT_EQ("00d134120000c40900000000000050c3000000000000fbacc8214765d457c8e3f2b5a1d3c4981a2e9d2a4d02e900148962e81f62cb76068b5f204ea5425d64d57147191457e9d1a61f9aafa798b6c7fbeae35639681d7df653c1087472616e736665726780ef586ef5fff2b1ea837839d662a527cd9fc500000241403c3a5e738f99e8f98ac4f59e225e549e2483bb60aee1771ef8ef189255e1670825d6a4c401f2e103348877393d8355c4d295b21fdfaf3dc4fea9b0459f1e1507232103d9fd62df332403d9114f3fa3da0d5aec9dfa42948c2f50738d52470469a1a1eeac41409501ccaab299dc660da9084dd6e8f22658f7687e77319b17b97149c3f023806d04b300baa52874eae57ccde935bb64e2c16c59e00e0efe7086ae93c1153b80722321031bec1250aa8f78275f99a6663688f31085848d0ed92f1203e447125f927b7486ac", rawTx); +} + +} // namespace TW::Ontology::tests diff --git a/tests/Ontology/OngTests.cpp b/tests/Ontology/OngTests.cpp index afb5ba4fd67..88ca8431eea 100644 --- a/tests/Ontology/OngTests.cpp +++ b/tests/Ontology/OngTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/tests/Ontology/OntTests.cpp b/tests/Ontology/OntTests.cpp index e2d26a06895..e03c72b793b 100644 --- a/tests/Ontology/OntTests.cpp +++ b/tests/Ontology/OntTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/tests/Ontology/ParamsBuilderTests.cpp b/tests/Ontology/ParamsBuilderTests.cpp index eed7e998aca..875a207a3dc 100644 --- a/tests/Ontology/ParamsBuilderTests.cpp +++ b/tests/Ontology/ParamsBuilderTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -82,3 +82,45 @@ TEST(ParamsBuilder, transferInvokeCode) { "164f6e746f6c6f67792e4e61746976652e496e766f6b65"; EXPECT_EQ(hexInvokeCode, hex(invokeCode)); } + +TEST(ParamsBuilder, invokeOep4Code) { + std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; + auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + + std::vector args{}; + std::string method{"name"}; + auto invokeCode = ParamsBuilder::buildOep4InvokeCode(wing_addr, method, args); + + auto expectCode = "00c1046e616d656733def739225d0f93dd2aed457d7b1fd074ec31ff"; + EXPECT_EQ(expectCode, hex(invokeCode)); +} + +TEST(ParamsBuilder, invokeOep4CodeBalanceOf) { + std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; + auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + auto user_addr = Address("AeaThtPwh5kAYnjHavzwmvxPd725nVTvbM"); + Data d(std::begin(user_addr._data), std::end(user_addr._data)); + + std::vector args{d}; + std::string method{"balanceOf"}; + auto invokeCode = ParamsBuilder::buildOep4InvokeCode(wing_addr, method, args); + + auto expectCode = "14fa2254ffaee3c3e1172e8e98f800e4105c74988e51c10962616c616e63654f666733def739225d0f93dd2aed457d7b1fd074ec31ff"; + EXPECT_EQ(expectCode, hex(invokeCode)); +} + +TEST(OntologyOep4, invokeOep4CodeTransfer) { + std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; + auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + auto from = Address("APniYDGozkhUh8Tk7pe35aah2HGJ4fJfVd"); + auto to = Address("AVY6LfvxauVQAVHDV9hC3ZCv7cQqzfDotH"); + uint64_t amount = 253; + + std::vector args{from._data, to._data, amount}; + std::reverse(args.begin(), args.end()); + std::string method{"transfer"}; + auto invokeCode = ParamsBuilder::buildOep4InvokeCode(wing_addr, method, args); + + auto expectCode = "02fd001496f688657b95be51c11a87b51adfda4ab69e9cbb1457e9d1a61f9aafa798b6c7fbeae35639681d7df653c1087472616e736665726733def739225d0f93dd2aed457d7b1fd074ec31ff"; + EXPECT_EQ(expectCode, hex(invokeCode)); +} diff --git a/tests/Ontology/TWAnySignerTests.cpp b/tests/Ontology/TWAnySignerTests.cpp index f9cfe0be93d..e25b1e46190 100644 --- a/tests/Ontology/TWAnySignerTests.cpp +++ b/tests/Ontology/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,6 +7,7 @@ #include "HexCoding.h" #include "../interface/TWTestUtilities.h" +#include "Ontology/Oep4TxBuilder.h" #include "Ontology/OngTxBuilder.h" #include "Ontology/OntTxBuilder.h" @@ -190,4 +191,50 @@ TEST(TWAnySingerOntology, OngWithdraw) { rawTx); } +TEST(TWAnySingerOntology, Oep4Decimal) { + auto input = Proto::SigningInput(); + input.set_contract("ff31ec74d01f7b7d45ed2add930f5d2239f7de33"); + input.set_method("decimals"); + input.set_nonce(0x1234); + auto data = Oep4TxBuilder::build(input); + auto rawTx = hex(data); + EXPECT_EQ("00d1341200000000000000000000000000000000000000000000000000000000000000000000000000002000c108646563696d616c736733def739225d0f93dd2aed457d7b1fd074ec31ff0000", rawTx); +} + +TEST(TWAnySingerOntology, Oep4BalanceOf) { + // read only method don't need signer + auto input = Proto::SigningInput(); + input.set_contract("ff31ec74d01f7b7d45ed2add930f5d2239f7de33"); + input.set_method("balanceOf"); + input.set_query_address("AeaThtPwh5kAYnjHavzwmvxPd725nVTvbM"); + input.set_nonce(0x1234); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeOntology); + EXPECT_EQ("00d1341200000000000000000000000000000000000000000000000000000000000000000000000000003614fa2254ffaee3c3e1172e8e98f800e4105c74988e51c10962616c616e63654f666733def739225d0f93dd2aed457d7b1fd074ec31ff0000", hex(output.encoded())); +} + +TEST(TWAnySingerOntology, Oep4Transfer) { + // https://explorer.ont.io/testnet/tx/710266b8d497e794ecd47e01e269e4aeb6f4ff2b01eaeafc4cd371e062b13757 + auto ownerPrivateKey = + parse_hex("4646464646464646464646464646464646464646464646464646464646464652"); + auto payerPrivateKey = + parse_hex("4646464646464646464646464646464646464646464646464646464646464646"); + auto input = Proto::SigningInput(); + input.set_contract("ff31ec74d01f7b7d45ed2add930f5d2239f7de33"); + input.set_method("transfer"); + input.set_owner_private_key(ownerPrivateKey.data(), ownerPrivateKey.size()); + input.set_payer_private_key(payerPrivateKey.data(), payerPrivateKey.size()); + input.set_to_address("AVY6LfvxauVQAVHDV9hC3ZCv7cQqzfDotH"); + input.set_amount(233); + input.set_gas_price(2500); + input.set_gas_limit(50000); + input.set_nonce(0x1234); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeOntology); + + EXPECT_EQ("00d134120000c40900000000000050c3000000000000fbacc8214765d457c8e3f2b5a1d3c4981a2e9d2a4d02e9001496f688657b95be51c11a87b51adfda4ab69e9cbb1457e9d1a61f9aafa798b6c7fbeae35639681d7df653c1087472616e736665726733def739225d0f93dd2aed457d7b1fd074ec31ff00024140bd2923854d7b84b97a107bb3cddf18c8e3dddd2f36b41a1f5f5b23366484daa22871cfb819923fe01e9cb1e9ed16baa2b05c2feb76bcbe2ec125f72701c5e965232103d9fd62df332403d9114f3fa3da0d5aec9dfa42948c2f50738d52470469a1a1eeac41406d638653597774ce45812ea2653250806b657b32b7c6ad3e027ddeba91e9a9da4bb5dacd23dafba868cb31bacb38b4a6ff2607682a426c1dc09b05a1e158d6cd2321031bec1250aa8f78275f99a6663688f31085848d0ed92f1203e447125f927b7486ac", hex(output.encoded())); +} + } // namespace TW::Ontology::tests diff --git a/tests/Ontology/TWCoinTypeTests.cpp b/tests/Ontology/TWCoinTypeTests.cpp index 30bb745ab50..733c1fe94cf 100644 --- a/tests/Ontology/TWCoinTypeTests.cpp +++ b/tests/Ontology/TWCoinTypeTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/tests/Ontology/TransactionTests.cpp b/tests/Ontology/TransactionTests.cpp index c3ed787c304..1954db1db33 100644 --- a/tests/Ontology/TransactionTests.cpp +++ b/tests/Ontology/TransactionTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the From 77865d42c8590f7ab5f3b584e604e14e61cc56d5 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 26 Aug 2022 04:10:01 +0200 Subject: [PATCH 064/497] [Tezos]: FA1.2/FA2 support (#2527) * feat(tezos): add new forging operations * feat(tezos): update proto * feat(tezos): add forgeAddress * feat(tezos): add forgeMichelJson capabilities * feat(tezos): finalize fa12 transaction transfer * feat(tezos): upgrade signFA12 tests * feat(tezos): add the ref of the broadcasted FA12 transaction * feat(tezos): add full fa2 support * feat(tezos_tokens): remove unused parameter from forgeArray --- .../app/blockchains/tezos/TestTezosSigner.kt | 122 +++++++++++- src/Tezos/Address.cpp | 2 +- src/Tezos/Address.h | 2 +- src/Tezos/BinaryCoding.cpp | 2 +- src/Tezos/BinaryCoding.h | 2 +- src/Tezos/Entry.cpp | 2 +- src/Tezos/Entry.h | 2 +- src/Tezos/Forging.cpp | 178 +++++++++++++++++- src/Tezos/Forging.h | 19 +- src/Tezos/Michelson.cpp | 32 ++++ src/Tezos/Michelson.h | 56 ++++++ src/Tezos/OperationList.cpp | 2 +- src/Tezos/OperationList.h | 6 + src/Tezos/Signer.cpp | 2 +- src/Tezos/Signer.h | 2 +- src/proto/Tezos.proto | 33 +++- swift/Tests/Blockchains/TezosTests.swift | 87 +++++++++ tests/Tezos/ForgingTests.cpp | 120 +++++++++--- tests/Tezos/TWAnySignerTests.cpp | 65 +++++++ 19 files changed, 688 insertions(+), 48 deletions(-) create mode 100644 src/Tezos/Michelson.cpp create mode 100644 src/Tezos/Michelson.h diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tezos/TestTezosSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tezos/TestTezosSigner.kt index f84b3edb766..f14a6a6c689 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tezos/TestTezosSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tezos/TestTezosSigner.kt @@ -1,10 +1,13 @@ -package com.trustwallet.core.app.blockchains.waves +package com.trustwallet.core.app.blockchains.tezos +import com.trustwallet.core.app.utils.Numeric import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytesInByteString import org.junit.Assert.* import org.junit.Test import wallet.core.jni.CoinType.TEZOS import wallet.core.java.AnySigner +import wallet.core.jni.proto.Tezos.* class TestTezosTransactionSigner { @@ -12,6 +15,115 @@ class TestTezosTransactionSigner { System.loadLibrary("TrustWalletCore") } + @Test + fun testSigningFA2() { + val key = + "363265a0b3f06661001cab8b4f3ca8fd97ae70608184979cf7300836f57ec2d6".toHexBytesInByteString() + + val transferInfos = Txs.newBuilder() + .setAmount("10") + .setTokenId("0") + .setTo("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP") + .build() + + val txObj = TxObject.newBuilder() + .setFrom("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP") + .addTxs(transferInfos) + .build() + + val fa12 = FA2Parameters.newBuilder() + .setEntrypoint("transfer") + .addTxsObject(txObj) + .build() + + val parameters = OperationParameters.newBuilder() + .setFa2Parameters(fa12) + .build() + + val transactionData = TransactionOperationData.newBuilder() + .setAmount(0) + .setDestination("KT1DYk1XDzHredJq1EyNkDindiWDqZyekXGj") + .setParameters(parameters) + .build() + + val transaction = Operation.newBuilder() + .setSource("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP") + .setFee(100000) + .setCounter(2993173) + .setGasLimit(100000) + .setStorageLimit(0) + .setKind(Operation.OperationKind.TRANSACTION) + .setTransactionOperationData(transactionData) + .build(); + + val operationList = OperationList.newBuilder() + .setBranch("BKvEAX9HXfJZWYfTQbR1C7B3ADoKY6a1aKVRF7qQqvc9hS8Rr3m") + .addOperations(transaction) + .build(); + + val signingInput = SigningInput.newBuilder() + .setPrivateKey(key) + .setOperationList(operationList) + .build() + + val result = AnySigner.sign(signingInput, TEZOS, SigningOutput.parser()) + + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.encoded.toByteArray())), + "1b1f9345dc9f77bd24b09034d1d2f9a28f02ac837f49db54b8d68341f53dc4b76c00fe2ce0cccc0214af521ad60c140c5589b4039247a08d0695d8b601a08d0600000136767f88850bae28bfb9f46b73c5e87ede4de12700ffff087472616e7366657200000066020000006107070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b5550020000003107070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555007070000000a552d24710d6c59383286700c6c2917b25a6c1fa8b587e593c289dd47704278796792f1e522c1623845ec991e292b0935445e6994850bd03f035a006c5ed93806" + ) + } + + @Test + fun testSigningFA12() { + val key = + "363265a0b3f06661001cab8b4f3ca8fd97ae70608184979cf7300836f57ec2d6".toHexBytesInByteString() + + val fa12 = FA12Parameters.newBuilder() + .setEntrypoint("transfer") + .setFrom("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP") + .setTo("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP") + .setValue("123") + .build() + + val parameters = OperationParameters.newBuilder() + .setFa12Parameters(fa12) + .build() + + val transactionData = TransactionOperationData.newBuilder() + .setAmount(0) + .setDestination("KT1EwXFWoG9bYebmF4pYw72aGjwEnBWefgW5") + .setParameters(parameters) + .build() + + val transaction = Operation.newBuilder() + .setSource("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP") + .setFee(100000) + .setCounter(2993172) + .setGasLimit(100000) + .setStorageLimit(0) + .setKind(Operation.OperationKind.TRANSACTION) + .setTransactionOperationData(transactionData) + .build(); + + val operationList = OperationList.newBuilder() + .setBranch("BL8euoCWqNCny9AR3AKjnpi38haYMxjei1ZqNHuXMn19JSQnoWp") + .addOperations(transaction) + .build(); + + val signingInput = SigningInput.newBuilder() + .setPrivateKey(key) + .setOperationList(operationList) + .build() + + val result = AnySigner.sign(signingInput, TEZOS, SigningOutput.parser()) + + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.encoded.toByteArray())), + "3756ef37b1be849e3114643f0aa5847cabf9a896d3bfe4dd51448de68e91da016c00fe2ce0cccc0214af521ad60c140c5589b4039247a08d0694d8b601a08d0600000145bd8a65cc48159d8ea60a55df735b7c5ad45f0e00ffff087472616e736665720000005907070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555007070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555000bb012914d768155fba2df319a81136e8e3e573b9cadb1676834490c90212615d271da029b6b0531e290e9063bcdb40bea43627af048b18e036f02be2b6b22fc8b307" + ) + } + @Test fun testSigningJSON() { val json = """ @@ -43,9 +155,13 @@ class TestTezosTransactionSigner { } } """ - val key = "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6f".toHexByteArray() + val key = + "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6f".toHexByteArray() val result = AnySigner.signJSON(json, key, TEZOS.value()) assertTrue(AnySigner.supportsJSON(TEZOS.value())) - assertEquals(result, "3756ef37b1be849e3114643f0aa5847cabf9a896d3bfe4dd51448de68e91da016b0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80992f001f44e810200429a986c8072a40a1f3a3e2ab5a5819bb1b2fb69993c5004837815b9dc55923e6c0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80993f001f44e810201000081faa75f741ef614b0e35fcc8c90dfa3b0b957210001b86398d5b9be737dca8e4106ea18d70e69b75e92f892fb283546a99152b8d7794b919c0fbf1c31de386069a60014491c0e7505adef5781cead1cfe6608030b") + assertEquals( + result, + "3756ef37b1be849e3114643f0aa5847cabf9a896d3bfe4dd51448de68e91da016b0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80992f001f44e810200429a986c8072a40a1f3a3e2ab5a5819bb1b2fb69993c5004837815b9dc55923e6c0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80993f001f44e810201000081faa75f741ef614b0e35fcc8c90dfa3b0b957210001b86398d5b9be737dca8e4106ea18d70e69b75e92f892fb283546a99152b8d7794b919c0fbf1c31de386069a60014491c0e7505adef5781cead1cfe6608030b" + ) } } diff --git a/src/Tezos/Address.cpp b/src/Tezos/Address.cpp index 62caf255523..e351ce4d776 100644 --- a/src/Tezos/Address.cpp +++ b/src/Tezos/Address.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Tezos/Address.h b/src/Tezos/Address.h index 88fb46bc79e..c939ee66276 100644 --- a/src/Tezos/Address.h +++ b/src/Tezos/Address.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Tezos/BinaryCoding.cpp b/src/Tezos/BinaryCoding.cpp index b00b8c3bd6e..1e1758bfee4 100644 --- a/src/Tezos/BinaryCoding.cpp +++ b/src/Tezos/BinaryCoding.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Tezos/BinaryCoding.h b/src/Tezos/BinaryCoding.h index 736f28edbbc..39d34885f7f 100644 --- a/src/Tezos/BinaryCoding.h +++ b/src/Tezos/BinaryCoding.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Tezos/Entry.cpp b/src/Tezos/Entry.cpp index 1006c26b5c2..71aa8246a81 100644 --- a/src/Tezos/Entry.cpp +++ b/src/Tezos/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Tezos/Entry.h b/src/Tezos/Entry.h index e5198945574..96bca2e2144 100644 --- a/src/Tezos/Entry.h +++ b/src/Tezos/Entry.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Tezos/Forging.cpp b/src/Tezos/Forging.cpp index 91f33014410..7d2cc57f7ce 100644 --- a/src/Tezos/Forging.cpp +++ b/src/Tezos/Forging.cpp @@ -4,6 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include "Forging.h" #include "Address.h" #include "BinaryCoding.h" #include "../Base58.h" @@ -14,8 +15,20 @@ #include using namespace TW; -using namespace TW::Tezos; -using namespace TW::Tezos::Proto; + +namespace { + +constexpr const char* gTezosContractAddressPrefix{"KT1"}; + +void encodePrefix(const std::string& address, Data& forged) { + const auto decoded = Base58::bitcoin.decodeCheck(address); + constexpr auto prefixSize{3}; + forged.insert(forged.end(), decoded.begin() + prefixSize, decoded.end()); +} + +} // namespace + +namespace TW::Tezos { // Forge the given boolean into a hex encoded string. Data forgeBool(bool input) { @@ -23,6 +36,39 @@ Data forgeBool(bool input) { return Data{result}; } +Data forgeInt32(int value, int len) { + Data out(len); + for (int i = len - 1; i >= 0; i--, value >>= 8) { + out[i] = (value & 0xFF); + } + return out; +} + +Data forgeString(const std::string& value, std::size_t len) { + auto bytes = data(value); + auto result = forgeInt32(static_cast(bytes.size()), static_cast(len)); + append(result, bytes); + return result; +} + +Data forgeEntrypoint(const std::string& value) { + if (value == "default") + return Data{0x00}; + else if (value == "root") + return Data{0x01}; + else if (value == "do") + return Data{0x02}; + else if (value == "set_delegate") + return Data{0x03}; + else if (value == "remove_delegate") + return Data{0x04}; + else { + Data forged{0xff}; + append(forged, forgeString(value, 1)); + return forged; + } +} + // Forge the given public key hash into a hex encoded string. // Note: This function supports tz1, tz2 and tz3 addresses. Data forgePublicKeyHash(const std::string& publicKeyHash) { @@ -41,12 +87,31 @@ Data forgePublicKeyHash(const std::string& publicKeyHash) { default: throw std::invalid_argument("Invalid Prefix"); } - const auto decoded = Base58::bitcoin.decodeCheck(publicKeyHash); - const auto prefixSize = 3; - forged.insert(forged.end(), decoded.begin() + prefixSize, decoded.end()); + encodePrefix(publicKeyHash, forged); return forged; } +Data forgeAddress(const std::string& address) { + if (address.size() < 3) { + throw std::invalid_argument("Invalid address size"); + } + auto prefix = address.substr(0, 3); + + if (prefix == "tz1" || prefix == "tz2" || prefix == "tz3") { + Data forged{0x00}; + append(forged, forgePublicKeyHash(address)); + return forged; + } + + if (prefix == gTezosContractAddressPrefix) { + Data forged{0x01}; + encodePrefix(address, forged); + forged.emplace_back(0x00); + return forged; + } + throw std::invalid_argument("Invalid Prefix"); +} + // Forge the given public key into a hex encoded string. Data forgePublicKey(PublicKey publicKey) { std::array prefix = {13, 15, 37, 217}; @@ -71,7 +136,8 @@ Data forgeZarith(uint64_t input) { } // Forge the given operation. -Data forgeOperation(const Operation& operation) { +Data forgeOperation(const Proto::Operation& operation) { + using namespace Proto; auto forged = Data(); auto source = Address(operation.source()); auto forgedSource = source.forge(); @@ -118,18 +184,110 @@ Data forgeOperation(const Operation& operation) { auto forgedAmount = forgeZarith(operation.transaction_operation_data().amount()); auto forgedDestination = Address(operation.transaction_operation_data().destination()).forge(); - forged.push_back(Operation_OperationKind_TRANSACTION); + forged.emplace_back(Operation_OperationKind_TRANSACTION); append(forged, forgedSource); append(forged, forgedFee); append(forged, forgedCounter); append(forged, forgedGasLimit); append(forged, forgedStorageLimit); append(forged, forgedAmount); - append(forged, forgeBool(false)); - append(forged, forgedDestination); - append(forged, forgeBool(false)); + if (!operation.transaction_operation_data().has_parameters()) { + append(forged, forgeBool(false)); + append(forged, forgedDestination); + append(forged, forgeBool(false)); + } else if (operation.transaction_operation_data().has_parameters()) { + append(forged, forgeAddress(operation.transaction_operation_data().destination())); + append(forged, forgeBool(true)); + auto& parameters = operation.transaction_operation_data().parameters(); + switch (parameters.parameters_case()) { + case OperationParameters::kFa12Parameters: + append(forged, forgeEntrypoint(parameters.fa12_parameters().entrypoint())); + append(forged, forgeArray(forgeMichelson(FA12ParameterToMichelson(parameters.fa12_parameters())))); + break; + case OperationParameters::kFa2Parameters: + append(forged, forgeEntrypoint(parameters.fa2_parameters().entrypoint())); + append(forged, forgeArray(forgeMichelson(FA2ParameterToMichelson(parameters.fa2_parameters())))); + break; + case OperationParameters::PARAMETERS_NOT_SET: + break; + } + } return forged; } throw std::invalid_argument("Invalid operation kind"); } + +Data forgePrim(const PrimValue& value) { + Data forged; + if (value.prim == "Pair") { + // https://tezos.gitlab.io/developer/encodings.html?highlight=pair#pairs + forged.reserve(2); + constexpr uint8_t nbArgs = 2; + // https://github.com/ecadlabs/taquito/blob/fd84d627171d24ce7ba81dd7b18763a95f16a99c/packages/taquito-local-forging/src/michelson/codec.ts#L195 + // https://github.com/baking-bad/netezos/blob/0bfd6db4e85ab1c99fb55503e476fe67cebd2dc5/Netezos/Forging/Local/LocalForge.Forgers.cs#L199 + const uint8_t preamble = static_cast(std::min(2 * nbArgs + static_cast(value.anots.size()) + 0x03, 9)); + forged.emplace_back(preamble); + forged.emplace_back(PrimType::Pair); + Data subForged; + for (auto&& cur : value.args) { + append(subForged, forgeMichelson(cur.value)); + } + append(forged, subForged); + } + return forged; +} + +Data forgeMichelson(const MichelsonValue::MichelsonVariant& value) { + auto visit_functor = [](const MichelsonValue::MichelsonVariant& value) -> Data { + if (std::holds_alternative(value)) { + return forgePrim(std::get(value)); + } else if (std::holds_alternative(value)) { + Data forged{1}; + append(forged, forgeString(std::get(value).string)); + return forged; + } else if (std::holds_alternative(value)) { + Data forged{0}; + auto res = int256_t(std::get(value)._int); + append(forged, forgeMichelInt(res)); + return forged; + } else if (std::holds_alternative(value)) { + return {}; + } else if (std::holds_alternative(value)) { + // array + Data forged{2}; + Data subForged; + auto array = std::get(value); + for (auto&& cur : array) { + std::visit([&subForged](auto&& arg) { append(subForged, forgeMichelson(arg)); }, cur); + } + append(forged, forgeArray(subForged)); + return forged; + } else { + throw std::invalid_argument("Invalid variant"); + } + }; + + return std::visit(visit_functor, value); +} + +Data forgeArray(const Data& data) { + auto forged = forgeInt32(static_cast(data.size())); + append(forged, data); + return forged; +} + +Data forgeMichelInt(const TW::int256_t& value) { + Data forged; + auto abs = boost::multiprecision::abs(value); + forged.emplace_back(static_cast(value.sign() < 0 ? (abs & 0x3f - 0x40) : (abs & 0x3f))); + abs >>= 6; + while (abs > 0) { + forged[forged.size() - 1] |= 0x80; + forged.emplace_back(static_cast(abs & 0x7F)); + abs >>= 7; + } + return forged; +} + +} // namespace TW::Tezos diff --git a/src/Tezos/Forging.h b/src/Tezos/Forging.h index 9e7b1125c4a..818ffce744a 100644 --- a/src/Tezos/Forging.h +++ b/src/Tezos/Forging.h @@ -6,16 +6,31 @@ #pragma once +#include "Michelson.h" +#include "uint256.h" #include "../PublicKey.h" #include "../proto/Tezos.pb.h" #include +#include +#include using namespace TW; -using namespace TW::Tezos::Proto; + +namespace TW::Tezos { Data forgeBool(bool input); -Data forgeOperation(const Operation& operation); +Data forgeOperation(const Proto::Operation& operation); +Data forgeAddress(const std::string& address); +Data forgeArray(const Data& data); Data forgePublicKeyHash(const std::string& publicKeyHash); Data forgePublicKey(PublicKey publicKey); Data forgeZarith(uint64_t input); +Data forgeInt32(int value, int len = 4); +Data forgeString(const std::string& value, std::size_t len = 4); +Data forgeEntrypoint(const std::string& value); +Data forgeMichelson(const MichelsonValue::MichelsonVariant& value); +Data forgeMichelInt(const TW::int256_t& value); +Data forgePrim(const PrimValue& value); + +} // namespace TW::Tezos diff --git a/src/Tezos/Michelson.cpp b/src/Tezos/Michelson.cpp new file mode 100644 index 00000000000..0b573885ebd --- /dev/null +++ b/src/Tezos/Michelson.cpp @@ -0,0 +1,32 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Michelson.h" + +namespace TW::Tezos { + +MichelsonValue::MichelsonVariant FA12ParameterToMichelson(const Proto::FA12Parameters& data) { + MichelsonValue::MichelsonVariant address = StringValue{.string = data.from()}; + MichelsonValue::MichelsonVariant to = StringValue{.string = data.to()}; + MichelsonValue::MichelsonVariant amount = IntValue{._int = data.value()}; + auto primTransferInfos = PrimValue{.prim = "Pair", .args{{to}, {amount}}}; + return PrimValue{.prim = "Pair", .args{{address}, {primTransferInfos}}}; +} + +MichelsonValue::MichelsonVariant FA2ParameterToMichelson(const Proto::FA2Parameters& data) { + auto& txObj = *data.txs_object().begin(); + MichelsonValue::MichelsonVariant from = StringValue{.string = txObj.from()}; + auto& txTransferInfos = txObj.txs(0); + MichelsonValue::MichelsonVariant tokenId = IntValue{._int = txTransferInfos.token_id()}; + MichelsonValue::MichelsonVariant amount = IntValue{._int = txTransferInfos.amount()}; + auto primTransferInfos = PrimValue{.prim = "Pair", .args{{tokenId}, {amount}}}; + MichelsonValue::MichelsonVariant to = StringValue{.string = txTransferInfos.to()}; + MichelsonValue::MichelsonVariant txs = MichelsonValue::MichelsonArray{PrimValue{.prim = "Pair", .args{{to}, {primTransferInfos}}}}; + auto primTxs = PrimValue{.prim = "Pair", .args{{from}, {txs}}}; + return MichelsonValue::MichelsonArray{primTxs}; +} + +} // namespace TW::Tezos diff --git a/src/Tezos/Michelson.h b/src/Tezos/Michelson.h new file mode 100644 index 00000000000..1e6d944c59d --- /dev/null +++ b/src/Tezos/Michelson.h @@ -0,0 +1,56 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include +#include +#include + +#include "../proto/Tezos.pb.h" + +#pragma once + +namespace TW::Tezos { + +enum PrimType : std::uint8_t { + Pair = 7, +}; + +struct MichelsonValue; + +struct PrimValue { + std::string prim; + std::vector args; + std::vector anots; +}; + +struct BytesValue { + std::string bytes; +}; + +struct StringValue { + std::string string; +}; + +struct IntValue { + std::string _int; +}; + +struct MichelsonValue { + using MichelsonArray = std::vector>; + using MichelsonVariant = std::variant< + PrimValue, + BytesValue, + StringValue, + IntValue, + MichelsonArray>; + MichelsonVariant value; +}; + +MichelsonValue::MichelsonVariant FA12ParameterToMichelson(const Proto::FA12Parameters& data); +MichelsonValue::MichelsonVariant FA2ParameterToMichelson(const Proto::FA2Parameters& data); + +} // namespace TW::Tezos diff --git a/src/Tezos/OperationList.cpp b/src/Tezos/OperationList.cpp index ff7780ed385..72fbb82ca57 100644 --- a/src/Tezos/OperationList.cpp +++ b/src/Tezos/OperationList.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Tezos/OperationList.h b/src/Tezos/OperationList.h index f7ddd5615ed..c3d0040f606 100644 --- a/src/Tezos/OperationList.h +++ b/src/Tezos/OperationList.h @@ -1,3 +1,9 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + #pragma once #include "../Data.h" diff --git a/src/Tezos/Signer.cpp b/src/Tezos/Signer.cpp index c695827b2cb..3ff02ed8e85 100644 --- a/src/Tezos/Signer.cpp +++ b/src/Tezos/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Tezos/Signer.h b/src/Tezos/Signer.h index 798d703ab21..e1a64844dbd 100644 --- a/src/Tezos/Signer.h +++ b/src/Tezos/Signer.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/proto/Tezos.proto b/src/proto/Tezos.proto index c09f70bd674..f5d9240e1e7 100644 --- a/src/proto/Tezos.proto +++ b/src/proto/Tezos.proto @@ -50,11 +50,42 @@ message Operation { } } +message FA12Parameters { + string entrypoint = 1; + string from = 2; + string to = 3; + string value = 4; +} + +message Txs { + string to = 1; + string token_id = 2; + string amount = 3; +} + +message TxObject { + string from = 1; + repeated Txs txs = 2; +} + +message FA2Parameters { + string entrypoint = 1; + repeated TxObject txs_object = 2; +} + +message OperationParameters { + oneof parameters { + FA12Parameters fa12_parameters = 1; + FA2Parameters fa2_parameters = 2; + } +} + // Transaction operation specific data. // Next field: 3 message TransactionOperationData { string destination = 1; int64 amount = 2; + OperationParameters parameters = 3; } // Reveal operation specific data. @@ -67,4 +98,4 @@ message RevealOperationData { // Next field: 2 message DelegationOperationData { string delegate = 1; -} \ No newline at end of file +} diff --git a/swift/Tests/Blockchains/TezosTests.swift b/swift/Tests/Blockchains/TezosTests.swift index a9416b97322..67a26a6c971 100644 --- a/swift/Tests/Blockchains/TezosTests.swift +++ b/swift/Tests/Blockchains/TezosTests.swift @@ -26,6 +26,93 @@ class TezosTests: XCTestCase { XCTAssertEqual(address.description, "tz1cG2jx3W4bZFeVGBjsTxUAG8tdpTXtE8PT") } + + public func testSigningFA12() { + let privateKeyData = Data(hexString: "363265a0b3f06661001cab8b4f3ca8fd97ae70608184979cf7300836f57ec2d6")! + + let branch = "BL8euoCWqNCny9AR3AKjnpi38haYMxjei1ZqNHuXMn19JSQnoWp" + var operationList = TezosOperationList() + operationList.branch = branch + + let transactionOperationData = TezosTransactionOperationData.with { + $0.amount = 0 + $0.destination = "KT1EwXFWoG9bYebmF4pYw72aGjwEnBWefgW5" + $0.parameters.fa12Parameters.entrypoint = "transfer"; + $0.parameters.fa12Parameters.from = "tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"; + $0.parameters.fa12Parameters.to = "tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"; + $0.parameters.fa12Parameters.value = "123"; + } + + let transactionOperation = TezosOperation.with { + $0.source = "tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP" + $0.fee = 100000 + $0.counter = 2993172 + $0.gasLimit = 100000 + $0.storageLimit = 0 + $0.kind = .transaction + $0.transactionOperationData = transactionOperationData + } + + operationList.operations = [ transactionOperation ] + + let input = TezosSigningInput.with { + $0.operationList = operationList + $0.privateKey = privateKeyData + } + + let output: TezosSigningOutput = AnySigner.sign(input: input, coin: .tezos) + let expected = "3756ef37b1be849e3114643f0aa5847cabf9a896d3bfe4dd51448de68e91da016c00fe2ce0cccc0214af521ad60c140c5589b4039247a08d0694d8b601a08d0600000145bd8a65cc48159d8ea60a55df735b7c5ad45f0e00ffff087472616e736665720000005907070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555007070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555000bb012914d768155fba2df319a81136e8e3e573b9cadb1676834490c90212615d271da029b6b0531e290e9063bcdb40bea43627af048b18e036f02be2b6b22fc8b307" + + XCTAssertEqual(output.encoded.hexString, expected) + } + + public func testSigningFA2() { + let privateKeyData = Data(hexString: "363265a0b3f06661001cab8b4f3ca8fd97ae70608184979cf7300836f57ec2d6")! + + let branch = "BKvEAX9HXfJZWYfTQbR1C7B3ADoKY6a1aKVRF7qQqvc9hS8Rr3m" + var operationList = TezosOperationList() + operationList.branch = branch + + let transferInfos = TezosTxs.with{ + $0.to = "tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP" + $0.tokenID = "0" + $0.amount = "10" + } + + let transactionOperationData = TezosTransactionOperationData.with { + $0.amount = 0 + $0.destination = "KT1DYk1XDzHredJq1EyNkDindiWDqZyekXGj" + $0.parameters.fa2Parameters.entrypoint = "transfer"; + $0.parameters.fa2Parameters.txsObject = [TezosTxObject.with{ + $0.from = "tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP" + $0.txs = [transferInfos] + }] + } + + + + let transactionOperation = TezosOperation.with { + $0.source = "tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP" + $0.fee = 100000 + $0.counter = 2993173 + $0.gasLimit = 100000 + $0.storageLimit = 0 + $0.kind = .transaction + $0.transactionOperationData = transactionOperationData + } + + operationList.operations = [ transactionOperation ] + + let input = TezosSigningInput.with { + $0.operationList = operationList + $0.privateKey = privateKeyData + } + + let output: TezosSigningOutput = AnySigner.sign(input: input, coin: .tezos) + let expected = "1b1f9345dc9f77bd24b09034d1d2f9a28f02ac837f49db54b8d68341f53dc4b76c00fe2ce0cccc0214af521ad60c140c5589b4039247a08d0695d8b601a08d0600000136767f88850bae28bfb9f46b73c5e87ede4de12700ffff087472616e7366657200000066020000006107070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b5550020000003107070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555007070000000a552d24710d6c59383286700c6c2917b25a6c1fa8b587e593c289dd47704278796792f1e522c1623845ec991e292b0935445e6994850bd03f035a006c5ed93806" + + XCTAssertEqual(output.encoded.hexString, expected) + } public func testSigning() { let privateKeyData = Data(hexString: "c6377a4cc490dc913fc3f0d9cf67d293a32df4547c46cb7e9e33c3b7b97c64d8")! diff --git a/tests/Tezos/ForgingTests.cpp b/tests/Tezos/ForgingTests.cpp index 187569f6021..ec6542fef3c 100644 --- a/tests/Tezos/ForgingTests.cpp +++ b/tests/Tezos/ForgingTests.cpp @@ -4,20 +4,20 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Tezos/BinaryCoding.h" -#include "Tezos/Address.h" #include "HDWallet.h" #include "HexCoding.h" -#include "PublicKey.h" #include "PrivateKey.h" +#include "PublicKey.h" +#include "Tezos/Address.h" +#include "Tezos/BinaryCoding.h" #include "Tezos/Forging.h" #include "proto/Tezos.pb.h" #include +#include #include #include -#include using namespace TW; using namespace TW::Tezos; @@ -40,41 +40,41 @@ TEST(Forging, ForgeBoolFalse) { TEST(Forging, ForgeZarithZero) { auto expected = "00"; - + auto output = forgeZarith(0); - + ASSERT_EQ(hex(output), hex(parse_hex(expected))); } TEST(Forging, ForgeZarithTen) { auto expected = "0a"; - + auto output = forgeZarith(10); - + ASSERT_EQ(output, parse_hex(expected)); } TEST(Forging, ForgeZarithTwenty) { auto expected = "14"; - + auto output = forgeZarith(20); - + ASSERT_EQ(output, parse_hex(expected)); } TEST(Forging, ForgeZarithOneHundredFifty) { auto expected = "9601"; - + auto output = forgeZarith(150); - + ASSERT_EQ(output, parse_hex(expected)); } TEST(Forging, ForgeZarithLarge) { auto expected = "bbd08001"; - + auto output = forgeZarith(2107451); - + ASSERT_EQ(hex(output), expected); } @@ -104,19 +104,43 @@ TEST(Forging, forge_tz3) { TEST(Forging, ForgePublicKey) { auto expected = "00311f002e899cdd9a52d96cb8be18ea2bbab867c505da2b44ce10906f511cff95"; - + auto privateKey = PrivateKey(parse_hex("c6377a4cc490dc913fc3f0d9cf67d293a32df4547c46cb7e9e33c3b7b97c64d8")); auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519); auto output = forgePublicKey(publicKey); - + ASSERT_EQ(hex(output), expected); } +TEST(Forging, ForgeInt32) { + auto expected = "01"; + ASSERT_EQ(hex(forgeInt32(1, 1)), expected); +} + +TEST(Forging, ForgeString) { + auto expected = "087472616e73666572"; + ASSERT_EQ(hex(forgeString("transfer", 1)), expected); +} + +TEST(Forging, ForgeEntrypoint) { + auto expected = "ff087472616e73666572"; + ASSERT_EQ(hex(forgeEntrypoint("transfer")), expected); +} + +TEST(Forging, ForgeMichelsonFA12) { + Tezos::Proto::FA12Parameters data; + data.set_entrypoint("transfer"); + data.set_from("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + data.set_to("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + data.set_value("123"); + auto v = FA12ParameterToMichelson(data); + ASSERT_EQ(hex(forgeMichelson(v)), "07070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555007070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555000bb01"); +} -TEST(TezosTransaction, forgeTransaction) { +TEST(TezosTransaction, forgeTransaction) { auto transactionOperationData = new TW::Tezos::Proto::TransactionOperationData(); - transactionOperationData -> set_amount(1); - transactionOperationData -> set_destination("tz1Yju7jmmsaUiG9qQLoYv35v5pHgnWoLWbt"); + transactionOperationData->set_amount(1); + transactionOperationData->set_destination("tz1Yju7jmmsaUiG9qQLoYv35v5pHgnWoLWbt"); auto transactionOperation = TW::Tezos::Proto::Operation(); transactionOperation.set_source("tz1XVJ8bZUXs7r5NV8dHvuiBhzECvLRLR3jW"); @@ -133,11 +157,61 @@ TEST(TezosTransaction, forgeTransaction) { ASSERT_EQ(hex(serialized.begin(), serialized.end()), expected); } +TEST(TezosTransaction, forgeTransactionFA12) { + auto transactionOperationData = new TW::Tezos::Proto::TransactionOperationData(); + transactionOperationData->set_amount(0); + transactionOperationData->set_destination("KT1EwXFWoG9bYebmF4pYw72aGjwEnBWefgW5"); + transactionOperationData->mutable_parameters()->mutable_fa12_parameters()->set_from("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + transactionOperationData->mutable_parameters()->mutable_fa12_parameters()->set_to("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + transactionOperationData->mutable_parameters()->mutable_fa12_parameters()->set_entrypoint("transfer"); + transactionOperationData->mutable_parameters()->mutable_fa12_parameters()->set_value("123"); + + auto transactionOperation = TW::Tezos::Proto::Operation(); + transactionOperation.set_source("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + transactionOperation.set_fee(100000); + transactionOperation.set_counter(2993172); + transactionOperation.set_gas_limit(100000); + transactionOperation.set_storage_limit(0); + transactionOperation.set_kind(TW::Tezos::Proto::Operation::TRANSACTION); + transactionOperation.set_allocated_transaction_operation_data(transactionOperationData); + + auto expected = "6c00fe2ce0cccc0214af521ad60c140c5589b4039247a08d0694d8b601a08d0600000145bd8a65cc48159d8ea60a55df735b7c5ad45f0e00ffff087472616e736665720000005907070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555007070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555000bb01"; + auto serialized = forgeOperation(transactionOperation); + + ASSERT_EQ(hex(serialized), expected); +} + +TEST(TezosTransaction, forgeTransactionFA2) { + auto transactionOperationData = new TW::Tezos::Proto::TransactionOperationData(); + transactionOperationData->set_amount(0); + transactionOperationData->set_destination("KT1DYk1XDzHredJq1EyNkDindiWDqZyekXGj"); + auto& fa2 = *transactionOperationData->mutable_parameters()->mutable_fa2_parameters(); + fa2.set_entrypoint("transfer"); + auto& txObject = *fa2.add_txs_object(); + txObject.set_from("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + auto& tx = *txObject.add_txs(); + tx.set_amount("10"); + tx.set_token_id("0"); + tx.set_to("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + + auto transactionOperation = TW::Tezos::Proto::Operation(); + transactionOperation.set_source("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + transactionOperation.set_fee(100000); + transactionOperation.set_counter(2993173); + transactionOperation.set_gas_limit(100000); + transactionOperation.set_storage_limit(0); + transactionOperation.set_kind(TW::Tezos::Proto::Operation::TRANSACTION); + transactionOperation.set_allocated_transaction_operation_data(transactionOperationData); + auto serialized = forgeOperation(transactionOperation); + auto expected = "6c00fe2ce0cccc0214af521ad60c140c5589b4039247a08d0695d8b601a08d0600000136767f88850bae28bfb9f46b73c5e87ede4de12700ffff087472616e7366657200000066020000006107070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b5550020000003107070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555007070000000a"; + ASSERT_EQ(hex(serialized), expected); +} + TEST(TezosTransaction, forgeReveal) { PublicKey publicKey = parsePublicKey("edpku9ZF6UUAEo1AL3NWy1oxHLL6AfQcGYwA5hFKrEKVHMT3Xx889A"); - + auto revealOperationData = new TW::Tezos::Proto::RevealOperationData(); - revealOperationData -> set_public_key(publicKey.bytes.data(), publicKey.bytes.size()); + revealOperationData->set_public_key(publicKey.bytes.data(), publicKey.bytes.size()); auto revealOperation = TW::Tezos::Proto::Operation(); revealOperation.set_source("tz1XVJ8bZUXs7r5NV8dHvuiBhzECvLRLR3jW"); @@ -147,7 +221,7 @@ TEST(TezosTransaction, forgeReveal) { revealOperation.set_storage_limit(257); revealOperation.set_kind(TW::Tezos::Proto::Operation::REVEAL); revealOperation.set_allocated_reveal_operation_data(revealOperationData); - + auto expected = "6b0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80992f001f44e810200429a986c8072a40a1f3a3e2ab5a5819bb1b2fb69993c5004837815b9dc55923e"; auto serialized = forgeOperation(revealOperation); @@ -190,4 +264,4 @@ TEST(TezosTransaction, forgeUndelegate) { auto serialized = forgeOperation(delegateOperation); ASSERT_EQ(hex(serialized.begin(), serialized.end()), expected); -} \ No newline at end of file +} diff --git a/tests/Tezos/TWAnySignerTests.cpp b/tests/Tezos/TWAnySignerTests.cpp index 08dedc82145..4cac74a7885 100644 --- a/tests/Tezos/TWAnySignerTests.cpp +++ b/tests/Tezos/TWAnySignerTests.cpp @@ -5,6 +5,7 @@ // file LICENSE at the root of the source code distribution tree. #include "HexCoding.h" +#include "Tezos/BinaryCoding.h" #include "proto/Tezos.pb.h" #include "../interface/TWTestUtilities.h" #include @@ -14,6 +15,70 @@ using namespace TW; namespace TW::Tezos::tests { +TEST(TWAnySignerTezos, SignFA12) { + // https://ghostnet.tzkt.io/ooTBu7DLbeC7DmVfXEsp896A6WTwimedbsM9QRqUVtqA8Vxt6D3/2993172 + auto key = parse_hex("363265a0b3f06661001cab8b4f3ca8fd97ae70608184979cf7300836f57ec2d6"); + + Proto::SigningInput input; + input.set_private_key(key.data(), key.size()); + auto& operations = *input.mutable_operation_list(); + operations.set_branch("BL8euoCWqNCny9AR3AKjnpi38haYMxjei1ZqNHuXMn19JSQnoWp"); + + auto& transaction = *operations.add_operations(); + auto& txData = *transaction.mutable_transaction_operation_data(); + txData.set_amount(0); + txData.set_destination("KT1EwXFWoG9bYebmF4pYw72aGjwEnBWefgW5"); + txData.mutable_parameters()->mutable_fa12_parameters()->set_entrypoint("transfer"); + txData.mutable_parameters()->mutable_fa12_parameters()->set_from("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + txData.mutable_parameters()->mutable_fa12_parameters()->set_to("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + txData.mutable_parameters()->mutable_fa12_parameters()->set_value("123"); + transaction.set_source("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + transaction.set_fee(100000); + transaction.set_counter(2993172); + transaction.set_gas_limit(100000); + transaction.set_storage_limit(0); + transaction.set_kind(Proto::Operation::TRANSACTION); + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeTezos); + ASSERT_EQ(hex(output.encoded()), "3756ef37b1be849e3114643f0aa5847cabf9a896d3bfe4dd51448de68e91da016c00fe2ce0cccc0214af521ad60c140c5589b4039247a08d0694d8b601a08d0600000145bd8a65cc48159d8ea60a55df735b7c5ad45f0e00ffff087472616e736665720000005907070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555007070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555000bb012914d768155fba2df319a81136e8e3e573b9cadb1676834490c90212615d271da029b6b0531e290e9063bcdb40bea43627af048b18e036f02be2b6b22fc8b307"); +} + +TEST(TWAnySignerTezos, SignFA2) { + // https://ghostnet.tzkt.io/onxLBoPaf23M3A8kHTwncSFG2GVXPfnGXUhkC8BhKj8QDdCEbng + auto key = parse_hex("363265a0b3f06661001cab8b4f3ca8fd97ae70608184979cf7300836f57ec2d6"); + + Proto::SigningInput input; + input.set_private_key(key.data(), key.size()); + auto& operations = *input.mutable_operation_list(); + operations.set_branch("BKvEAX9HXfJZWYfTQbR1C7B3ADoKY6a1aKVRF7qQqvc9hS8Rr3m"); + + auto& transaction = *operations.add_operations(); + + auto* transactionOperationData = transaction.mutable_transaction_operation_data(); + transactionOperationData->set_amount(0); + transactionOperationData->set_destination("KT1DYk1XDzHredJq1EyNkDindiWDqZyekXGj"); + + auto& fa2 = *transactionOperationData->mutable_parameters()->mutable_fa2_parameters(); + fa2.set_entrypoint("transfer"); + auto& txObject = *fa2.add_txs_object(); + txObject.set_from("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + auto& tx = *txObject.add_txs(); + tx.set_amount("10"); + tx.set_token_id("0"); + tx.set_to("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + + transaction.set_source("tz1ioz62kDw6Gm5HApeQtc1PGmN2wPBtJKUP"); + transaction.set_fee(100000); + transaction.set_counter(2993173); + transaction.set_gas_limit(100000); + transaction.set_storage_limit(0); + transaction.set_kind(Proto::Operation::TRANSACTION); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeTezos); + ASSERT_EQ(hex(output.encoded()), "1b1f9345dc9f77bd24b09034d1d2f9a28f02ac837f49db54b8d68341f53dc4b76c00fe2ce0cccc0214af521ad60c140c5589b4039247a08d0695d8b601a08d0600000136767f88850bae28bfb9f46b73c5e87ede4de12700ffff087472616e7366657200000066020000006107070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b5550020000003107070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555007070000000a552d24710d6c59383286700c6c2917b25a6c1fa8b587e593c289dd47704278796792f1e522c1623845ec991e292b0935445e6994850bd03f035a006c5ed93806"); +} + TEST(TWAnySignerTezos, Sign) { auto key = parse_hex("2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6f"); auto revealKey = parse_hex("311f002e899cdd9a52d96cb8be18ea2bbab867c505da2b44ce10906f511cff95"); From bca52a8802f4f61cd7f8b0ee3397e0345a938abf Mon Sep 17 00:00:00 2001 From: Alexey Pashinov Date: Wed, 31 Aug 2022 07:21:23 +0200 Subject: [PATCH 065/497] Add Everscale support (#2428) * Generate Everscale coin stub * Add cell stub * Add cell serialization * Add normalization address to lowercase test * Make workchain id as i8 * Add transfer action to Everscale proto * Normalize address implementation * Add WalletV3 code * Add cell deserialization * Extend BuilderData interface * Implement intoCell for BuilderData * Finish address implementation * Add CellSlice * Improve address calculation * Prepare and sign Everscale transaction * Fix dst address for external in_message * Fix message serialization to cell * Reveal magic number * Fix Everscale primitive types * Fix CellSlice; sign message with state init test * Add swift tests * Android address tests * WIP: fix conversion loses integer precision * Add coin address derivation/validation tests * Append workchain id to test address * Optimize moving vec to array * Replace map with vector for intermediate cell buffer * Short representation of wallet code * Integrate CellBuilder test into TW::Everscale namespace * Sign method should return serialized transaction boc instead cell data * Simplify parsing workchain id to avoid writing wasm tests * sync with upstream * Update network info * Use `Hash::sha256` instead of raw hasher. Fix lints * Refactor `clzU128` * Complete ios tests * Set rpc url Co-authored-by: Ivan Kalinin Co-authored-by: milerius Co-authored-by: Ivan Kalinin Co-authored-by: Adam V <13562139+catenocrypt@users.noreply.github.com> --- .../blockchains/CoinAddressDerivationTests.kt | 1 + .../everscale/TestEverscaleAddress.kt | 28 ++ .../everscale/TestEverscaleSigner.kt | 48 +++ coverage.stats | 2 +- docs/registry.md | 1 + include/TrustWalletCore/TWBlockchain.h | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 28 ++ src/Coin.cpp | 3 + src/Everscale/Address.cpp | 77 ++++ src/Everscale/Address.h | 51 +++ src/Everscale/Cell.cpp | 400 ++++++++++++++++++ src/Everscale/Cell.h | 66 +++ src/Everscale/CellBuilder.cpp | 260 ++++++++++++ src/Everscale/CellBuilder.h | 55 +++ src/Everscale/CellSlice.cpp | 59 +++ src/Everscale/CellSlice.h | 32 ++ src/Everscale/Entry.cpp | 36 ++ src/Everscale/Entry.h | 23 + src/Everscale/Messages.cpp | 146 +++++++ src/Everscale/Messages.h | 81 ++++ src/Everscale/Signer.cpp | 69 +++ src/Everscale/Signer.h | 25 ++ src/Everscale/Wallet.cpp | 82 ++++ src/Everscale/Wallet.h | 77 ++++ src/Everscale/WorkchainType.h | 16 + src/proto/Everscale.proto | 50 +++ swift/Tests/Blockchains/EverscaleTests.swift | 54 +++ swift/Tests/CoinAddressDerivationTests.swift | 3 + tests/CoinAddressDerivationTests.cpp | 3 + tests/CoinAddressValidationTests.cpp | 7 + tests/Everscale/AddressTests.cpp | 52 +++ tests/Everscale/CellBuilderTest.cpp | 121 ++++++ tests/Everscale/CellTests.cpp | 106 +++++ tests/Everscale/SignerTests.cpp | 88 ++++ tests/Everscale/TWAnyAddressTests.cpp | 30 ++ tests/Everscale/TWAnySignerTests.cpp | 38 ++ tests/Everscale/TWCoinTypeTests.cpp | 38 ++ 38 files changed, 2257 insertions(+), 1 deletion(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleAddress.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleSigner.kt create mode 100644 src/Everscale/Address.cpp create mode 100644 src/Everscale/Address.h create mode 100644 src/Everscale/Cell.cpp create mode 100644 src/Everscale/Cell.h create mode 100644 src/Everscale/CellBuilder.cpp create mode 100644 src/Everscale/CellBuilder.h create mode 100644 src/Everscale/CellSlice.cpp create mode 100644 src/Everscale/CellSlice.h create mode 100644 src/Everscale/Entry.cpp create mode 100644 src/Everscale/Entry.h create mode 100644 src/Everscale/Messages.cpp create mode 100644 src/Everscale/Messages.h create mode 100644 src/Everscale/Signer.cpp create mode 100644 src/Everscale/Signer.h create mode 100644 src/Everscale/Wallet.cpp create mode 100644 src/Everscale/Wallet.h create mode 100644 src/Everscale/WorkchainType.h create mode 100644 src/proto/Everscale.proto create mode 100644 swift/Tests/Blockchains/EverscaleTests.swift create mode 100644 tests/Everscale/AddressTests.cpp create mode 100644 tests/Everscale/CellBuilderTest.cpp create mode 100644 tests/Everscale/CellTests.cpp create mode 100644 tests/Everscale/SignerTests.cpp create mode 100644 tests/Everscale/TWAnyAddressTests.cpp create mode 100644 tests/Everscale/TWAnySignerTests.cpp create mode 100644 tests/Everscale/TWCoinTypeTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 5973cdd140a..55d6d14dd38 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -104,5 +104,6 @@ class CoinAddressDerivationTests { ECASH -> assertEquals("ecash:qpelrdn7a0hcucjlf9ascz3lkxv7r3rffgzn6x5377", address) NATIVEEVMOS -> assertEquals("evmos13u6g7vqgw074mgmf2ze2cadzvkz9snlwstd20d", address) NERVOS -> assertEquals("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02wectaumxn0664yw2jd53lqk4mxg3", address) + EVERSCALE -> assertEquals("0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04", address) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleAddress.kt new file mode 100644 index 00000000000..b09cfaff057 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleAddress.kt @@ -0,0 +1,28 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.everscale + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestEverscaleAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("5b59e0372d19b6355c73fa8cc708fa3301ae2ec21bb6277e8b79d386ccb7846f".toHexByteArray()) + val pubkey = key.publicKeyEd25519 + val address = AnyAddress(pubkey, CoinType.EVERSCALE) + val expected = AnyAddress("0:269fee242eb410786abe1777a14785c8bbeb1e34100c7570e17698b36ad66fb0", CoinType.EVERSCALE) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleSigner.kt new file mode 100644 index 00000000000..cb1d7266f92 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/everscale/TestEverscaleSigner.kt @@ -0,0 +1,48 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.everscale + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType.EVERSCALE +import wallet.core.jni.proto.Everscale +import wallet.core.jni.proto.Everscale.SigningOutput + +class TestEverscaleSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testSign() { + val transferMessage = Everscale.Transfer.newBuilder().apply { + bounce = false + behavior = Everscale.MessageBehavior.SimpleTransfer + amount = 100000000 + expiredAt = 1680770631 + to = "0:db18a67f4626f15ac0537a18445937f685f9b30184f0d7b28be4bdeb92d2fd90" + encodedContractData = "te6ccgEBAQEAKgAAUAAAAAFLqS2KOWKN+7Y5OSiKhKisiw6t/h2ovvR3WbapyAtrdctwupw=" + }.build() + val signingInput = Everscale.SigningInput.newBuilder().apply { + transfer = transferMessage + privateKey = ByteString.copyFrom("542bd4288352f1c6b270046f153d406aec054a0a06000ab9b36b5c6dd3050ad4".toHexByteArray()) + }.build() + + val output = AnySigner.sign(signingInput, EVERSCALE, SigningOutput.parser()) + + // Link to the external message: https://everscan.io/messages/73807b0a3ca2d8564c023dccd5b9da222a270f68338c6fc2c064dda376a2c59d + val expectedString = "te6ccgICAAIAAQAAAKoAAAHfiAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrAImASIQKH2jIwoA65IGC6aua4gAA4fFo/Nuxgb3sIRELhZnSXIS7IsE2E4D+8hk3EWGVZX+ICqlN/ka9DvXduhaXUlsUyF0MjgAAAAIHAABAGhCAG2MUz+jE3itYCm9DCIsm/tC/NmAwnhr2UXyXvXJaX7IIC+vCAAAAAAAAAAAAAAAAAAA" + assertEquals(output.encoded, expectedString) + } +} diff --git a/coverage.stats b/coverage.stats index a13c286215c..7aebde8602a 100644 --- a/coverage.stats +++ b/coverage.stats @@ -1 +1 @@ -94.7 +94.9 \ No newline at end of file diff --git a/docs/registry.md b/docs/registry.md index d6902661ca4..755c49365ac 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -37,6 +37,7 @@ This list is generated from [./registry.json](../registry.json) | 330 | Terra Classic | LUNC | | | | 354 | Polkadot | DOT | | | | 394 | Crypto.org | CRO | | | +| 396 | Everscale | EVER | | | | 397 | NEAR | NEAR | | | | 425 | Aion | AION | | | | 434 | Kusama | KSM | | | diff --git a/include/TrustWalletCore/TWBlockchain.h b/include/TrustWalletCore/TWBlockchain.h index 9fdc83f7727..eb289fc6d43 100644 --- a/include/TrustWalletCore/TWBlockchain.h +++ b/include/TrustWalletCore/TWBlockchain.h @@ -53,6 +53,7 @@ enum TWBlockchain { TWBlockchainRonin = 39, // Ethereum TWBlockchainKusama = 40, // Polkadot TWBlockchainNervos = 41, + TWBlockchainEverscale = 42, }; TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 4d473c64dc1..002b622c28a 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -115,6 +115,7 @@ enum TWCoinType { TWCoinTypeMeter = 18000, TWCoinTypeOKXChain = 996, TWCoinTypeNervos = 309, + TWCoinTypeEverscale = 396, }; /// Returns the blockchain for a coin type. diff --git a/registry.json b/registry.json index 7ef1312ff58..5ff19c81691 100644 --- a/registry.json +++ b/registry.json @@ -996,6 +996,34 @@ "documentation": "https://polkadot.js.org/api/substrate/rpc.html" } }, + { + "id": "everscale", + "name": "Everscale", + "coinId": 396, + "symbol": "EVER", + "decimals": 9, + "blockchain": "Everscale", + "derivation": [ + { + "path": "m/44'/396'/0'/0/0" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://everscan.io", + "txPath": "/transactions/", + "accountPath": "/accounts/", + "sampleTx": "781238b2b0d15cd4cd2e2a0a142753750cd5e1b2c8b506fcede75a90e02f1268", + "sampleAccount": "0:d2bf59964a05dee84a0dd1ddc0ad83ba44d49719cf843d689dc8b726d0fb59d8" + }, + "info": { + "url": "https://everscale.network/", + "source": "https://github.com/tonlabs/evernode-ds", + "rpc": "https://evercloud.dev", + "documentation": "https://docs.everos.dev/evernode-platform/products/evercloud/get-started" + } + }, { "id": "near", "name": "NEAR", diff --git a/src/Coin.cpp b/src/Coin.cpp index 609b97db6cd..c90996899b7 100644 --- a/src/Coin.cpp +++ b/src/Coin.cpp @@ -53,6 +53,7 @@ #include "Waves/Entry.h" #include "Zcash/Entry.h" #include "Zilliqa/Entry.h" +#include "Everscale/Entry.h" // end_of_coin_includes_marker_do_not_modify using namespace TW; @@ -99,6 +100,7 @@ Waves::Entry wavesDP; Zcash::Entry zcashDP; Zilliqa::Entry zilliqaDP; Nervos::Entry NervosDP; +Everscale::Entry EverscaleDP; // end_of_coin_dipatcher_declarations_marker_do_not_modify CoinEntry* coinDispatcher(TWCoinType coinType) { @@ -147,6 +149,7 @@ CoinEntry* coinDispatcher(TWCoinType coinType) { case TWBlockchainRonin: entry = &roninDP; break; case TWBlockchainKusama: entry = &kusamaDP; break; case TWBlockchainNervos: entry = &NervosDP; break; + case TWBlockchainEverscale: entry = &EverscaleDP; break; // end_of_coin_dipatcher_switch_marker_do_not_modify default: entry = nullptr; break; diff --git a/src/Everscale/Address.cpp b/src/Everscale/Address.cpp new file mode 100644 index 00000000000..177313473cd --- /dev/null +++ b/src/Everscale/Address.cpp @@ -0,0 +1,77 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include + +#include "Address.h" +#include "HexCoding.h" +#include "Wallet.h" +#include "WorkchainType.h" + +using namespace TW; + +namespace TW::Everscale { + +using MaybeWorkchain = std::optional>; + +MaybeWorkchain parseWorkchainId(const std::string& string) { + if (auto pos = string.find(':'); pos != std::string::npos) { + try { + auto workchainId = static_cast(std::stoi(string.substr(0, pos))); + return std::make_pair(workchainId, pos + 1); + } catch (...) { + // Do nothing and return empty value later + } + } + + return {}; +} + +bool Address::isValid(const std::string& string) noexcept { + auto parsed = parseWorkchainId(string); + if (!parsed.has_value()) { + return false; + } + + auto [workchainId, pos] = *parsed; + + if (workchainId != WorkchainType::Basechain && workchainId != WorkchainType::Masterchain) { + return false; + } + + if (string.size() != pos + hexAddrLen) { + return false; + } + + std::string addr = string.substr(pos); + return parse_hex(addr).size() == size; +} + +Address::Address(const std::string& string) { + if (!Address::isValid(string)) { + throw std::invalid_argument("Invalid address string!"); + } + + auto parsed = parseWorkchainId(string); + auto [parsedWorkchainId, pos] = *parsed; + + workchainId = parsedWorkchainId; + + const auto parsedHash = parse_hex(string.substr(pos)); + std::copy(begin(parsedHash), end(parsedHash), begin(hash)); +} + +Address::Address(const PublicKey& publicKey, int8_t workchainId) + : Address(InitData(publicKey).computeAddr(workchainId)) { +} + +std::string Address::string() const { + std::string address = std::to_string(workchainId) + ":" + hex(hash); + return address; +} + +} // namespace TW::Everscale diff --git a/src/Everscale/Address.h b/src/Everscale/Address.h new file mode 100644 index 00000000000..19dbcb7db72 --- /dev/null +++ b/src/Everscale/Address.h @@ -0,0 +1,51 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "../Data.h" +#include "../PublicKey.h" + +#include +#include + +namespace TW::Everscale { + +class Address { +public: + /// Number of bytes in an address + static const size_t size = Hash::sha256Size; + + /// Hex address length + static const size_t hexAddrLen = size * 2; + + /// Workchain ID (-1 for masterchain, 0 for base workchain) + std::int8_t workchainId; + /// StateInit hash + std::array hash{}; + + /// Determines whether a string makes a valid address. + [[nodiscard]] static bool isValid(const std::string& string) noexcept; + + /// Initializes an Everscale address with a string representation. + explicit Address(const std::string& string); + + /// Initializes an Everscale address with a public key and a workchain id. + explicit Address(const PublicKey& publicKey, int8_t workchainId); + + /// Initializes an Everscale address with its parts + explicit Address(int8_t workchainId, std::array hash) + : workchainId(workchainId), hash(hash) {} + + /// Returns a string representation of the address. + [[nodiscard]] std::string string() const; +}; + +inline bool operator==(const Address& lhs, const Address& rhs) { + return lhs.workchainId == rhs.workchainId && lhs.hash == rhs.hash; +} + +} // namespace TW::Everscale diff --git a/src/Everscale/Cell.cpp b/src/Everscale/Cell.cpp new file mode 100644 index 00000000000..41d9ec32a81 --- /dev/null +++ b/src/Everscale/Cell.cpp @@ -0,0 +1,400 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Cell.h" + +#include +#include +#include +#include + +#include "../BinaryCoding.h" + +#include +#include + +using namespace TW; + +namespace TW::Everscale { + +constexpr static uint32_t BOC_MAGIC = 0xb5ee9c72; + +uint16_t computeBitLen(const Data& data, bool aligned) { + auto bitLen = static_cast(data.size() * 8); + if (aligned) { + return bitLen; + } + + for (auto i = static_cast(data.size() - 1); i >= 0; --i) { + if (data[i] == 0) { + bitLen -= 8; + } else { + auto skip = 1; + uint8_t mask = 1; + while ((data[i] & mask) == 0) { + skip += 1; + mask <<= 1; + } + bitLen -= skip; + break; + } + } + return bitLen; +} + +struct Reader { + const uint8_t* _Nonnull buffer; + size_t bufferLen; + size_t offset = 0; + + explicit Reader(const uint8_t* _Nonnull buffer, size_t len) noexcept + : buffer(buffer), bufferLen(len) { + } + + void require(size_t bytes) const { + if (offset + bytes > bufferLen) { + throw std::runtime_error("unexpected eof"); + } + } + + void advance(size_t bytes) { + offset += bytes; + } + + const uint8_t* _Nonnull data() const { + return buffer + offset; + } + + size_t readNextUint(uint8_t len) { + const auto* _Nonnull p = data(); + advance(len); + + switch (len) { + case 1: + return static_cast(*p); + case 2: + return static_cast(decode16BE(p)); + case 3: + return static_cast(p[2]) | (static_cast(p[1]) << 8) | (static_cast(p[0]) << 16); + case 4: + return static_cast(decode32BE(p)); + default: + // Unreachable in valid cells + return 0; + } + } +}; + +std::shared_ptr Cell::fromBase64(const std::string& encoded) { + // `Hash::base64` trims \0 bytes from the end of the _decoded_ data, so + // raw transform is used here + using namespace boost::archive::iterators; + using It = transform_width, 8, 6>; + Data boc(It(begin(encoded)), It(end(encoded))); + return Cell::deserialize(boc.data(), boc.size()); +} + +std::shared_ptr Cell::deserialize(const uint8_t* _Nonnull data, size_t len) { + Reader reader(data, len); + + // Parse header + reader.require(6); + // 1. Magic + if (reader.readNextUint(sizeof(BOC_MAGIC)) != BOC_MAGIC) { + throw std::runtime_error("unknown magic"); + } + // 2. Flags + struct Flags { + uint8_t refSize : 3; + uint8_t : 2; // unused + bool hasCacheBits : 1; + bool hasCrc : 1; + bool indexIncluded : 1; + }; + + static_assert(sizeof(Flags) == 1, "flags must be represented as 1 byte"); + const auto flags = reinterpret_cast(reader.data())[0]; + const auto refSize = flags.refSize; + const auto offsetSize = reader.data()[1]; + reader.advance(2); + + // 3. Counters and root index + reader.require(refSize * 3 + offsetSize + refSize); + const auto cellCount = reader.readNextUint(refSize); + const auto rootCount = reader.readNextUint(refSize); + if (rootCount != 1) { + throw std::runtime_error("unsupported root count"); + } + if (rootCount > cellCount) { + throw std::runtime_error("root count is greater than cell count"); + } + const auto absent_count = reader.readNextUint(refSize); + if (absent_count > 0) { + throw std::runtime_error("absent cells are not supported"); + } + + reader.readNextUint(offsetSize); // total cell size + + const auto rootIndex = reader.readNextUint(refSize); + + // 4. Cell offsets (skip if specified) + if (flags.indexIncluded) { + reader.advance(cellCount * offsetSize); + } + + // 5. Deserialize cells + struct IntermediateCell { + uint16_t bitLen; + Data data; + std::vector references; + }; + + std::vector intermediate{}; + intermediate.reserve(cellCount); + + for (size_t i = 0; i < cellCount; ++i) { + struct Descriptor { + uint8_t refCount : 3; + bool exotic : 1; + bool storeHashes : 1; + uint8_t level : 3; + }; + + static_assert(sizeof(Descriptor) == 1, "cell descriptor must be represented as 1 byte"); + + reader.require(2); + const auto d1 = reinterpret_cast(reader.data())[0]; + if (d1.level != 0) { + throw std::runtime_error("non-zero level is not supported"); + } + if (d1.exotic) { + throw std::runtime_error("exotic cells are not supported"); + } + if (d1.refCount == 7 && d1.storeHashes) { + throw std::runtime_error("absent cells are not supported"); + } + if (d1.refCount > 4) { + throw std::runtime_error("invalid ref count"); + } + const auto d2 = reader.data()[1]; + const auto byteLen = (d2 >> 1) + (d2 & 0b1); + reader.advance(2); + + // Skip stored hashes + if (d1.storeHashes) { + reader.advance(sizeof(uint16_t) + Hash::sha256Size); + } + + reader.require(byteLen); + Data cellData(byteLen); + std::memcpy(cellData.data(), reader.data(), byteLen); + reader.advance(byteLen); + + std::vector references{}; + references.reserve(refSize * d1.refCount); + reader.require(refSize * d1.refCount); + for (size_t r = 0; r < d1.refCount; ++r) { + const auto index = reader.readNextUint(refSize); + if (index > cellCount || index <= i) { + throw std::runtime_error("invalid child index"); + } + + references.push_back(index); + } + + const auto bitLen = computeBitLen(cellData, (d2 & 0b1) == 0); + intermediate.emplace_back( + IntermediateCell{ + .bitLen = bitLen, + .data = std::move(cellData), + .references = std::move(references), + }); + } + + std::unordered_map doneCells{}; + + size_t index = cellCount; + for (auto it = intermediate.rbegin(); it != intermediate.rend(); ++it, --index) { + auto& raw = *it; + + Cell::Refs references{}; + for (size_t r = 0; r < raw.references.size(); ++r) { + const auto child = doneCells.find(raw.references[r]); + if (child == doneCells.end()) { + throw std::runtime_error("child cell not found"); + } + references[r] = child->second; + } + + auto cell = std::make_shared(raw.bitLen, std::move(raw.data), raw.references.size(), std::move(references)); + cell->finalize(); + doneCells.emplace(index - 1, cell); + } + + const auto root = doneCells.find(rootIndex); + if (root == doneCells.end()) { + throw std::runtime_error("root cell not found"); + } + return std::move(root->second); +} + +class SerializationContext { +public: + static SerializationContext build(const Cell& cell) { + SerializationContext ctx{}; + fillContext(cell, ctx); + return ctx; + } + + void encode(Data& os) const { + os.reserve(os.size() + HEADER_SIZE + cellsSize); + + const auto cellCount = static_cast(reversedCells.size()); + + // Write header + encode32BE(BOC_MAGIC, os); + os.push_back(REF_SIZE); + os.push_back(OFFSET_SIZE); + encode16BE(static_cast(cellCount), os); + encode16BE(1, os); // root count + encode16BE(0, os); // absent cell count + encode16BE(static_cast(cellsSize), os); + encode16BE(0, os); // root cell index + + // Write cells + size_t i = cellCount - 1; + while (true) { + const auto& cell = *reversedCells[i]; + + // Write cell data + const auto [d1, d2] = cell.getDescriptorBytes(); + os.push_back(d1); + os.push_back(d2); + os.insert(os.end(), cell.data.begin(), cell.data.end()); + + // Write cell references + for (const auto& child : cell.references) { + if (child == nullptr) { + break; + } + + // Map cell hash to index (which must be presented) + const auto it = indices.find(child->hash); + assert(it != indices.end()); + + encode16BE(cellCount - it->second - 1, os); + } + + if (i == 0) { + break; + } else { + --i; + } + } + } + +private: + // uint16_t will be enough for wallet transactions (e.g. 64k is the size of the whole elector) + using ref_t = uint16_t; + using offset_t = uint16_t; + + constexpr static uint8_t REF_SIZE = sizeof(ref_t); + constexpr static uint8_t OFFSET_SIZE = sizeof(offset_t); + constexpr static size_t HEADER_SIZE = + /*magic*/ sizeof(BOC_MAGIC) + + /*ref_size*/ 1 + + /*offset_size*/ 1 + + /*cell_count*/ REF_SIZE + + /*root_count*/ REF_SIZE + + /*absent_count*/ REF_SIZE + + /*data_size*/ OFFSET_SIZE + + /*root_cell_index*/ REF_SIZE; + + size_t cellsSize = 0; + ref_t index = 0; + std::map indices{}; + std::vector reversedCells{}; + + static void fillContext(const Cell& cell, SerializationContext& ctx) { + if (ctx.indices.find(cell.hash) != ctx.indices.end()) { + return; + } + + for (const auto& ref : cell.references) { + if (ref == nullptr) { + break; + } + fillContext(*ref, ctx); + } + + ctx.indices.insert(std::make_pair(cell.hash, ctx.index++)); + ctx.reversedCells.emplace_back(&cell); + ctx.cellsSize += cell.serializedSize(REF_SIZE); + } +}; + +void Cell::serialize(Data& os) const { + assert(finalized); + const auto ctx = SerializationContext::build(*this); + ctx.encode(os); +} + +void Cell::finalize() { + if (finalized) { + return; + } + + if (bitLen > Cell::MAX_BITS || refCount > Cell::MAX_REFS) { + throw std::invalid_argument("invalid cell"); + } + + // Finalize child cells and update current cell depth + // NOTE: Use before context creation to reduce stack size + for (const auto& ref : references) { + if (ref == nullptr) { + break; + } + ref->finalize(); + depth = std::max(depth, static_cast(ref->depth + 1)); + } + + // Compute cell hash + const auto dataSize = std::min(data.size(), static_cast((bitLen + 7) / 8)); + + Data normalized{}; + normalized.reserve(/* descriptor bytes */ 2 + dataSize + refCount * (sizeof(uint16_t) + Hash::sha256Size)); + + // Write descriptor bytes + const auto [d1, d2] = getDescriptorBytes(); + normalized.push_back(d1); + normalized.push_back(d2); + std::copy(data.begin(), std::next(data.begin(), static_cast(dataSize)), std::back_inserter(normalized)); + + // Write all children depths + for (const auto& ref : references) { + if (ref == nullptr) { + break; + } + encode16BE(ref->depth, normalized); + } + + // Write all children hashes + for (const auto& ref : references) { + if (ref == nullptr) { + break; + } + std::copy(ref->hash.begin(), ref->hash.end(), std::back_inserter(normalized)); + } + + // Done + const auto computedHash = Hash::sha256(normalized); + assert(computedHash.size() == Hash::sha256Size); + + std::copy(computedHash.begin(), computedHash.end(), hash.begin()); + finalized = true; +} + +} // namespace TW::Everscale diff --git a/src/Everscale/Cell.h b/src/Everscale/Cell.h new file mode 100644 index 00000000000..565fd4daea5 --- /dev/null +++ b/src/Everscale/Cell.h @@ -0,0 +1,66 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include +#include + +#include + +#include "../Data.h" +#include "../Hash.h" + +namespace TW::Everscale { + +class Cell { +public: + constexpr static uint16_t MAX_BITS = 1023; + constexpr static uint8_t MAX_REFS = 4; + + using Ref = std::shared_ptr; + using Refs = std::array; + using CellHash = std::array; + + bool finalized = false; + uint16_t bitLen = 0; + std::vector data{}; + uint8_t refCount = 0; + Refs references{}; + + uint16_t depth = 0; + CellHash hash{}; + + Cell() = default; + + Cell(uint16_t bitLen, std::vector data, uint8_t refCount, Refs references) + : bitLen(bitLen), data(std::move(data)), refCount(refCount), references(std::move(references)) {} + + // Deserialize from Base64 + static std::shared_ptr fromBase64(const std::string& encoded); + + // Deserialize from BOC representation + static std::shared_ptr deserialize(const uint8_t* _Nonnull data, size_t len); + + // Serialize to binary stream + void serialize(Data& os) const; + + // Compute cell depth and hash + void finalize(); + + [[nodiscard]] inline std::pair getDescriptorBytes() const noexcept { + const uint8_t d1 = refCount; + const uint8_t d2 = (static_cast(bitLen >> 2) & 0b11111110) | (bitLen % 8 != 0); + return std::pair{d1, d2}; + } + + [[nodiscard]] inline size_t serializedSize(uint8_t refSize) const noexcept { + return 2 + (bitLen + 7) / 8 + refCount * refSize; + } +}; + +} // namespace TW::Everscale diff --git a/src/Everscale/CellBuilder.cpp b/src/Everscale/CellBuilder.cpp new file mode 100644 index 00000000000..8ddc3ccbc94 --- /dev/null +++ b/src/Everscale/CellBuilder.cpp @@ -0,0 +1,260 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "CellBuilder.h" +#include "Cell.h" + +#include +#include +#include + +#include "../BinaryCoding.h" + +using namespace TW; + +namespace TW::Everscale { + +CellBuilder::CellBuilder(Data& appendedData, uint16_t bits) { + assert(bits <= appendedData.size() * 8); + assert(bits < Cell::MAX_BITS); + assert(bits % 8 == 0); + + appendedData.resize(bits / 8); + + data = appendedData; + bitLen = bits; + references = {}; +} + +void CellBuilder::appendBitZero() { + Data appendedData{0x00}; + appendRaw(appendedData, 1); +} + +void CellBuilder::appendBitOne() { + Data appendedData{0xFF}; + appendRaw(appendedData, 1); +} + +void CellBuilder::appendBitBool(bool bit) { + auto getAppendedData = [](bool bit) { + if (bit) { + return Data{0xFF}; + } else { + return Data{0x00}; + } + }; + auto appendedData = getAppendedData(bit); + appendRaw(appendedData, 1); +} + +void CellBuilder::appendU8(uint8_t value) { + Data appendedData{value}; + appendRaw(appendedData, 8); +} + +void CellBuilder::appendU32(uint32_t value) { + Data appendedData; + encode32BE(value, appendedData); + appendRaw(appendedData, 32); +} + +void CellBuilder::appendU64(uint64_t value) { + Data appendedData; + encode64BE(value, appendedData); + appendRaw(appendedData, 64); +} + +void CellBuilder::appendU128(const uint128_t& value) { + uint8_t bits = 4; + uint16_t bytes = 16 - clzU128(value) / 8; + + appendBits(bytes, bits); + + Data encodedValue; + encode128BE(value, encodedValue); + + auto offset = static_cast(encodedValue.size() - bytes); + + Data appendedData(encodedValue.begin() + offset, encodedValue.end()); + appendRaw(appendedData, bytes * 8); +} + +void CellBuilder::appendI8(int8_t value) { + Data appendedData{static_cast(value)}; + appendRaw(appendedData, 8); +} + +void CellBuilder::appendBits(uint64_t value, uint8_t bits) { + assert(bits >= 1 && bits <= 7); + + Data appendedData; + + auto val = static_cast(value << (8 - bits)); + appendedData.push_back(val); + + appendRaw(appendedData, bits); +} + +void CellBuilder::appendRaw(const Data& appendedData, uint16_t bits) { + if (appendedData.size() * 8 < bits) { + throw std::invalid_argument("invalid builder data"); + } else if (bitLen + bits > Cell::MAX_BITS) { + throw std::runtime_error("cell data overflow"); + } else if (bits != 0) { + if ((bitLen % 8) == 0) { + if ((bits % 8) == 0) { + appendWithoutShifting(appendedData, bits); + } else { + appendWithSliceShifting(appendedData, bits); + } + } else { + appendWithDoubleShifting(appendedData, bits); + } + } + assert(bitLen <= Cell::MAX_BITS); + assert(data.size() * 8 <= Cell::MAX_BITS + 1); +} + +void CellBuilder::prependRaw(Data& appendedData, uint16_t bits) { + if (bits != 0) { + auto buffer = CellBuilder(appendedData, bits); + buffer.appendRaw(data, bitLen); + + data = buffer.data; + bitLen = buffer.bitLen; + } +} + +void CellBuilder::appendReferenceCell(std::shared_ptr child) { + if (child) { + if (references.size() + 1 > Cell::MAX_REFS) { + throw std::runtime_error("cell refs overflow"); + } + references.emplace_back(std::move(child)); + } +} + +void CellBuilder::appendBuilder(const CellBuilder& builder) { + appendRaw(builder.data, builder.bitLen); + for (const auto& reference : builder.references) { + appendReferenceCell(reference); + } +} + +void CellBuilder::appendCellSlice(const CellSlice& other) { + Data appendedData(other.cell->data); + appendRaw(appendedData, other.cell->bitLen); + + for (const auto& cell : other.cell->references) { + appendReferenceCell(cell); + } +} + +Cell::Ref CellBuilder::intoCell() { + // Append tag + if (bitLen & 7) { + const auto mask = static_cast(0x80 >> (bitLen & 7)); + const auto l = bitLen / 8; + data[l] = static_cast((data[l] & ~mask) | mask); + } + + auto refCount = references.size(); + + Cell::Refs refs; + std::move(references.begin(), references.end(), refs.begin()); + + auto cell = std::make_shared(bitLen, std::move(data), refCount, std::move(refs)); + cell->finalize(); + + bitLen = 0; + refCount = 0; + + return cell; +} + +void CellBuilder::appendWithoutShifting(const Data& appendedData, uint16_t bits) { + assert(bits % 8 == 0); + assert(bitLen % 8 == 0); + + data.resize(bitLen / 8); + data.insert(data.end(), appendedData.begin(), appendedData.end()); + bitLen += bits; + data.resize(bitLen / 8); +} + +void CellBuilder::appendWithSliceShifting(const Data& appendedData, uint16_t bits) { + assert(bits % 8 != 0); + assert(bitLen % 8 == 0); + + data.resize(bitLen / 8); + data.insert(data.end(), appendedData.begin(), appendedData.end()); + bitLen += bits; + data.resize(1 + bitLen / 8); + + data.back() &= ~static_cast(0xff >> (bits % 8)); +} + +void CellBuilder::appendWithDoubleShifting(const Data& appendedData, uint16_t bits) { + auto selfShift = bitLen % 8; + data.resize(1 + bitLen / 8); + bitLen += bits; + + // yyyyy000 -> 00000000 000yyyyy + auto y = static_cast(data.back() >> (8 - selfShift)); + data.pop_back(); + + for (const auto x : appendedData) { + // 00000000 000yyyyy -> 000yyyyy xxxxxxxx + y = static_cast(y << 8) | x; + // 000yyyyy xxxxxxxx -> 00000000 yyyyyxxx + data.push_back(static_cast(y >> selfShift)); + } + // 00000000 yyyyyxxx + data.push_back(static_cast(y << (8 - selfShift))); + + auto shift = bitLen % 8; + if (shift == 0) { + data.resize(bitLen / 8); + } else { + data.resize(bitLen / 8 + 1); + data.back() &= ~static_cast(0xff >> (bitLen % 8)); + } +} + +uint8_t CellBuilder::clzU128(const uint128_t& u) { + auto hi = static_cast(u >> 64); + auto lo = static_cast(u); + + if (lo == 0 && hi == 0) { + return 128; + } else if (hi == 0) { + return static_cast(std::countl_zero(lo) + 64); + } else { + return static_cast(std::countl_zero(hi)); + } +} + +void CellBuilder::encode128BE(const uint128_t& val, Data& data) { + data.emplace_back(static_cast((val >> 120))); + data.emplace_back(static_cast((val >> 112))); + data.emplace_back(static_cast((val >> 104))); + data.emplace_back(static_cast((val >> 96))); + data.emplace_back(static_cast((val >> 88))); + data.emplace_back(static_cast((val >> 80))); + data.emplace_back(static_cast((val >> 72))); + data.emplace_back(static_cast((val >> 64))); + data.emplace_back(static_cast((val >> 56))); + data.emplace_back(static_cast((val >> 48))); + data.emplace_back(static_cast((val >> 40))); + data.emplace_back(static_cast((val >> 32))); + data.emplace_back(static_cast((val >> 24))); + data.emplace_back(static_cast((val >> 16))); + data.emplace_back(static_cast((val >> 8))); + data.emplace_back(static_cast(val)); +} + +} // namespace TW::Everscale diff --git a/src/Everscale/CellBuilder.h b/src/Everscale/CellBuilder.h new file mode 100644 index 00000000000..8b192ec42b3 --- /dev/null +++ b/src/Everscale/CellBuilder.h @@ -0,0 +1,55 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include +#include + +#include "Cell.h" +#include "CellSlice.h" + +namespace TW::Everscale { + +class CellBuilder { + uint16_t bitLen = 0; + std::vector data{}; + std::vector references{}; + +public: + using uint128_t = boost::multiprecision::uint128_t; + + CellBuilder() = default; + CellBuilder(Data& appendedData, uint16_t bits); + + void appendBitZero(); + void appendBitOne(); + void appendU8(uint8_t value); + void appendBitBool(bool bit); + void appendU32(uint32_t value); + void appendU64(uint64_t value); + void appendU128(const uint128_t& value); + void appendI8(int8_t value); + void appendBits(uint64_t value, uint8_t bits); + void appendRaw(const Data& appendedData, uint16_t bits); + void prependRaw(Data& appendedData, uint16_t bits); + void appendReferenceCell(Cell::Ref child); + void appendBuilder(const CellBuilder& builder); + void appendCellSlice(const CellSlice& other); + + Cell::Ref intoCell(); + +private: + void appendWithoutShifting(const Data& data, uint16_t bits); + void appendWithSliceShifting(const Data& data, uint16_t bits); + void appendWithDoubleShifting(const Data& data, uint16_t bits); + + static uint8_t clzU128(const uint128_t& u); + static void encode128BE(const uint128_t& value, Data& data); +}; + +} // namespace TW::Everscale diff --git a/src/Everscale/CellSlice.cpp b/src/Everscale/CellSlice.cpp new file mode 100644 index 00000000000..346f4a65365 --- /dev/null +++ b/src/Everscale/CellSlice.cpp @@ -0,0 +1,59 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "CellSlice.h" + +#include + +#include "../BinaryCoding.h" + +using namespace TW; + +namespace TW::Everscale { + +uint32_t CellSlice::getNextU32() { + const auto bytes = getNextBytes(sizeof(uint32_t)); + return decode32BE(bytes.data()); +} + +Data CellSlice::getNextBytes(uint8_t bytes) { + if (bytes == 0) { + return Data{}; + } + require(bytes * 8); + Data result{}; + result.reserve(bytes); + + const size_t q = dataOffset / 8; + const auto r = dataOffset % 8; + const auto invR = 8 - r; + + dataOffset += bytes * 8; + + if (r == 0) { + const auto begin = cell->data.begin() + q; + const auto end = begin + bytes; + std::copy(begin, end, std::back_inserter(result)); + return result; + } + + for (size_t byte = q; byte < q + bytes; ++byte) { + auto bits = static_cast(static_cast(cell->data[byte]) << 8); + if (byte + 1 < cell->data.size()) { + bits |= static_cast(cell->data[byte + 1]); + } + result.push_back(static_cast(bits >> invR)); + } + return result; +} + +void CellSlice::require(uint16_t bits) const { + if (dataOffset + bits > cell->bitLen) { + throw std::runtime_error("cell data underflow"); + } +} + +} // namespace TW::Everscale diff --git a/src/Everscale/CellSlice.h b/src/Everscale/CellSlice.h new file mode 100644 index 00000000000..38c4598b9a5 --- /dev/null +++ b/src/Everscale/CellSlice.h @@ -0,0 +1,32 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include +#include + +#include "Cell.h" + +namespace TW::Everscale { + +class CellSlice { +public: + const Cell* _Nonnull cell; + uint16_t dataOffset = 0; + + explicit CellSlice(const Cell* _Nonnull cell) noexcept + : cell(cell) {} + + uint32_t getNextU32(); + Data getNextBytes(uint8_t bytes); + +private: + void require(uint16_t bits) const; +}; + +} // namespace TW::Everscale diff --git a/src/Everscale/Entry.cpp b/src/Everscale/Entry.cpp new file mode 100644 index 00000000000..e17aa9d5997 --- /dev/null +++ b/src/Everscale/Entry.cpp @@ -0,0 +1,36 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Entry.h" + +#include "Address.h" +#include "Signer.h" +#include "WorkchainType.h" + +using namespace TW; +using namespace std; + +namespace TW::Everscale { + +// Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. + +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { + return Address::isValid(address); +} + +string Entry::normalizeAddress([[maybe_unused]] TWCoinType coin, const string& address) const { + return Address(address).string(); +} + +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { + return Address(publicKey, WorkchainType::Basechain).string(); +} + +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { + signTemplate(dataIn, dataOut); +} + +} // namespace TW::Everscale diff --git a/src/Everscale/Entry.h b/src/Everscale/Entry.h new file mode 100644 index 00000000000..12daffaa0e9 --- /dev/null +++ b/src/Everscale/Entry.h @@ -0,0 +1,23 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "../CoinEntry.h" + +namespace TW::Everscale { + +/// Entry point for implementation of Everscale coin. +/// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file +class Entry : public CoinEntry { +public: + virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + virtual std::string normalizeAddress(TWCoinType coin, const std::string& address) const; + virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* d) const; + virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; +}; + +} // namespace TW::Everscale diff --git a/src/Everscale/Messages.cpp b/src/Everscale/Messages.cpp new file mode 100644 index 00000000000..a20ee263f08 --- /dev/null +++ b/src/Everscale/Messages.cpp @@ -0,0 +1,146 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Messages.h" +#include "WorkchainType.h" + +using namespace TW; + +namespace TW::Everscale { + +void ExternalInboundMessageHeader::writeTo(CellBuilder& builder) const { + builder.appendBitOne(); + builder.appendBitZero(); + + // addr src (none) + builder.appendRaw(Data{0x00}, 2); + + // addr dst + Data dstAddr(_dst.hash.begin(), _dst.hash.end()); + + Data prefix{0x80}; + builder.appendRaw(prefix, 2); + + builder.appendBitZero(); + builder.appendI8(_dst.workchainId); + builder.appendRaw(dstAddr, 256); + + // fee + builder.appendU128(_importFee); +} + +void InternalMessageHeader::writeTo(CellBuilder& builder) const { + // tag + builder.appendBitZero(); + + builder.appendBitBool(_ihrDisabled); + builder.appendBitBool(_bounce); + builder.appendBitBool(_bounced); + + // addr src (none) + builder.appendRaw(Data{0x00}, 2); + + // addr dst + Data dstAddr(_dst.hash.begin(), _dst.hash.end()); + + Data prefix{0x80}; + builder.appendRaw(prefix, 2); + + builder.appendBitZero(); + builder.appendI8(_dst.workchainId); + builder.appendRaw(dstAddr, 256); + + // value + builder.appendU128(_value); + builder.appendBitZero(); + + // fee + builder.appendU128(_ihrFee); + builder.appendU128(_fwdFee); + + // created + builder.appendU64(_createdLt); + builder.appendU32(_createdAt); +} + +Cell::Ref Message::intoCell() const { + CellBuilder builder; + + // write Header + _header->writeTo(builder); + + // write StateInit + if (_init.has_value()) { + auto initBuilder = _init.value().writeTo(); + + builder.appendBitOne(); + builder.appendBitZero(); + builder.appendBuilder(initBuilder); + } else { + builder.appendBitZero(); + } + + // write Body + if (_body.has_value()) { + builder.appendBitZero(); + builder.appendCellSlice(_body.value()); + } else { + builder.appendBitZero(); + } + + return builder.intoCell(); +} + +Data createSignedMessage(PublicKey& publicKey, PrivateKey& key, bool bounce, uint32_t flags, uint64_t amount, uint32_t expiredAt, + Address to, const Cell::Ref& contractData) { + auto getInitData = [](const PublicKey& publicKey, const Cell::Ref& contractData) { + if (contractData != nullptr) { + auto cellSlice = CellSlice(contractData.get()); + return std::make_pair(InitData(cellSlice), /* withInitState */ false); + } else { + return std::make_pair(InitData(publicKey), /* withInitState */ true); + } + }; + + auto [initData, withInitState] = getInitData(publicKey, contractData); + + auto gift = Wallet::Gift{ + .bounce = bounce, + .amount = amount, + .to = to, + .flags = static_cast(flags), + }; + + auto payload = initData.makeTransferPayload(expiredAt, gift); + + auto payloadCopy = payload; + auto payloadCell = payloadCopy.intoCell(); + + Data data(payloadCell->hash.begin(), payloadCell->hash.end()); + auto signature = key.sign(data, TWCurveED25519); + payload.prependRaw(signature, static_cast(signature.size()) * 8); + + auto header = std::make_shared(InitData(publicKey).computeAddr(WorkchainType::Basechain)); + auto message = Message(header); + + if (withInitState) { + message.setStateInit(initData.makeStateInit()); + } + + auto cell = payload.intoCell(); + auto body = CellSlice(cell.get()); + + message.setBody(body); + + const auto messageCell = message.intoCell(); + + Data result{}; + messageCell->serialize(result); + + return result; +} + +} // namespace TW::Everscale diff --git a/src/Everscale/Messages.h b/src/Everscale/Messages.h new file mode 100644 index 00000000000..345f75667ec --- /dev/null +++ b/src/Everscale/Messages.h @@ -0,0 +1,81 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include + +#include "Address.h" +#include "CellBuilder.h" +#include "CellSlice.h" +#include "Wallet.h" + +#include "../PrivateKey.h" + +namespace TW::Everscale { + +using uint128_t = CellBuilder::uint128_t; + +class CommonMsgInfo { +public: + virtual void writeTo(CellBuilder& builder) const = 0; + + virtual ~CommonMsgInfo() = default; +}; + +class ExternalInboundMessageHeader : public CommonMsgInfo { + Address _dst; + uint128_t _importFee{}; + +public: + explicit ExternalInboundMessageHeader(Address dst) + : _dst(dst) {} + + void writeTo(CellBuilder& builder) const override; +}; + +class InternalMessageHeader : public CommonMsgInfo { + bool _ihrDisabled; + bool _bounce; + Address _dst; + uint128_t _value; + + bool _bounced{}; + uint128_t _ihrFee{}; + uint128_t _fwdFee{}; + uint64_t _createdLt{}; + uint32_t _createdAt{}; + +public: + InternalMessageHeader(bool ihrDisabled, bool bounce, Address dst, uint64_t value) + : _ihrDisabled(ihrDisabled), _bounce(bounce), _dst(dst), _value(static_cast(value)) {} + + void writeTo(CellBuilder& builder) const override; +}; + +class Message { +private: + std::shared_ptr _header; + + std::optional _init{}; + std::optional _body{}; + +public: + using HeaderRef = std::shared_ptr; + + explicit Message(HeaderRef header) + : _header(std::move(header)) {} + + [[nodiscard]] Cell::Ref intoCell() const; + inline void setBody(CellSlice body) { _body = body; } + inline void setStateInit(const StateInit& stateInit) { _init = stateInit; } +}; + +Data createSignedMessage(PublicKey& publicKey, PrivateKey& key, bool bounce, uint32_t flags, uint64_t amount, + uint32_t expiredAt, Address destination, const Cell::Ref& contractData); + +} // namespace TW::Everscale diff --git a/src/Everscale/Signer.cpp b/src/Everscale/Signer.cpp new file mode 100644 index 00000000000..1f2a0fb9d10 --- /dev/null +++ b/src/Everscale/Signer.cpp @@ -0,0 +1,69 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Signer.h" +#include "Address.h" +#include "Messages.h" + +#include "../Base64.h" + +using namespace TW; +using namespace std::chrono; + +namespace TW::Everscale { + +Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { + auto key = PrivateKey(input.private_key()); + auto publicKey = key.getPublicKey(TWPublicKeyTypeED25519); + + auto protoOutput = Proto::SigningOutput(); + + switch (input.action_oneof_case()) { + case Proto::SigningInput::ActionOneofCase::kTransfer: { + const auto& transfer = input.transfer(); + + uint8_t flags; + switch (transfer.behavior()) { + case Proto::MessageBehavior::SendAllBalance: { + flags = Wallet::sendAllBalanceFlags; + break; + } + default: { + flags = Wallet::simpleTransferFlags; + break; + } + } + + Cell::Ref contractData{}; + switch (transfer.account_state_oneof_case()) { + case Proto::Transfer::AccountStateOneofCase::kEncodedContractData: { + contractData = Cell::fromBase64(transfer.encoded_contract_data()); + break; + } + default: + break; + } + + auto signedMessage = createSignedMessage( + publicKey, + key, + transfer.bounce(), + flags, + transfer.amount(), + transfer.expired_at(), + Address(transfer.to()), + contractData); + protoOutput.set_encoded(TW::Base64::encode(signedMessage)); + break; + } + default: + break; + } + + return protoOutput; +} + +} // namespace TW::Everscale diff --git a/src/Everscale/Signer.h b/src/Everscale/Signer.h new file mode 100644 index 00000000000..99ed125d1c9 --- /dev/null +++ b/src/Everscale/Signer.h @@ -0,0 +1,25 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "../Data.h" +#include "../PrivateKey.h" +#include "../proto/Everscale.pb.h" + +namespace TW::Everscale { + +/// Helper class that performs Everscale transaction signing. +class Signer { +public: + /// Hide default constructor + Signer() = delete; + + /// Signs a Proto::SigningInput transaction + static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept; +}; + +} // namespace TW::Everscale diff --git a/src/Everscale/Wallet.cpp b/src/Everscale/Wallet.cpp new file mode 100644 index 00000000000..09bf1e442e5 --- /dev/null +++ b/src/Everscale/Wallet.cpp @@ -0,0 +1,82 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Wallet.h" +#include "CellBuilder.h" +#include "Messages.h" + +#include "HexCoding.h" + +using namespace TW; + +namespace TW::Everscale { + +// WalletV3 contract https://github.com/tonlabs/ton-1/blob/master/crypto/smartcont/wallet3-code.fc +const Data Wallet::code = parse_hex("b5ee9c720101010100710000deff0020dd2082014c97ba218201339cbab19f71b0ed44d0d31fd31f31d70bffe304e0a4f2608308d71820d31fd31fd31ff82313bbf263ed44d0d31fd31fd3ffd15132baf2a15144baf2a204f901541055f910f2a3f8009320d74a96d307d402fb00e8d101a4c8cb1fcb1fcbffc9ed54"); + +CellBuilder InitData::writeTo() const { + CellBuilder builder; + + builder.appendU32(_seqno); + builder.appendU32(_walletId); + builder.appendRaw(_publicKey.bytes, 256); + + return builder; +} + +Address InitData::computeAddr(int8_t workchainId) const { + auto builder = this->writeTo(); + + StateInit stateInit{ + .code = Cell::deserialize(Wallet::code.data(), Wallet::code.size()), + .data = builder.intoCell(), + }; + return Address(workchainId, stateInit.writeTo().intoCell()->hash); +} + +StateInit InitData::makeStateInit() const { + auto builder = this->writeTo(); + + return StateInit{ + .code = Cell::deserialize(Wallet::code.data(), Wallet::code.size()), + .data = builder.intoCell(), + }; +} + +CellBuilder InitData::makeTransferPayload(uint32_t expireAt, const Wallet::Gift& gift) const { + CellBuilder payload; + + // insert prefix + payload.appendU32(_walletId); + payload.appendU32(expireAt); + payload.appendU32(_seqno); + + // create internal message + Message::HeaderRef header = std::make_shared(true, gift.bounce, gift.to, gift.amount); + auto message = Message(header); + + // append it to the body + payload.appendU8(gift.flags); + payload.appendReferenceCell(message.intoCell()); + + return payload; +} + +CellBuilder StateInit::writeTo() const { + CellBuilder builder; + + builder.appendBitZero(); // split_depth + builder.appendBitZero(); // special + builder.appendBitOne(); // code + builder.appendReferenceCell(code); + builder.appendBitOne(); // data + builder.appendReferenceCell(data); + builder.appendBitZero(); // library + + return builder; +} + +} // namespace TW::Everscale diff --git a/src/Everscale/Wallet.h b/src/Everscale/Wallet.h new file mode 100644 index 00000000000..a0216c465db --- /dev/null +++ b/src/Everscale/Wallet.h @@ -0,0 +1,77 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include + +#include "../PublicKey.h" + +#include "Address.h" +#include "Cell.h" +#include "CellBuilder.h" +#include "CellSlice.h" + +const uint32_t WALLET_ID = 0x4BA92D8A; + +namespace TW::Everscale { + +class Wallet { +public: + enum MessageFlags : uint8_t { + // Sender wants to pay transfer fees separately + // (from account balance instead of message balance) + FeesFromAccountBalance = (1 << 0), + + // If there are some errors during the action phase it should be ignored + IgnoreActionPhaseErrors = (1 << 1), + + // Message will carry all the remaining balance + AttachAllBalance = (1 << 7), + }; + + struct Gift { + bool bounce; + uint64_t amount; + Address to; + uint8_t flags; + }; + + static constexpr uint8_t simpleTransferFlags = + MessageFlags::FeesFromAccountBalance | MessageFlags::IgnoreActionPhaseErrors; + static constexpr uint8_t sendAllBalanceFlags = + MessageFlags::AttachAllBalance | MessageFlags::IgnoreActionPhaseErrors; + + static const Data code; +}; + +class StateInit { +public: + Cell::Ref code; + Cell::Ref data; + + [[nodiscard]] CellBuilder writeTo() const; +}; + +class InitData { + uint32_t _seqno; + uint32_t _walletId; + PublicKey _publicKey; + +public: + explicit InitData(PublicKey publicKey) + : _seqno(0), _walletId(WALLET_ID), _publicKey(std::move(publicKey)) {} + explicit InitData(CellSlice cs) + : _seqno(cs.getNextU32()), _walletId(cs.getNextU32()), _publicKey(PublicKey(cs.getNextBytes(32), TWPublicKeyTypeED25519)) {} + + [[nodiscard]] CellBuilder writeTo() const; + [[nodiscard]] StateInit makeStateInit() const; + [[nodiscard]] Address computeAddr(int8_t workchainId) const; + [[nodiscard]] CellBuilder makeTransferPayload(uint32_t expireAt, const Wallet::Gift& gift) const; +}; + +} // namespace TW::Everscale diff --git a/src/Everscale/WorkchainType.h b/src/Everscale/WorkchainType.h new file mode 100644 index 00000000000..786343e1065 --- /dev/null +++ b/src/Everscale/WorkchainType.h @@ -0,0 +1,16 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +namespace TW::Everscale { + +enum WorkchainType { + Masterchain = -1, + Basechain = 0, +}; + +} // namespace TW::Everscale diff --git a/src/proto/Everscale.proto b/src/proto/Everscale.proto new file mode 100644 index 00000000000..c98841981c4 --- /dev/null +++ b/src/proto/Everscale.proto @@ -0,0 +1,50 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +syntax = "proto3"; + +package TW.Everscale.Proto; +option java_package = "wallet.core.jni.proto"; + +enum MessageBehavior { + SimpleTransfer = 0; // Sends a message with the specified amount. The sender pays a fee from the account balance + SendAllBalance = 1; // Sends the entire account balance along with the message +} + +message Transfer { + // If set to true, then the message will be returned if there is an error on the recipient's side. + bool bounce = 1; + + // Affect the attached amount and fees + MessageBehavior behavior = 2; + + // Amount to send in nano EVER + uint64 amount = 3; + + // Expiration UNIX timestamp + uint32 expired_at = 4; + + // Recipient address + string to = 5; + + // Account state if there is any + oneof account_state_oneof { + // Just contract data + string encoded_contract_data = 6; + } +} + +message SigningInput { + oneof action_oneof { + Transfer transfer = 1; + } + + bytes private_key = 2; +} + +message SigningOutput { + string encoded = 1; +} diff --git a/swift/Tests/Blockchains/EverscaleTests.swift b/swift/Tests/Blockchains/EverscaleTests.swift new file mode 100644 index 00000000000..d3ce3f32293 --- /dev/null +++ b/swift/Tests/Blockchains/EverscaleTests.swift @@ -0,0 +1,54 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import WalletCore +import XCTest + +class EverscaleTests: XCTestCase { + func testAddressFromPrivateKey() { + let privateKey = PrivateKey(data: Data(hexString: "15d126cb1a84acdbcd1d9c3f6975968c2beb18cc43c95849d4b0226e1c8552aa")!)! + let publicKey = privateKey.getPublicKeyEd25519() + let address = AnyAddress(publicKey: publicKey, coin: .everscale) + XCTAssertEqual(address.description, "0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04") + } + + func testAddressFromPublicKey() { + let publicKey = PublicKey(data: Data(hexString: "a0303f8fc89a3c2124f5dc6f3ab9a9cb246b7d1e24897eaf5e63eeee20085db0")!, type: PublicKeyType.ed25519)! + let address = AnyAddress(publicKey: publicKey, coin: .everscale) + XCTAssertEqual(address.description, "0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04") + } + + func testAddressFromString() { + let addressString = "0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04" + let address = AnyAddress(string: addressString, coin: .everscale) + XCTAssertEqual(address!.description, "0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04") + } + + func testSign() throws { + let privateKeyData = Data(hexString: "542bd4288352f1c6b270046f153d406aec054a0a06000ab9b36b5c6dd3050ad4")! + + let transfer = EverscaleTransfer.with { + $0.bounce = false + $0.behavior = EverscaleMessageBehavior.simpleTransfer + $0.amount = 100000000 + $0.expiredAt = 1680770631 + $0.to = "0:db18a67f4626f15ac0537a18445937f685f9b30184f0d7b28be4bdeb92d2fd90" + $0.encodedContractData = "te6ccgEBAQEAKgAAUAAAAAFLqS2KOWKN+7Y5OSiKhKisiw6t/h2ovvR3WbapyAtrdctwupw=" + } + + let input = EverscaleSigningInput.with { + $0.transfer = transfer + $0.privateKey = privateKeyData + } + + let output: EverscaleSigningOutput = AnySigner.sign(input: input, coin: .everscale) + + // Link to the message: https://everscan.io/messages/73807b0a3ca2d8564c023dccd5b9da222a270f68338c6fc2c064dda376a2c59d + let expectedString = "te6ccgICAAIAAQAAAKoAAAHfiAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrAImASIQKH2jIwoA65IGC6aua4gAA4fFo/Nuxgb3sIRELhZnSXIS7IsE2E4D+8hk3EWGVZX+ICqlN/ka9DvXduhaXUlsUyF0MjgAAAAIHAABAGhCAG2MUz+jE3itYCm9DCIsm/tC/NmAwnhr2UXyXvXJaX7IIC+vCAAAAAAAAAAAAAAAAAAA" + + XCTAssertEqual(output.encoded, expectedString) + } +} diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index c02527d54fa..8fdf3190737 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -249,6 +249,9 @@ class CoinAddressDerivationTests: XCTestCase { case .nativeEvmos: let expectedResult = "evmos13u6g7vqgw074mgmf2ze2cadzvkz9snlwstd20d" assertCoinDerivation(coin, expectedResult, derivedAddress, address) + case .everscale: + let expectedResult = "0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04"; + assertCoinDerivation(coin, expectedResult, derivedAddress, address) @unknown default: fatalError() } diff --git a/tests/CoinAddressDerivationTests.cpp b/tests/CoinAddressDerivationTests.cpp index e109a4dae5f..ed8d695148e 100644 --- a/tests/CoinAddressDerivationTests.cpp +++ b/tests/CoinAddressDerivationTests.cpp @@ -149,6 +149,9 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeElrond: EXPECT_EQ(address, "erd1a6f6fan035ttsxdmn04ellxdlnwpgyhg0lhx5vjv92v6rc8xw9yq83344f"); break; + case TWCoinTypeEverscale: + EXPECT_EQ(address, "0:ef64d51f95ef17973b737277cfecbd2a8d551141be2f58f5fb362575fc3eb5b0"); + break; case TWCoinTypeFIO: EXPECT_EQ(address, "FIO5TrYnZP1RkDSUMzBY4GanCy6AP68kCMdkAb5EACkAwkdgRLShz"); break; diff --git a/tests/CoinAddressValidationTests.cpp b/tests/CoinAddressValidationTests.cpp index 607f9f120c5..a1816d6e911 100644 --- a/tests/CoinAddressValidationTests.cpp +++ b/tests/CoinAddressValidationTests.cpp @@ -402,4 +402,11 @@ TEST(Coin, ValidateAddressECash) { ASSERT_EQ(normalizeAddress(TWCoinTypeECash, "1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2"), "1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2"); } +TEST(Coin, ValidateAddressEverscale) { + EXPECT_TRUE(validateAddress(TWCoinTypeEverscale, "0:83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469a")); + EXPECT_FALSE(validateAddress(TWCoinTypeEverscale, "83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469a")); + + ASSERT_EQ(normalizeAddress(TWCoinTypeEverscale, "0:83A0352908060FA87839195D8A763A8D9AB28F8FA41468832B398A719CC6469A"), "0:83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469a"); +} + } // namespace TW diff --git a/tests/Everscale/AddressTests.cpp b/tests/Everscale/AddressTests.cpp new file mode 100644 index 00000000000..5896183c21d --- /dev/null +++ b/tests/Everscale/AddressTests.cpp @@ -0,0 +1,52 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Everscale/Address.h" +#include "Everscale/WorkchainType.h" +#include "HexCoding.h" +#include "PrivateKey.h" +#include "PublicKey.h" +#include +#include + +using namespace TW; + +namespace TW::Everscale { + +TEST(EverscaleAddress, Valid) { + ASSERT_TRUE(Address::isValid("0:83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469a")); +} + +TEST(EverscaleAddress, Invalid) { + ASSERT_FALSE(Address::isValid("hello world")); + ASSERT_FALSE(Address::isValid("83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469a")); + ASSERT_FALSE(Address::isValid("1:83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469a")); + ASSERT_FALSE(Address::isValid("-2:83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469a")); + ASSERT_FALSE(Address::isValid("2147483648:83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469a")); + ASSERT_FALSE(Address::isValid("0:83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469ab")); +} + +TEST(EverscaleAddress, FromString) { + auto address = Address("0:83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469a"); + ASSERT_EQ(address.string(), "0:83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469a"); + + auto address_uppercase = Address("0:83A0352908060FA87839195D8A763A8D9AB28F8FA41468832B398A719CC6469A"); + ASSERT_EQ(address_uppercase.string(), "0:83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469a"); +} + +TEST(EverscaleAddress, FromPrivateKey) { + auto privateKey = PrivateKey(parse_hex("5b59e0372d19b6355c73fa8cc708fa3301ae2ec21bb6277e8b79d386ccb7846f")); + auto address = Address(privateKey.getPublicKey(TWPublicKeyTypeED25519), WorkchainType::Basechain); + ASSERT_EQ(address.string(), "0:269fee242eb410786abe1777a14785c8bbeb1e34100c7570e17698b36ad66fb0"); +} + +TEST(EverscaleAddress, FromPublicKey) { + auto publicKey = PublicKey(parse_hex("e4925f9932df8d7fd0042efff3e2178a972028b644ded3a3b66f6d0577f82e78"), TWPublicKeyTypeED25519); + auto address = Address(publicKey, WorkchainType::Basechain); + ASSERT_EQ(address.string(), "0:269fee242eb410786abe1777a14785c8bbeb1e34100c7570e17698b36ad66fb0"); +} + +} // namespace TW::Everscale diff --git a/tests/Everscale/CellBuilderTest.cpp b/tests/Everscale/CellBuilderTest.cpp new file mode 100644 index 00000000000..860f3bac6e5 --- /dev/null +++ b/tests/Everscale/CellBuilderTest.cpp @@ -0,0 +1,121 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "BinaryCoding.h" +#include "HexCoding.h" +#include "PublicKey.h" + +#include "Everscale/Cell.h" +#include "Everscale/CellBuilder.h" +#include "Everscale/Wallet.h" + +#include + +using namespace TW; +using boost::multiprecision::uint128_t; + +namespace TW::Everscale { + +void checkBuilder(const uint128_t& value, uint16_t bitLen, const std::string& hash) { + CellBuilder dataBuilder; + dataBuilder.appendU128(value); + const auto cell = dataBuilder.intoCell(); + ASSERT_EQ(cell->bitLen, bitLen); + ASSERT_EQ(hex(cell->hash), hash); +} + +TEST(EverscaleCell, BuilderVarUint16) { + const uint128_t oneEver{1'000'000'000u}; + + checkBuilder(0, 4, "5331fed036518120c7f345726537745c5929b8ea1fa37b99b2bb58f702671541"); + checkBuilder(1, 12, "d46edee086ccbace01f45c13d26d49b68f74cd1b7616f4662e699c82c6ec728b"); + checkBuilder(255, 12, "bd16b2d60c93163fbed832e91a5faec484715c48176857c57dcedf9f6e0f32f6"); + checkBuilder(256, 20, "16559011ce6f0f7aaa765179e73ef293f39610f5baa3838a1dc8c52da95793b3"); + checkBuilder(oneEver, 36, "e139b2d96d0bd76da98c3c23b0dc0481dcfe19562798fefbb7bf2e56d8ef37b5"); + checkBuilder(10 * oneEver, 44, "8882fead71f2deb3aa7b8dbd15bbb42c651fcaae8da82e6d5cf8e49825eed12b"); + checkBuilder(1000000 * oneEver, 60, "125f2f85da07f9d92148c067bc19aecbf4da65becdd6b51f17ae3a2aeb2c1bdd"); + checkBuilder(1'000'000'000'000u * oneEver, 76, "39bcb314cdb31de5159764d9c28779de27be44210ffcc52a27aa01bff1d82bf7"); +} + +TEST(EverscaleCell, ComputeContractAddress) { + const auto seqno = 0; + const auto walletId = WALLET_ID; + const auto publicKey = PublicKey(parse_hex("7dbe83e9b223157e85bed2628430e2cdb531d5c99ab428618b7dd29b567a0369"), TWPublicKeyTypeED25519); + + CellBuilder dataBuilder; + dataBuilder.appendU32(seqno); + dataBuilder.appendU32(walletId); + dataBuilder.appendRaw(publicKey.bytes, 256); + + const auto data = dataBuilder.intoCell(); + + // Builder should be empty after `intoCell` + { + const auto emptyCell = dataBuilder.intoCell(); + ASSERT_EQ(hex(emptyCell->hash), "96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7"); + } + + const auto code = Cell::deserialize(Wallet::code.data(), Wallet::code.size()); + + CellBuilder stateInitBuilder; + stateInitBuilder.appendBitZero(); // split_depth + stateInitBuilder.appendBitZero(); // special + stateInitBuilder.appendBitOne(); // code + stateInitBuilder.appendReferenceCell(code); + stateInitBuilder.appendBitOne(); // data + stateInitBuilder.appendReferenceCell(data); + stateInitBuilder.appendBitZero(); // library + + auto stateInit = stateInitBuilder.intoCell(); + + ASSERT_EQ(hex(stateInit->hash), "5a0f742c28067da91e05830f0b072a2069f0617a5f6529d295f6c517d63d67c6"); +} + +TEST(EverscaleCell, UnalignedRead) { + CellBuilder dataBuilder; + dataBuilder.appendU32(0x12312312); + + auto cell = dataBuilder.intoCell(); + auto slice = CellSlice(cell.get()); + + slice.dataOffset += 1; + const auto nextBytes = slice.getNextBytes(2); + ASSERT_TRUE(nextBytes.size() == 2 && nextBytes[0] == 0x24 && nextBytes[1] == 0x62); +} + +TEST(EverscaleCell, ReadZeroBytes) { + CellBuilder dataBuilder; + dataBuilder.appendU32(0x12312312); + + auto cell = dataBuilder.intoCell(); + auto slice = CellSlice(cell.get()); + + ASSERT_EQ(slice.getNextBytes(0), Data{}); +} + +TEST(EverscaleCell, InvalidBuilderData) { + CellBuilder dataBuilder; + ASSERT_ANY_THROW(dataBuilder.appendRaw(Data{}, 1)); +} + +TEST(EverscaleCell, DataOverflow) { + CellBuilder dataBuilder; + + Data data(128, 0x00); + ASSERT_ANY_THROW(dataBuilder.appendRaw(data, data.size() * 8)); +} + +TEST(EverscaleCell, DataUnderflow) { + CellBuilder dataBuilder; + dataBuilder.appendU32(0x12312312); + + auto cell = dataBuilder.intoCell(); + auto slice = CellSlice(cell.get()); + + ASSERT_ANY_THROW(slice.getNextBytes(100)); +} + +} // namespace TW::Everscale diff --git a/tests/Everscale/CellTests.cpp b/tests/Everscale/CellTests.cpp new file mode 100644 index 00000000000..c9b1b821cb9 --- /dev/null +++ b/tests/Everscale/CellTests.cpp @@ -0,0 +1,106 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Base64.h" +#include "Everscale/Cell.h" +#include "Everscale/Wallet.h" +#include "HexCoding.h" +#include +#include +#include +#include + +using namespace TW; + +namespace TW::Everscale { + +// All hashes could be verified using https://ever.bytie.moe/visualizer + +static constexpr auto TX = "te6ccgECDgEAAyUAA7V6uRyM7ESqbjssMUQyAqYyQTlEkfDkEhWjBiC1fvKLabAAAaKsEuhQGeqOSyMlWG32ehDzoVCXMh6ugfMLr6pOPj3b6KD4DR/wAAGirA4jnSYtmdCAADR6V/lIBQQBAg8MQQYcxc1EQAMCAG/JkrcETDHn2AAAAAAAAgAAAAAAAop8XDVxQ98+QpgCzzW0U0opAulbEzfySLp3wLLoHzboQRA6FACdROMjE4gAAAAAAAAAACHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIACCcgkc5v5RyBDaeDdbY8Q+SpmX5OOkhzxFyB/ug4o/bJwJXDMKjAeOEr9OvfcJlgyx80ukSBl43/FO2DXIt1+SuAQCAeAJBgEB3wcBsWgBVyORnYiVTcdlhiiGQFTGSCcokj4cgkK0YMQWr95RbTcAIXxdqfc1KmavZDEIGsfjdBuS4lE5Ox4rJZ+Z+rauOxDRZaC8AAYx6CQAADRVgl0KBMWzOhDACAF7C04VCAAAAAAvMK5pAAAAAAAAAAAAAAAAAA7xIIAFdGVusOGq5cSrATb2hH5h5turvUDrer4E0Mf51wPlefAMAd2IAVcjkZ2IlU3HZYYohkBUxkgnKJI+HIJCtGDEFq/eUW02AMrbR14n5UXrp1deXDU5rl8kQvDfSKbnA+d09dtQe2mo8t94jbtllx/DjCgucIpvywjhJBhWNQjtWXh4dP6qiDAAAAADFszqDukuhIYKAQTQAwsB42IAQvi7U+5qVM1eyGIQNY/G6DclxKJydjxWSz8z9W1cdiGiy0F4AAAAAAAAAAAAAAAAAAALThUIAAAAAC8wrmkAAAAAAAAAAAAAAAAADvEggAV0ZW6w4arlxKsBNvaEfmHm26u9QOt6vgTQx/nXA+V58AwBY4AUk5qcKxU0Kqq8xI6zxcnOzaRMAW8AGxI8jfJSPgiVJ6AAAAAAAAAAAAAARVadlK9wDQBDgBVyORnYiVTcdlhiiGQFTGSCcokj4cgkK0YMQWr95RbTcA=="; +static constexpr auto BIG_TX = "te6ccgECdQEAFD4AA7d61FeCHf8yG3+VsHLEilQ6UuYy8wcpWi1+/eB+QyLiYMAAAahJB7OYkL2Pl+S0sBbapRCERwSsVWKsZ/1WGbNouh5HwPhxSiGAAAGoP8TeAJYumenAAFSARBWHSAUEAQIbBIgLyR0Jj8WYgCdHLREDAgBxygFZfVBPmUqMAAAAAAAGAAIAAAAEW8033SNQ2/1TE9Nzuof+lf33h4/sRfFyiGy4DaJos2pa1CzcAJ5KDiw9CQAAAAAAAAAAATMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIJyjI1j6xocdf/ts8UpUE4PQBjq+eZ4ePLwpE1tDGf3pHcFUnuY03DQrIX8ExegcAhTl+187mhCPuegYR4tBS3ejwIB4HEGAgHdCgcBASAIAbFoAVqK8EO/5kNv8rYOWJFKh0pcxl5g5StFr9+8D8hkXEwZAB03C5ZU3g0onstArcVRQt2q942P0t/N68CNCNeI9IxfETHWk3wGKJa2AAA1CSD2cxbF0z04wAkBa2eguV8AAAAAAAAAAAAAAANFARhPgB374hjvHSKb7xHdyPtVEPFzv/+BeyMtxMrKJu6jDYpu8HMBASALArNoAVqK8EO/5kNv8rYOWJFKh0pcxl5g5StFr9+8D8hkXEwZAB03C5ZU3g0onstArcVRQt2q942P0t/N68CNCNeI9IxfEI8NGAAIA3C5RAAANQkg9nMUxdM9OeBTDAJTFaA4+wAAAAGAHfviGO8dIpvvEd3I+1UQ8XO//4F7Iy3Eysom7qMNim7wDg0AQ4AVmHZxK25XVSkUA1uAHGOMneWjMhSxqkQWdAyAImMM0RACBorbNXAPBCSK7VMg4wMgwP/jAiDA/uMC8gtNERB0A77tRNDXScMB+GaJ+Gkh2zzTAAGOGoECANcYIPkBAdMAAZTT/wMBkwL4QuL5EPKoldMAAfJ64tM/AfhDIbnytCD4I4ED6KiCCBt3QKC58rT4Y9MfAfgjvPK50x8B2zzyPGodEgR87UTQ10nDAfhmItDTA/pAMPhpqTgA+ER/b3GCCJiWgG9ybW9zcG90+GTjAiHHAOMCIdcNH/K8IeMDAds88jxKa2sSAiggghBnoLlfu+MCIIIQfW/yVLvjAh8TAzwgghBotV8/uuMCIIIQc+IhQ7rjAiCCEH1v8lS64wIcFhQDNjD4RvLgTPhCbuMAIZPU0dDe+kDR2zww2zzyAEwVUABo+Ev4SccF8uPo+Ev4TfhKcMjPhYDKAHPPQM5xzwtuVSDIz5BT9raCyx/OAcjOzc3JgED7AANOMPhG8uBM+EJu4wAhk9TR0N7Tf/pA03/U0dD6QNIA1NHbPDDbPPIATBdQBG74S/hJxwXy4+glwgDy5Bol+Ey78uQkJPpCbxPXC//DACX4S8cFs7Dy5AbbPHD7AlUD2zyJJcIAUTpqGAGajoCcIfkAyM+KAEDL/8nQ4jH4TCehtX/4bFUhAvhLVQZVBH/Iz4WAygBzz0DOcc8LblVAyM+RnoLlfst/zlUgyM7KAMzNzcmBAID7AFsZAQpUcVTbPBoCuPhL+E34QYjIz44rbNbMzslVBCD5APgo+kJvEsjPhkDKB8v/ydAGJsjPhYjOAfoCi9AAAAAAAAAAAAAAAAAHzxYh2zzMz4NVMMjPkFaA4+7Myx/OAcjOzc3JcfsAcBsANNDSAAGT0gQx3tIAAZPSATHe9AT0BPQE0V8DARww+EJu4wD4RvJz0fLAZB0CFu1E0NdJwgGOgOMNHkwDZnDtRND0BXEhgED0Do6A33IigED0Do6A33AgiPhu+G34bPhr+GqAQPQO8r3XC//4YnD4Y2lpdARQIIIQDwJYqrvjAiCCECDrx2274wIgghBGqdfsu+MCIIIQZ6C5X7vjAj0yKSAEUCCCEElpWH+64wIgghBWJUituuMCIIIQZl3On7rjAiCCEGeguV+64wInJSMhA0ow+Eby4Ez4Qm7jACGT1NHQ3tN/+kDU0dD6QNIA1NHbPDDbPPIATCJQAuT4SSTbPPkAyM+KAEDL/8nQxwXy5EzbPHL7AvhMJaC1f/hsAY41UwH4SVNW+Er4S3DIz4WAygBzz0DOcc8LblVQyM+Rw2J/Js7Lf1UwyM5VIMjOWcjOzM3Nzc2aIcjPhQjOgG/PQOLJgQCApgK1B/sAXwQ6UQPsMPhG8uBM+EJu4wDTH/hEWG91+GTR2zwhjiUj0NMB+kAwMcjPhyDOjQQAAAAAAAAAAAAAAAAOZdzp+M8WzMlwji74RCBvEyFvEvhJVQJvEchyz0DKAHPPQM4B+gL0AIBqz0D4RG8VzwsfzMn4RG8U4vsA4wDyAEwkSAE0+ERwb3KAQG90cG9x+GT4QYjIz44rbNbMzslwA0Yw+Eby4Ez4Qm7jACGT1NHQ3tN/+kDU0dD6QNTR2zww2zzyAEwmUAEW+Ev4SccF8uPo2zxCA/Aw+Eby4Ez4Qm7jANMf+ERYb3X4ZNHbPCGOJiPQ0wH6QDAxyM+HIM6NBAAAAAAAAAAAAAAAAAyWlYf4zxbLf8lwji/4RCBvEyFvEvhJVQJvEchyz0DKAHPPQM4B+gL0AIBqz0D4RG8Vzwsfy3/J+ERvFOL7AOMA8gBMKEgAIPhEcG9ygEBvdHBvcfhk+EwEUCCCEDIE7Cm64wIgghBDhPKYuuMCIIIQRFdChLrjAiCCEEap1+y64wIwLiwqA0ow+Eby4Ez4Qm7jACGT1NHQ3tN/+kDU0dD6QNIA1NHbPDDbPPIATCtQAcz4S/hJxwXy4+gkwgDy5Bok+Ey78uQkI/pCbxPXC//DACT4KMcFs7Dy5AbbPHD7AvhMJaG1f/hsAvhLVRN/yM+FgMoAc89AznHPC25VQMjPkZ6C5X7Lf85VIMjOygDMzc3JgQCA+wBRA+Iw+Eby4Ez4Qm7jANMf+ERYb3X4ZNHbPCGOHSPQ0wH6QDAxyM+HIM5xzwthAcjPkxFdChLOzclwjjH4RCBvEyFvEvhJVQJvEchyz0DKAHPPQM4B+gL0AHHPC2kByPhEbxXPCx/Ozcn4RG8U4vsA4wDyAEwtSAAg+ERwb3KAQG90cG9x+GT4SgNAMPhG8uBM+EJu4wAhk9TR0N7Tf/pA0gDU0ds8MNs88gBML1AB8PhK+EnHBfLj8ts8cvsC+EwkoLV/+GwBjjJUcBL4SvhLcMjPhYDKAHPPQM5xzwtuVTDIz5Hqe3iuzst/WcjOzM3NyYEAgKYCtQf7AI4oIfpCbxPXC//DACL4KMcFs7COFCHIz4UIzoBvz0DJgQCApgK1B/sA3uJfA1ED9DD4RvLgTPhCbuMA0x/4RFhvdfhk0x/R2zwhjiYj0NMB+kAwMcjPhyDOjQQAAAAAAAAAAAAAAAALIE7CmM8WygDJcI4v+EQgbxMhbxL4SVUCbxHIcs9AygBzz0DOAfoC9ACAas9A+ERvFc8LH8oAyfhEbxTi+wDjAPIATDFIAJr4RHBvcoBAb3Rwb3H4ZCCCEDIE7Cm6IYIQT0efo7oighAqSsQ+uiOCEFYlSK26JIIQDC/yDbolghB+3B03ulUFghAPAliqurGxsbGxsQRQIIIQEzKpMbrjAiCCEBWgOPu64wIgghAfATKRuuMCIIIQIOvHbbrjAjs3NTMDNDD4RvLgTPhCbuMAIZPU0dDe+kDR2zzjAPIATDRIAUL4S/hJxwXy4+jbPHD7AsjPhQjOgG/PQMmBAICmArUH+wBSA+Iw+Eby4Ez4Qm7jANMf+ERYb3X4ZNHbPCGOHSPQ0wH6QDAxyM+HIM5xzwthAcjPknwEykbOzclwjjH4RCBvEyFvEvhJVQJvEchyz0DKAHPPQM4B+gL0AHHPC2kByPhEbxXPCx/Ozcn4RG8U4vsA4wDyAEw2SAAg+ERwb3KAQG90cG9x+GT4SwNMMPhG8uBM+EJu4wAhltTTH9TR0JPU0x/i+kDU0dD6QNHbPOMA8gBMOEgCePhJ+ErHBSCOgN/y4GTbPHD7AiD6Qm8T1wv/wwAh+CjHBbOwjhQgyM+FCM6Ab89AyYEAgKYCtQf7AN5fBDlRASYwIds8+QDIz4oAQMv/ydD4SccFOgBUcMjL/3BtgED0Q/hKcViAQPQWAXJYgED0Fsj0AMn4TsjPhID0APQAz4HJA/Aw+Eby4Ez4Qm7jANMf+ERYb3X4ZNHbPCGOJiPQ0wH6QDAxyM+HIM6NBAAAAAAAAAAAAAAAAAkzKpMYzxbLH8lwji/4RCBvEyFvEvhJVQJvEchyz0DKAHPPQM4B+gL0AIBqz0D4RG8Vzwsfyx/J+ERvFOL7AOMA8gBMPEgAIPhEcG9ygEBvdHBvcfhk+E0ETCCCCIV++rrjAiCCCzaRmbrjAiCCEAwv8g264wIgghAPAliquuMCR0NAPgM2MPhG8uBM+EJu4wAhk9TR0N76QNHbPDDbPPIATD9QAEL4S/hJxwXy4+j4TPLULsjPhQjOgG/PQMmBAICmILUH+wADRjD4RvLgTPhCbuMAIZPU0dDe03/6QNTR0PpA1NHbPDDbPPIATEFQARb4SvhJxwXy4/LbPEIBmiPCAPLkGiP4TLvy5CTbPHD7AvhMJKG1f/hsAvhLVQP4Sn/Iz4WAygBzz0DOcc8LblVAyM+QZK1Gxst/zlUgyM5ZyM7Mzc3NyYEAgPsAUQNEMPhG8uBM+EJu4wAhltTTH9TR0JPU0x/i+kDR2zww2zzyAExEUAIo+Er4SccF8uPy+E0iuo6AjoDiXwNGRQFy+ErIzvhLAc74TAHLf/hNAcsfUiDLH1IQzvhOAcwj+wQj0CCLOK2zWMcFk9dN0N7XTNDtHu1Tyds8YgEy2zxw+wIgyM+FCM6Ab89AyYEAgKYCtQf7AFED7DD4RvLgTPhCbuMA0x/4RFhvdfhk0ds8IY4lI9DTAfpAMDHIz4cgzo0EAAAAAAAAAAAAAAAACAhX76jPFszJcI4u+EQgbxMhbxL4SVUCbxHIcs9AygBzz0DOAfoC9ACAas9A+ERvFc8LH8zJ+ERvFOL7AOMA8gBMSUgAKO1E0NP/0z8x+ENYyMv/yz/Oye1UACD4RHBvcoBAb3Rwb3H4ZPhOA7wh1h8x+Eby4Ez4Qm7jANs8cvsCINMfMiCCEGeguV+6jj0h038z+EwhoLV/+Gz4SQH4SvhLcMjPhYDKAHPPQM5xzwtuVSDIz5CfQjemzst/AcjOzc3JgQCApgK1B/sATFFLAYyOQCCCEBkrUbG6jjUh038z+EwhoLV/+Gz4SvhLcMjPhYDKAHPPQM5xzwtuWcjPkHDKgrbOy3/NyYEAgKYCtQf7AN7iW9s8UABK7UTQ0//TP9MAMfpA1NHQ+kDTf9Mf1NH4bvht+Gz4a/hq+GP4YgIK9KQg9KFObQQsoAAAAALbPHL7Aon4aon4a3D4bHD4bVFqak8Dpoj4bokB0CD6QPpA03/TH9Mf+kA3XkD4avhr+Gww+G0y1DD4biD6Qm8T1wv/wwAh+CjHBbOwjhQgyM+FCM6Ab89AyYEAgKYCtQf7AN4w2zz4D/IAdGpQAEb4TvhN+Ez4S/hK+EP4QsjL/8s/z4POVTDIzst/yx/MzcntVAEe+CdvEGim/mChtX/bPLYJUgAMghAF9eEAAgE0WlQBAcBVAgPPoFdWAENIAVmHZxK25XVSkUA1uAHGOMneWjMhSxqkQWdAyAImMM0RAgEgWVgAQyAE+QMzZwkbAX69TKqEV1UHZyfJCZqB4G/esE2ZHPnIDxQAQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAIGits1cFsEJIrtUyDjAyDA/+MCIMD+4wLyC2xdXHQDiu1E0NdJwwH4Zon4aSHbPNMAAZ+BAgDXGCD5AVj4QvkQ8qje0z8B+EMhufK0IPgjgQPoqIIIG3dAoLnytPhj0x8B2zzyPGpmXgNS7UTQ10nDAfhmItDTA/pAMPhpqTgA3CHHAOMCIdcNH/K8IeMDAds88jxra14BFCCCEBWgOPu64wJfBJAw+EJu4wD4RvJzIZbU0x/U0dCT1NMf4vpA1NHQ+kDR+En4SscFII6A346AjhQgyM+FCM6Ab89AyYEAgKYgtQf7AOJfBNs88gBmY2BvAQhdIts8YQJ8+ErIzvhLAc5wAct/cAHLHxLLH874QYjIz44rbNbMzskBzCH7BAHQIIs4rbNYxwWT103Q3tdM0O0e7VPJ2zxwYgAE8AIBHjAh+kJvE9cL/8MAII6A3mQBEDAh2zz4SccFZQF+cMjL/3BtgED0Q/hKcViAQPQWAXJYgED0Fsj0AMn4QYjIz44rbNbMzsnIz4SA9AD0AM+ByfkAyM+KAEDL/8nQcAIW7UTQ10nCAY6A4w1oZwA07UTQ0//TP9MAMfpA1NHQ+kDR+Gv4avhj+GICVHDtRND0BXEhgED0Do6A33IigED0Do6A3/hr+GqAQPQO8r3XC//4YnD4Y2lpAQKJagBDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAK+Eby4EwCCvSkIPShbm0AFHNvbCAwLjU3LjEBGKAAAAACMNs8+A/yAG8ALPhK+EP4QsjL/8s/z4PO+EvIzs3J7VQADCD4Ye0e2QGxaAHfviGO8dIpvvEd3I+1UQ8XO//4F7Iy3Eysom7qMNim7wArUV4Id/zIbf5WwcsSKVDpS5jLzBylaLX794H5DIuJgxHQmPxYBisxYgAANQkg9nMQxdM9OMByAYtz4iFDAAAAAAAAAAAAAAADRQEYT4AVmHZxK25XVSkUA1uAHGOMneWjMhSxqkQWdAyAImMM0QAAAAAAAAAAAAAAAAR4aMAQcwFDgBWYdnErbldVKRQDW4AcY4yd5aMyFLGqRBZ0DIAiYwzRCHQAAA=="; + +TEST(EverscaleCell, DeserializeTransaction) { + const auto tx = Cell::fromBase64(TX); + ASSERT_EQ(hex(tx->hash), "88a02e7bd8833d384f37d63d4d01deef9a1806937b94a313cc5e8c3cc7643032"); + + const auto bigTx = Cell::fromBase64(BIG_TX); + ASSERT_EQ(hex(bigTx->hash), "37f29d9f3aa5c7cc783962d861c08705f245f5e5bfedd208dfe08d02e80a47d8"); +} + +TEST(EverscaleCell, DeserializeWallet) { + const auto cell = Cell::deserialize(Wallet::code.data(), Wallet::code.size()); + ASSERT_EQ(hex(cell->hash), "84dafa449f98a6987789ba232358072bc0f76dc4524002a5d0918b9a75d2d599"); +} + +TEST(EverscaleCell, SerializeTransaction) { + const auto cell = Cell::fromBase64(TX); + Data data; + cell->serialize(data); + + const auto decoded = Cell::deserialize(data.data(), data.size()); + ASSERT_EQ(hex(decoded->hash), "88a02e7bd8833d384f37d63d4d01deef9a1806937b94a313cc5e8c3cc7643032"); +} + +TEST(EverscaleCell, SerializeWallet) { + const auto cell = Cell::deserialize(Wallet::code.data(), Wallet::code.size()); + Data data; + cell->serialize(data); + + const auto decoded = Cell::deserialize(data.data(), data.size()); + ASSERT_EQ(hex(decoded->hash), "84dafa449f98a6987789ba232358072bc0f76dc4524002a5d0918b9a75d2d599"); +} + +TEST(EverscaleCell, EmptyCell) { + const auto EMPTY_CELL = "96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7"; + + const auto cell1 = Cell::fromBase64("te6ccgEBAQEAAgAAAA=="); + ASSERT_EQ(hex(cell1->hash), EMPTY_CELL); + + // With index + const auto cell2 = Cell::fromBase64("te6ccoEBAQEAAwACAAA="); + ASSERT_EQ(hex(cell2->hash), EMPTY_CELL); + + // With d2 > 0 && d2%8 != 0 but without end flag (computeBitLen should just return 0) + const auto cell3 = Cell::fromBase64("te6ccgEBAQEAAwAABQAAAA=="); + ASSERT_EQ(hex(cell3->hash), EMPTY_CELL); + + // With `storeHashes` (provided hash should be skipped) + const auto cell4 = Cell::fromBase64("te6ccgEBAQEAJAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + ASSERT_EQ(hex(cell4->hash), EMPTY_CELL); +} + +TEST(EverscaleCell, InvalidCell) { + // unexpected eof + ASSERT_THROW(Cell::fromBase64("te4="), std::runtime_error); + // unknown magic + ASSERT_THROW(Cell::fromBase64("aGVsbG8gd29ybGQK"), std::runtime_error); + // refSize > 4 + ASSERT_THROW(Cell::fromBase64("te6ccgUCAAAAAAEAAAAAAQAAAAAAFD4AAAAAAAO3etQ="), std::runtime_error); + // unsupported root count + ASSERT_THROW(Cell::fromBase64("te6ccgECdRIAFD4AA7d61A=="), std::runtime_error); + // root count is greater than cell count + ASSERT_THROW(Cell::fromBase64("te6ccgECAAEAFD4AA7d61A=="), std::runtime_error); + // absent cells are not supported + ASSERT_THROW(Cell::fromBase64("te6ccgECAQESFD4AA7d61A=="), std::runtime_error); + // non-zero level is not supported + ASSERT_THROW(Cell::fromBase64("te6ccgECAQEAFD4AY7d61FeCHf8yG3+VsHLEilQ6UuYy8wcpWi1+/Q=="), std::runtime_error); + // exotic cells are not supported + ASSERT_THROW(Cell::fromBase64("te6ccgECAQEAFD4AC7d61FeCHf8yG3+VsHLEilQ6UuYy8wcpWi1+/Q=="), std::runtime_error); + // absent cells are not supported + ASSERT_THROW(Cell::fromBase64("te6ccgECAQEAFD4AF7d61FeCHf8yG3+VsHLEilQ6UuYy8wcpWi1+/Q=="), std::runtime_error); + // invalid ref count + ASSERT_THROW(Cell::fromBase64("te6ccgEBAQEAAwAFAA=="), std::runtime_error); + // invalid child index + ASSERT_THROW(Cell::fromBase64("te6ccgEBAQEAJAABAP8="), std::runtime_error); + // invalid child index (reference to itself) + ASSERT_THROW(Cell::fromBase64("te6ccgEBAQEAAgABAAA="), std::runtime_error); + // invalid root index + ASSERT_THROW(Cell::fromBase64("te6ccgEBAQEAAwEAAA"), std::runtime_error); + // child cell not found + ASSERT_THROW(Cell::fromBase64("te6ccgEBAQEAAgABAAE="), std::runtime_error); +} + +} // namespace TW::Everscale diff --git a/tests/Everscale/SignerTests.cpp b/tests/Everscale/SignerTests.cpp new file mode 100644 index 00000000000..80eb521a52d --- /dev/null +++ b/tests/Everscale/SignerTests.cpp @@ -0,0 +1,88 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Everscale/Messages.h" +#include "Everscale/Signer.h" + +#include "Base64.h" +#include "HexCoding.h" + +#include + +using namespace TW; + +namespace TW::Everscale { + +TEST(EverscaleSigner, TransferWithDeploy) { + auto input = Proto::SigningInput(); + + auto& transfer = *input.mutable_transfer(); + transfer.set_bounce(false); + transfer.set_behavior(Proto::MessageBehavior::SimpleTransfer); + transfer.set_amount(500000000); + transfer.set_expired_at(1680770631); + transfer.set_to("0:db18a67f4626f15ac0537a18445937f685f9b30184f0d7b28be4bdeb92d2fd90"); + + // NOTE: There is `set_encoded_contract_data` because contract was not deployed yet + + auto privateKey = parse_hex("542bd4288352f1c6b270046f153d406aec054a0a06000ab9b36b5c6dd3050ad4"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input); + + ASSERT_EQ(hex(Cell::fromBase64(output.encoded())->hash), "bfb18e56e9d00d783c7eb1726f08bf613dd0f01a110a130c0f8f91bb13390a39"); + + // Link to the message: https://everscan.io/messages/bfb18e56e9d00d783c7eb1726f08bf613dd0f01a110a130c0f8f91bb13390a39 + ASSERT_EQ(output.encoded(), "te6ccgICAAQAAQAAAUoAAAPhiAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrBGMBTen55/RbfcIBoeCrPB1cxPMcHRx7xyBzJmdtewBPaTu/WuHgnqg09jQaxTEcii+Nuqm7p3b6iMq+/6598ggCXUlsUyF0MjgAAAAAHAAAwACAAEAaEIAbYxTP6MTeK1gKb0MIiyb+0L82YDCeGvZRfJe9clpfsgg7msoAAAAAAAAAAAAAAAAAAAAUAAAAABLqS2KOWKN+7Y5OSiKhKisiw6t/h2ovvR3WbapyAtrdctwupwA3v8AIN0gggFMl7ohggEznLqxn3Gw7UTQ0x/THzHXC//jBOCk8mCDCNcYINMf0x/TH/gjE7vyY+1E0NMf0x/T/9FRMrryoVFEuvKiBPkBVBBV+RDyo/gAkyDXSpbTB9QC+wDo0QGkyMsfyx/L/8ntVA=="); +} + +TEST(EverscaleSigner, Transfer1) { + auto input = Proto::SigningInput(); + + auto& transfer = *input.mutable_transfer(); + transfer.set_bounce(false); + transfer.set_behavior(Proto::MessageBehavior::SimpleTransfer); + transfer.set_amount(100000000); + transfer.set_expired_at(1680770631); + transfer.set_to("0:db18a67f4626f15ac0537a18445937f685f9b30184f0d7b28be4bdeb92d2fd90"); + + transfer.set_encoded_contract_data("te6ccgEBAQEAKgAAUAAAAAFLqS2KOWKN+7Y5OSiKhKisiw6t/h2ovvR3WbapyAtrdctwupw="); + + auto privateKey = parse_hex("542bd4288352f1c6b270046f153d406aec054a0a06000ab9b36b5c6dd3050ad4"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input); + + ASSERT_EQ(hex(Cell::fromBase64(output.encoded())->hash), "73807b0a3ca2d8564c023dccd5b9da222a270f68338c6fc2c064dda376a2c59d"); + + // Link to the message: https://everscan.io/messages/73807b0a3ca2d8564c023dccd5b9da222a270f68338c6fc2c064dda376a2c59d + ASSERT_EQ(output.encoded(), "te6ccgICAAIAAQAAAKoAAAHfiAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrAImASIQKH2jIwoA65IGC6aua4gAA4fFo/Nuxgb3sIRELhZnSXIS7IsE2E4D+8hk3EWGVZX+ICqlN/ka9DvXduhaXUlsUyF0MjgAAAAIHAABAGhCAG2MUz+jE3itYCm9DCIsm/tC/NmAwnhr2UXyXvXJaX7IIC+vCAAAAAAAAAAAAAAAAAAA"); +} + +TEST(EverscaleSigner, Transfer2) { + auto input = Proto::SigningInput(); + + auto& transfer = *input.mutable_transfer(); + transfer.set_bounce(true); + transfer.set_behavior(Proto::MessageBehavior::SendAllBalance); + transfer.set_amount(200000000); + transfer.set_expired_at(1680770631); + transfer.set_to("0:df112b59eb82792623575194c60d2f547c68d54366644a3a5e02b8132f3c4c56"); + + transfer.set_encoded_contract_data("te6ccgEBAQEAKgAAUAAAAAJLqS2KOWKN+7Y5OSiKhKisiw6t/h2ovvR3WbapyAtrdctwupw="); + + auto privateKey = parse_hex("542bd4288352f1c6b270046f153d406aec054a0a06000ab9b36b5c6dd3050ad4"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input); + + ASSERT_EQ(hex(Cell::fromBase64(output.encoded())->hash), "e35616cfa88e115580f07c6b41ae3ded1902d2bab1efefb74f677b4aececef24"); + + // Link to the message: https://everscan.io/messages/e35616cfa88e115580f07c6b41ae3ded1902d2bab1efefb74f677b4aececef24 + ASSERT_EQ(output.encoded(), "te6ccgICAAIAAQAAAKoAAAHfiAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrANrT0ivIEpuMGjKoyS9J03Wbl24jowXvdzQdLD6L3USLETUyRGbbmbUfBcNtF1FwKtmIQd0lNR1qIX9K/eloMgaXUlsUyF0MjgAAAAUFAABAGhiAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrIF9eEAAAAAAAAAAAAAAAAAAA"); +} + +} // namespace TW::Everscale diff --git a/tests/Everscale/TWAnyAddressTests.cpp b/tests/Everscale/TWAnyAddressTests.cpp new file mode 100644 index 00000000000..74d1212ec58 --- /dev/null +++ b/tests/Everscale/TWAnyAddressTests.cpp @@ -0,0 +1,30 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include + +#include "../interface/TWTestUtilities.h" +#include + +namespace TW::Everscale { + +TEST(TWEverscale, HDWallet) { + auto mnemonic = + STRING("shoot island position soft burden budget tooth cruel issue economy destroy above"); + auto passphrase = STRING(""); + + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(mnemonic.get(), passphrase.get())); + + auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKey(wallet.get(), TWCoinTypeEverscale, WRAPS(TWCoinTypeDerivationPath(TWCoinTypeEverscale)).get())); + auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyEd25519(privateKey.get())); + auto address = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKey(publicKey.get(), TWCoinTypeEverscale)); + auto addressStr = WRAPS(TWAnyAddressDescription(address.get())); + + assertStringsEqual(addressStr, "0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04"); +} + +} // namespace TW::Everscale diff --git a/tests/Everscale/TWAnySignerTests.cpp b/tests/Everscale/TWAnySignerTests.cpp new file mode 100644 index 00000000000..0dbae0871ee --- /dev/null +++ b/tests/Everscale/TWAnySignerTests.cpp @@ -0,0 +1,38 @@ +// Copyright © 2017-2021 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Base64.h" +#include "HexCoding.h" +#include "proto/Everscale.pb.h" +#include + +#include "../interface/TWTestUtilities.h" +#include + +namespace TW::Everscale { + +TEST(TWAnySignerEverscale, SignMessageToDeployWallet) { + Proto::SigningInput input; + + auto& transfer = *input.mutable_transfer(); + transfer.set_bounce(false); + transfer.set_behavior(Proto::MessageBehavior::SimpleTransfer); + transfer.set_amount(500000000); + transfer.set_expired_at(1680770631); + transfer.set_to("0:db18a67f4626f15ac0537a18445937f685f9b30184f0d7b28be4bdeb92d2fd90"); + + // NOTE: There is `set_encoded_contract_data` because contract was not deployed yet + + auto privateKey = parse_hex("542bd4288352f1c6b270046f153d406aec054a0a06000ab9b36b5c6dd3050ad4"); + input.set_private_key(privateKey.data(), privateKey.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeEverscale); + + ASSERT_EQ(output.encoded(), "te6ccgICAAQAAQAAAUoAAAPhiAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrBGMBTen55/RbfcIBoeCrPB1cxPMcHRx7xyBzJmdtewBPaTu/WuHgnqg09jQaxTEcii+Nuqm7p3b6iMq+/6598ggCXUlsUyF0MjgAAAAAHAAAwACAAEAaEIAbYxTP6MTeK1gKb0MIiyb+0L82YDCeGvZRfJe9clpfsgg7msoAAAAAAAAAAAAAAAAAAAAUAAAAABLqS2KOWKN+7Y5OSiKhKisiw6t/h2ovvR3WbapyAtrdctwupwA3v8AIN0gggFMl7ohggEznLqxn3Gw7UTQ0x/THzHXC//jBOCk8mCDCNcYINMf0x/TH/gjE7vyY+1E0NMf0x/T/9FRMrryoVFEuvKiBPkBVBBV+RDyo/gAkyDXSpbTB9QC+wDo0QGkyMsfyx/L/8ntVA=="); +} + +} // namespace TW::Everscale diff --git a/tests/Everscale/TWCoinTypeTests.cpp b/tests/Everscale/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..b737fe7dc63 --- /dev/null +++ b/tests/Everscale/TWCoinTypeTests.cpp @@ -0,0 +1,38 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "../interface/TWTestUtilities.h" +#include +#include + +namespace TW::Everscale { + +TEST(TWEverscaleCoinType, TWCoinType) { + const auto coin = TWCoinTypeEverscale; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("781238b2b0d15cd4cd2e2a0a142753750cd5e1b2c8b506fcede75a90e02f1268")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0:d2bf59964a05dee84a0dd1ddc0ad83ba44d49719cf843d689dc8b726d0fb59d8")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "everscale"); + assertStringsEqual(name, "Everscale"); + assertStringsEqual(symbol, "EVER"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 9); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainEverscale); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); + assertStringsEqual(txUrl, "https://everscan.io/transactions/781238b2b0d15cd4cd2e2a0a142753750cd5e1b2c8b506fcede75a90e02f1268"); + assertStringsEqual(accUrl, "https://everscan.io/accounts/0:d2bf59964a05dee84a0dd1ddc0ad83ba44d49719cf843d689dc8b726d0fb59d8"); +} + +} // namespace TW::Everscale From d6cff3ae3e20104efd6d7c4a5544622e4a48bb99 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 31 Aug 2022 07:21:36 +0200 Subject: [PATCH 066/497] feat(ontology): remove usage of boost::any (#2539) --- src/Ontology/Oep4.cpp | 12 +++---- src/Ontology/Ong.cpp | 14 ++++----- src/Ontology/Ont.cpp | 10 +++--- src/Ontology/ParamsBuilder.cpp | 45 ++++++++++++++++----------- src/Ontology/ParamsBuilder.h | 20 +++++++++--- tests/Ontology/ParamsBuilderTests.cpp | 20 ++++++------ tests/Ontology/TransactionTests.cpp | 6 ++-- 7 files changed, 72 insertions(+), 55 deletions(-) diff --git a/src/Ontology/Oep4.cpp b/src/Ontology/Oep4.cpp index 2152c186274..3c08c8af512 100644 --- a/src/Ontology/Oep4.cpp +++ b/src/Ontology/Oep4.cpp @@ -18,8 +18,8 @@ Oep4::Oep4(const Data bin) noexcept Transaction Oep4::readOnlyMethod(std::string method_name, uint32_t nonce) { Address addr(oep4Contract); - std::vector args{}; - auto invokeCode = ParamsBuilder::buildOep4InvokeCode(addr, method_name, args); + NeoVmParamValue::ParamArray args{}; + auto invokeCode = ParamsBuilder::buildOep4InvokeCode(addr, method_name, {args}); return Transaction(0, 0xD1, nonce, 0, 0, "", invokeCode); } @@ -43,8 +43,8 @@ Transaction Oep4::totalSupply(uint32_t nonce) { Transaction Oep4::balanceOf(const Address& user, uint32_t nonce) { Address contract(oep4Contract); Data d(std::begin(user._data), std::end(user._data)); - std::vector args{d}; - auto invokeCode = ParamsBuilder::buildOep4InvokeCode(contract, "balanceOf", args); + NeoVmParamValue::ParamArray args{d}; + auto invokeCode = ParamsBuilder::buildOep4InvokeCode(contract, "balanceOf", {args}); return Transaction(0, 0xD1, nonce, 0, 0, "", invokeCode); } @@ -54,10 +54,10 @@ Transaction Oep4::transfer(const Signer& from, const Address& to, uint64_t amoun Address contract(oep4Contract); auto fromAddr = from.getAddress(); - std::vector args{fromAddr._data, to._data, amount}; + NeoVmParamValue::ParamArray args{fromAddr._data, to._data, amount}; // yes, invoke neovm is not like ont transfer std::reverse(args.begin(), args.end()); - auto invokeCode = ParamsBuilder::buildOep4InvokeCode(contract, "transfer", args); + auto invokeCode = ParamsBuilder::buildOep4InvokeCode(contract, "transfer", {args}); auto tx = Transaction(0, 0xD1, nonce, gasPrice, gasLimit, payer.getAddress().string(), invokeCode); from.sign(tx); diff --git a/src/Ontology/Ong.cpp b/src/Ontology/Ong.cpp index ab9c4eacd7c..c26d78c8ae0 100644 --- a/src/Ontology/Ong.cpp +++ b/src/Ontology/Ong.cpp @@ -16,7 +16,7 @@ using namespace TW::Ontology; Transaction Ong::decimals(uint32_t nonce) { auto builder = ParamsBuilder(); auto invokeCode = - ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "decimals", Data()); + ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "decimals", {Data()}); auto tx = Transaction(version, txType, nonce, (uint64_t)0, (uint64_t)0, (std::string) "", invokeCode); return tx; @@ -25,7 +25,7 @@ Transaction Ong::decimals(uint32_t nonce) { Transaction Ong::balanceOf(const Address &address, uint32_t nonce) { auto builder = ParamsBuilder(); auto invokeCode = - ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "balanceOf", address._data); + ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "balanceOf", {address._data}); auto tx = Transaction(version, txType, nonce, (uint64_t)0, (uint64_t)0, (std::string) "", invokeCode); return tx; @@ -34,10 +34,10 @@ Transaction Ong::balanceOf(const Address &address, uint32_t nonce) { Transaction Ong::transfer(const Signer &from, const Address &to, uint64_t amount, const Signer &payer, uint64_t gasPrice, uint64_t gasLimit, uint32_t nonce) { - std::list transferParam{from.getAddress()._data, to._data, amount}; - std::vector args{transferParam}; + NeoVmParamValue::ParamList transferParam{from.getAddress()._data, to._data, amount}; + NeoVmParamValue::ParamArray args{transferParam}; auto invokeCode = - ParamsBuilder::buildNativeInvokeCode(contractAddress(), 0x00, "transfer", args); + ParamsBuilder::buildNativeInvokeCode(contractAddress(), 0x00, "transfer", {args}); auto tx = Transaction(version, txType, nonce, gasPrice, gasLimit, payer.getAddress().string(), invokeCode); from.sign(tx); @@ -49,9 +49,9 @@ Transaction Ong::withdraw(const Signer &claimer, const Address &receiver, uint64 const Signer &payer, uint64_t gasPrice, uint64_t gasLimit, uint32_t nonce) { auto ontContract = Address("AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV"); - std::list args{claimer.getAddress()._data, ontContract._data, receiver._data, amount}; + NeoVmParamValue::ParamList args{claimer.getAddress()._data, ontContract._data, receiver._data, amount}; auto invokeCode = - ParamsBuilder::buildNativeInvokeCode(contractAddress(), 0x00, "transferFrom", args); + ParamsBuilder::buildNativeInvokeCode(contractAddress(), 0x00, "transferFrom", {args}); auto tx = Transaction(version, txType, nonce, gasPrice, gasLimit, payer.getAddress().string(), invokeCode); claimer.sign(tx); diff --git a/src/Ontology/Ont.cpp b/src/Ontology/Ont.cpp index 51f9bc76864..3e2b784a0bb 100644 --- a/src/Ontology/Ont.cpp +++ b/src/Ontology/Ont.cpp @@ -16,7 +16,7 @@ using namespace TW::Ontology; Transaction Ont::decimals(uint32_t nonce) { auto builder = ParamsBuilder(); auto invokeCode = - ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "decimals", Data()); + ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "decimals", {Data()}); auto tx = Transaction((uint8_t)0, txType, nonce, (uint64_t)0, (uint64_t)0, (std::string) "", invokeCode); return tx; @@ -25,7 +25,7 @@ Transaction Ont::decimals(uint32_t nonce) { Transaction Ont::balanceOf(const Address &address, uint32_t nonce) { auto builder = ParamsBuilder(); auto invokeCode = - ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "balanceOf", address._data); + ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "balanceOf", {address._data}); auto tx = Transaction((uint8_t)0, txType, nonce, (uint64_t)0, (uint64_t)0, (std::string) "", invokeCode); return tx; @@ -34,10 +34,10 @@ Transaction Ont::balanceOf(const Address &address, uint32_t nonce) { Transaction Ont::transfer(const Signer &from, const Address &to, uint64_t amount, const Signer &payer, uint64_t gasPrice, uint64_t gasLimit, uint32_t nonce) { - std::list transferParam{from.getAddress()._data, to._data, amount}; - std::vector args{transferParam}; + NeoVmParamValue::ParamList transferParam{from.getAddress()._data, to._data, amount}; + NeoVmParamValue::ParamArray args{transferParam}; auto invokeCode = - ParamsBuilder::buildNativeInvokeCode(contractAddress(), 0x00, "transfer", args); + ParamsBuilder::buildNativeInvokeCode(contractAddress(), 0x00, "transfer", {args}); auto tx = Transaction(version, txType, nonce, gasPrice, gasLimit, payer.getAddress().string(), invokeCode); from.sign(tx); diff --git a/src/Ontology/ParamsBuilder.cpp b/src/Ontology/ParamsBuilder.cpp index 47d050cd0a5..300578a0101 100644 --- a/src/Ontology/ParamsBuilder.cpp +++ b/src/Ontology/ParamsBuilder.cpp @@ -18,28 +18,35 @@ using namespace TW; using namespace TW::Ontology; -void ParamsBuilder::buildNeoVmParam(ParamsBuilder& builder, const boost::any& param) { - if (param.type() == typeid(std::string)) { - builder.push(boost::any_cast(param)); - } else if (param.type() == typeid(std::array)) { - builder.push(boost::any_cast>(param)); - } else if (param.type() == typeid(Data)) { - builder.push(boost::any_cast(param)); - } else if (param.type() == typeid(uint64_t)) { - builder.push(boost::any_cast(param)); - } else if (param.type() == typeid(std::vector)) { - auto paramVec = boost::any_cast>(param); - for (const auto& item : paramVec) { - ParamsBuilder::buildNeoVmParam(builder, item); +void ParamsBuilder::buildNeoVmParam(ParamsBuilder& builder, const NeoVmParamValue& param) { + + if (auto* paramStr = std::get_if(¶m.params); paramStr) { + builder.push(*paramStr); + } else if (auto* paramFixedArray = std::get_if(¶m.params); paramFixedArray) { + builder.push(*paramFixedArray); + } else if (auto* paramData = std::get_if(¶m.params); paramData) { + builder.push(*paramData); + } else if (auto* paramInteger = std::get_if(¶m.params); paramInteger) { + builder.push(*paramInteger); + } else if (auto* paramArray = std::get_if(¶m.params); paramArray) { + for (auto&& item : *paramArray) { + std::visit([&builder](auto&& arg) { + NeoVmParamValue::ParamVariant value = arg; + ParamsBuilder::buildNeoVmParam(builder, {value}); + }, + item); } - builder.push(static_cast(paramVec.size())); + builder.push(static_cast(paramArray->size())); builder.pushBack(PACK); - } else if (param.type() == typeid(std::list)) { + } else if (auto* paramList = std::get_if(¶m.params); paramList) { builder.pushBack(PUSH0); builder.pushBack(NEW_STRUCT); builder.pushBack(TO_ALT_STACK); - for (auto const& p : boost::any_cast>(param)) { - ParamsBuilder::buildNeoVmParam(builder, p); + for (auto const& p : *paramList) { + std::visit([&builder](auto&& arg) { + NeoVmParamValue::ParamVariant value = arg; + ParamsBuilder::buildNeoVmParam(builder, {value}); + }, p); builder.pushBack(DUP_FROM_ALT_STACK); builder.pushBack(SWAP); builder.pushBack(HAS_KEY); @@ -221,7 +228,7 @@ Data ParamsBuilder::fromMultiPubkey(uint8_t m, const std::vector& pubKeys) } Data ParamsBuilder::buildNativeInvokeCode(const Data& contractAddress, uint8_t version, - const std::string& method, const boost::any& params) { + const std::string& method, const NeoVmParamValue& params) { ParamsBuilder builder; ParamsBuilder::buildNeoVmParam(builder, params); builder.push(Data(method.begin(), method.end())); @@ -233,7 +240,7 @@ Data ParamsBuilder::buildNativeInvokeCode(const Data& contractAddress, uint8_t v return builder.getBytes(); } -Data ParamsBuilder::buildOep4InvokeCode(const Address& contractAddress, const std::string& method, const boost::any& params) { +Data ParamsBuilder::buildOep4InvokeCode(const Address& contractAddress, const std::string& method, const NeoVmParamValue& params) { ParamsBuilder builder; ParamsBuilder::buildNeoVmParam(builder, params); builder.push(method); diff --git a/src/Ontology/ParamsBuilder.h b/src/Ontology/ParamsBuilder.h index 7f7ab9404d5..e8fa0c558f3 100644 --- a/src/Ontology/ParamsBuilder.h +++ b/src/Ontology/ParamsBuilder.h @@ -9,17 +9,27 @@ #include "../BinaryCoding.h" #include "../Data.h" -#include - #include #include #include #include +#include +#include #include "Address.h" namespace TW::Ontology { +struct NeoVmParamValue; + +struct NeoVmParamValue { + using ParamFixedArray = std::array; + using ParamList = std::list>; + using ParamArray = std::vector>; + using ParamVariant = std::variant; + ParamVariant params; +}; + class ParamsBuilder { private: @@ -38,7 +48,7 @@ class ParamsBuilder { static Data fromMultiPubkey(uint8_t m, const std::vector& pubKeys); - static void buildNeoVmParam(ParamsBuilder& builder, const boost::any& param); + static void buildNeoVmParam(ParamsBuilder& builder, const NeoVmParamValue& param); static void buildNeoVmParam(ParamsBuilder& builder, const std::string& param); @@ -79,9 +89,9 @@ class ParamsBuilder { static std::vector buildNativeInvokeCode(const std::vector& contractAddress, uint8_t version, const std::string& method, - const boost::any& params); + const NeoVmParamValue& params); - static std::vector buildOep4InvokeCode(const Address& contractAddress, const std::string& method, const boost::any& params); + static std::vector buildOep4InvokeCode(const Address& contractAddress, const std::string& method, const NeoVmParamValue& params); }; } // namespace TW::Ontology diff --git a/tests/Ontology/ParamsBuilderTests.cpp b/tests/Ontology/ParamsBuilderTests.cpp index 875a207a3dc..382ca6f3335 100644 --- a/tests/Ontology/ParamsBuilderTests.cpp +++ b/tests/Ontology/ParamsBuilderTests.cpp @@ -61,7 +61,7 @@ TEST(ParamsBuilder, pushInt) { TEST(ParamsBuilder, balanceInvokeCode) { auto balanceParam = Address("ANDfjwrUroaVtvBguDtrWKRMyxFwvVwnZD")._data; auto invokeCode = ParamsBuilder::buildNativeInvokeCode(Ont().contractAddress(), 0x00, - "balanceOf", balanceParam); + "balanceOf", {balanceParam}); auto hexInvokeCode = "1446b1a18af6b7c9f8a4602f9f73eeb3030f0c29b70962616c616e63654f661400000000000000000000000000" "000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b65"; @@ -72,10 +72,10 @@ TEST(ParamsBuilder, transferInvokeCode) { auto fromAddress = Address("ANDfjwrUroaVtvBguDtrWKRMyxFwvVwnZD")._data; auto toAddress = Address("Af1n2cZHhMZumNqKgw9sfCNoTWu9de4NDn")._data; uint64_t amount = 1; - std::list transferParam{fromAddress, toAddress, amount}; - std::vector args{transferParam}; + NeoVmParamValue::ParamList transferParam{fromAddress, toAddress, amount}; + NeoVmParamValue::ParamArray args{transferParam}; auto invokeCode = - ParamsBuilder::buildNativeInvokeCode(Ont().contractAddress(), 0x00, "transfer", args); + ParamsBuilder::buildNativeInvokeCode(Ont().contractAddress(), 0x00, "transfer", {args}); auto hexInvokeCode = "00c66b1446b1a18af6b7c9f8a4602f9f73eeb3030f0c29b76a7cc814feec06b79ed299ea06fcb94abac41aaf3e" "ad76586a7cc8516a7cc86c51c1087472616e736665721400000000000000000000000000000000000000010068" @@ -87,9 +87,9 @@ TEST(ParamsBuilder, invokeOep4Code) { std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); - std::vector args{}; + NeoVmParamValue::ParamArray args{}; std::string method{"name"}; - auto invokeCode = ParamsBuilder::buildOep4InvokeCode(wing_addr, method, args); + auto invokeCode = ParamsBuilder::buildOep4InvokeCode(wing_addr, method, {args}); auto expectCode = "00c1046e616d656733def739225d0f93dd2aed457d7b1fd074ec31ff"; EXPECT_EQ(expectCode, hex(invokeCode)); @@ -101,9 +101,9 @@ TEST(ParamsBuilder, invokeOep4CodeBalanceOf) { auto user_addr = Address("AeaThtPwh5kAYnjHavzwmvxPd725nVTvbM"); Data d(std::begin(user_addr._data), std::end(user_addr._data)); - std::vector args{d}; + NeoVmParamValue::ParamArray args{d}; std::string method{"balanceOf"}; - auto invokeCode = ParamsBuilder::buildOep4InvokeCode(wing_addr, method, args); + auto invokeCode = ParamsBuilder::buildOep4InvokeCode(wing_addr, method, {args}); auto expectCode = "14fa2254ffaee3c3e1172e8e98f800e4105c74988e51c10962616c616e63654f666733def739225d0f93dd2aed457d7b1fd074ec31ff"; EXPECT_EQ(expectCode, hex(invokeCode)); @@ -116,10 +116,10 @@ TEST(OntologyOep4, invokeOep4CodeTransfer) { auto to = Address("AVY6LfvxauVQAVHDV9hC3ZCv7cQqzfDotH"); uint64_t amount = 253; - std::vector args{from._data, to._data, amount}; + NeoVmParamValue::ParamArray args{from._data, to._data, amount}; std::reverse(args.begin(), args.end()); std::string method{"transfer"}; - auto invokeCode = ParamsBuilder::buildOep4InvokeCode(wing_addr, method, args); + auto invokeCode = ParamsBuilder::buildOep4InvokeCode(wing_addr, method, {args}); auto expectCode = "02fd001496f688657b95be51c11a87b51adfda4ab69e9cbb1457e9d1a61f9aafa798b6c7fbeae35639681d7df653c1087472616e736665726733def739225d0f93dd2aed457d7b1fd074ec31ff"; EXPECT_EQ(expectCode, hex(invokeCode)); diff --git a/tests/Ontology/TransactionTests.cpp b/tests/Ontology/TransactionTests.cpp index 1954db1db33..633686b4ebf 100644 --- a/tests/Ontology/TransactionTests.cpp +++ b/tests/Ontology/TransactionTests.cpp @@ -25,9 +25,9 @@ TEST(OntologyTransaction, validity) { auto fromAddress = Address("AeicEjZyiXKgUeSBbYQHxsU1X3V5Buori5"); auto toAddress = Address("APniYDGozkhUh8Tk7pe35aah2HGJ4fJfVd"); uint64_t amount = 1; - std::list transferParam{fromAddress._data, toAddress._data, amount}; - std::vector args{transferParam}; - auto invokeCode = ParamsBuilder::buildNativeInvokeCode(ontContract, 0x00, "transfer", args); + NeoVmParamValue::ParamList transferParam{fromAddress._data, toAddress._data, amount}; + NeoVmParamValue::ParamArray args{transferParam}; + auto invokeCode = ParamsBuilder::buildNativeInvokeCode(ontContract, 0x00, "transfer", {args}); uint8_t version = 0; uint8_t txType = 0xd1; uint32_t nonce = 1552759011; From 3d6ea1ec1a35ba61c7722e9fda29220bc58e1bcf Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Thu, 1 Sep 2022 03:56:22 +0200 Subject: [PATCH 067/497] Swift sample app: Use BigInt for Eth amount serialization (#2549) --- samples/osx/cocoapods/Podfile | 1 + samples/osx/cocoapods/Podfile.lock | 6 +++++- .../osx/cocoapods/WalletCoreExample/ViewController.swift | 7 ++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/samples/osx/cocoapods/Podfile b/samples/osx/cocoapods/Podfile index b3a50e2550b..d071a6b7c05 100644 --- a/samples/osx/cocoapods/Podfile +++ b/samples/osx/cocoapods/Podfile @@ -3,5 +3,6 @@ platform :osx, '10.14' target 'WalletCoreExample' do use_frameworks! pod 'TrustWalletCore' + pod 'BigInt' end diff --git a/samples/osx/cocoapods/Podfile.lock b/samples/osx/cocoapods/Podfile.lock index 6c8fa80e818..bfe2d08725c 100644 --- a/samples/osx/cocoapods/Podfile.lock +++ b/samples/osx/cocoapods/Podfile.lock @@ -1,4 +1,5 @@ PODS: + - BigInt (5.2.0) - SwiftProtobuf (1.19.0) - TrustWalletCore (2.9.5): - TrustWalletCore/Core (= 2.9.5) @@ -8,17 +9,20 @@ PODS: - SwiftProtobuf DEPENDENCIES: + - BigInt - TrustWalletCore SPEC REPOS: trunk: + - BigInt - SwiftProtobuf - TrustWalletCore SPEC CHECKSUMS: + BigInt: f668a80089607f521586bbe29513d708491ef2f7 SwiftProtobuf: 6ef3f0e422ef90d6605ca20b21a94f6c1324d6b3 TrustWalletCore: 52ec9b10c17c8d7443e848ff0e6adac4d39be9f0 -PODFILE CHECKSUM: 68848e868fc9571d319a35d139d7901079a7fe36 +PODFILE CHECKSUM: 5fb79210604aff833a8320c937ea3849c2d9ac06 COCOAPODS: 1.11.3 diff --git a/samples/osx/cocoapods/WalletCoreExample/ViewController.swift b/samples/osx/cocoapods/WalletCoreExample/ViewController.swift index 22c7eb87acc..bb130d940b6 100644 --- a/samples/osx/cocoapods/WalletCoreExample/ViewController.swift +++ b/samples/osx/cocoapods/WalletCoreExample/ViewController.swift @@ -6,6 +6,7 @@ import Cocoa import WalletCore +import BigInt class ViewController: NSViewController { @@ -27,13 +28,13 @@ class ViewController: NSViewController { let dummyReceiverAddress = "0xC37054b3b48C3317082E7ba872d7753D13da4986" let signerInput = EthereumSigningInput.with { $0.chainID = Data(hexString: "01")! - $0.gasPrice = Data(hexString: "d693a400")! // decimal 3600000000 - $0.gasLimit = Data(hexString: "5208")! // decimal 21000 + $0.gasPrice = BigInt(3600000000).magnitude.serialize() + $0.gasLimit = BigInt(21000).magnitude.serialize() $0.toAddress = dummyReceiverAddress $0.transaction = EthereumTransaction.with { $0.transfer = EthereumTransaction.Transfer.with { - $0.amount = Data(hexString: "0348bca5a16000")! + $0.amount = BigInt(0.0009244*1000000000000000000).magnitude.serialize() } } $0.privateKey = secretPrivateKeyEth.data From 1114cf79bf23d8125c717924738522669adfd77f Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 2 Sep 2022 06:43:20 +0900 Subject: [PATCH 068/497] document wasm flags (#2551) --- wasm/CMakeLists.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/wasm/CMakeLists.txt b/wasm/CMakeLists.txt index 5a24ab5e4dc..379042f09e6 100644 --- a/wasm/CMakeLists.txt +++ b/wasm/CMakeLists.txt @@ -19,6 +19,24 @@ set_target_properties(${TARGET_NAME} CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON ) + +# We use a set of COMPILE_FLAGS and LINK_FLAGS, see below links for more details. +# - https://emscripten.org/docs/optimizing/Optimizing-Code.html#how-to-optimize-code +# - https://github.com/emscripten-core/emscripten/blob/main/src/settings.js +# - https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html?highlight=lembind#embind + +# STRICT: Emscripten 'strict' build mode, disables AUTO_NATIVE_LIBRARIES and AUTO_JS_LIBRARIES etc. +# ASSERTIONS: Enable runtime assertions. + +# MODULARIZE=1: Emit generated JavaScript code wrapped in a function that returns a promise. +# ALLOW_MEMORY_GROWTH=1: Allowing allocating more memory from the system as necessary. +# DYNAMIC_EXECUTION=0: Do not emit eval() and new Function() in the generated JavaScript code. + +# -O2: good old code optimization level for release. +# --bind: Link Embind library. +# --no-entry: Skip main entry point because it's built as a library. +# --closure 1: Enable Emscripten closure compiler to minimize generated JavaScript code size. + set_target_properties(${TARGET_NAME} PROPERTIES COMPILE_FLAGS "-O2 -sSTRICT -sUSE_BOOST_HEADERS=1" From e5889a452cea1b362c80922d80fd937c751c8307 Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Tue, 6 Sep 2022 13:31:55 +0100 Subject: [PATCH 069/497] [Fix] Even more fixes of namespace collisions in unity build (#2533) * [Fix] Even more fixes of namespace collisions in unity build * Hopefully add all of the namespace fixes * Fixup: missing std:: specifier * Fixup: attempt to fix linking issues * add clang-format off for Cbor/ bitcoin tests * remove empty cpp files * style / typo fix * update namespace for new coin templates * Fixup: fix warnings * Fix shadowing warnings Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- codegen/lib/templates/newcoin/Address.cpp.erb | 6 +- codegen/lib/templates/newcoin/Address.h.erb | 2 +- .../templates/newcoin/AddressTests.cpp.erb | 7 +- .../lib/templates/newcoin/AddressTests.kt.erb | 2 +- codegen/lib/templates/newcoin/Entry.cpp.erb | 11 +- codegen/lib/templates/newcoin/Entry.h.erb | 4 +- codegen/lib/templates/newcoin/Proto.erb | 2 +- codegen/lib/templates/newcoin/Signer.cpp.erb | 8 +- codegen/lib/templates/newcoin/Signer.h.erb | 2 +- .../lib/templates/newcoin/SignerTests.cpp.erb | 7 +- .../lib/templates/newcoin/SignerTests.kt.erb | 2 +- .../templates/newcoin/TWAddressTests.cpp.erb | 2 +- .../templates/newcoin/TWSignerTests.cpp.erb | 2 +- codegen/lib/templates/newcoin/Tests.swift.erb | 2 +- src/Algorand/Address.cpp | 8 +- src/Algorand/AssetTransfer.cpp | 7 +- src/Algorand/Entry.cpp | 13 +- src/Algorand/OptInAssetTransaction.cpp | 7 +- src/Algorand/Signer.cpp | 19 +- src/Algorand/Transfer.cpp | 8 +- src/Bech32.cpp | 21 +- src/Binance/Address.cpp | 8 +- src/Binance/Entry.cpp | 14 +- src/Binance/Serialization.cpp | 38 ++- src/Binance/Signer.cpp | 10 +- src/Bitcoin/Address.cpp | 11 - src/Bitcoin/CashAddress.cpp | 18 +- src/Bitcoin/Entry.cpp | 80 +++--- src/Bitcoin/InputSelector.cpp | 7 +- src/Bitcoin/OutPoint.cpp | 7 +- src/Bitcoin/Script.cpp | 21 +- src/Bitcoin/SegwitAddress.cpp | 7 +- src/Bitcoin/SignatureBuilder.cpp | 26 +- src/Bitcoin/Signer.cpp | 9 +- src/Bitcoin/SigningInput.cpp | 13 +- src/Bitcoin/Transaction.cpp | 13 +- src/Bitcoin/TransactionInput.cpp | 6 +- src/Bitcoin/TransactionOutput.cpp | 6 +- src/Bitcoin/TransactionSigner.cpp | 11 +- src/Cardano/AddressV2.cpp | 47 +-- src/Cardano/AddressV3.cpp | 23 +- src/Cardano/Entry.cpp | 13 +- src/Cardano/Signer.cpp | 83 +++--- src/Cardano/Transaction.cpp | 78 ++--- src/Cosmos/Signer.cpp | 20 +- src/Decred/Address.cpp | 6 +- src/Decred/Entry.cpp | 12 +- src/Decred/OutPoint.cpp | 6 +- src/Decred/Signer.cpp | 17 +- src/Decred/Transaction.cpp | 10 +- src/Decred/TransactionInput.cpp | 6 +- src/Decred/TransactionOutput.cpp | 6 +- src/EOS/Action.cpp | 16 +- src/EOS/Address.cpp | 37 ++- src/EOS/Asset.cpp | 20 +- src/EOS/Entry.cpp | 11 +- src/EOS/Name.cpp | 17 +- src/EOS/Name.h | 2 +- src/EOS/PackedTransaction.cpp | 10 +- src/EOS/Signer.cpp | 17 +- src/EOS/Transaction.cpp | 17 +- src/Elrond/Codec.cpp | 7 +- src/Elrond/GasEstimator.cpp | 27 +- src/Elrond/NetworkConfig.cpp | 14 +- src/Elrond/Signer.cpp | 11 +- src/Elrond/Transaction.cpp | 22 +- src/Elrond/TransactionFactory.cpp | 32 +-- src/Ethereum/ABI/Bytes.cpp | 7 +- src/Ethereum/ABI/Function.cpp | 21 +- src/Ethereum/ABI/ParamAddress.cpp | 7 +- src/Ethereum/ABI/ParamNumber.cpp | 29 +- src/Ethereum/ABI/ParamStruct.cpp | 24 +- src/Ethereum/ABI/Parameters.cpp | 13 +- src/Ethereum/ABI/Tuple.cpp | 10 +- src/Ethereum/Address.cpp | 7 +- src/Ethereum/AddressChecksum.cpp | 10 +- src/Ethereum/Entry.cpp | 10 +- src/Ethereum/RLP.cpp | 21 +- src/Ethereum/Signer.cpp | 267 +++++++++-------- src/Ethereum/Transaction.cpp | 121 ++++---- src/FIO/Actor.cpp | 35 +-- src/FIO/Entry.cpp | 11 +- src/Filecoin/Address.cpp | 8 +- src/Filecoin/Entry.cpp | 13 +- src/Filecoin/Signer.cpp | 10 +- src/Filecoin/Transaction.cpp | 12 +- src/Groestlcoin/Address.cpp | 8 +- src/Groestlcoin/Entry.cpp | 14 +- src/Groestlcoin/Signer.cpp | 7 +- src/Harmony/Signer.cpp | 19 +- src/Harmony/Staking.cpp | 4 - src/Harmony/Transaction.cpp | 9 - src/Icon/Address.cpp | 5 - src/Icon/Address.h | 2 +- src/Icon/Entry.cpp | 9 +- src/Icon/Signer.cpp | 9 +- src/IoTeX/Signer.cpp | 9 +- src/Keystore/AESParameters.cpp | 7 +- src/Keystore/Account.cpp | 26 +- src/Keystore/EncryptionParameters.cpp | 20 +- src/Keystore/PBKDF2Parameters.cpp | 11 +- src/Keystore/ScryptParameters.cpp | 16 +- src/Keystore/StoredKey.cpp | 13 +- src/Kusama/Entry.cpp | 12 +- src/NEAR/Account.cpp | 6 +- src/NEAR/Serialization.cpp | 76 ++--- src/NEAR/Signer.cpp | 7 +- src/NEO/Entry.cpp | 7 +- src/NEO/Signer.cpp | 16 +- src/NEO/Transaction.cpp | 48 ++-- src/Nano/Address.cpp | 20 +- src/Nano/Entry.cpp | 14 +- src/Nervos/CellDep.cpp | 5 +- src/Nervos/CellInput.cpp | 7 +- src/Nervos/CellOutput.cpp | 7 +- src/Nervos/OutPoint.cpp | 7 +- src/Nervos/Script.cpp | 9 +- src/Nervos/Signer.cpp | 5 +- src/Nervos/Transaction.cpp | 9 +- src/Nervos/Witness.cpp | 10 +- src/Nimiq/Address.cpp | 8 +- src/Nimiq/Address.h | 2 +- src/Nimiq/Entry.cpp | 12 +- src/Nimiq/Transaction.cpp | 7 +- src/Ontology/Entry.cpp | 9 +- src/Ontology/Ong.cpp | 15 +- src/Ontology/OngTxBuilder.cpp | 15 +- src/Ontology/Ont.cpp | 11 +- src/Ontology/OntTxBuilder.cpp | 13 +- src/Ontology/ParamsBuilder.cpp | 5 +- src/Ontology/SigData.cpp | 5 +- src/Ontology/Signer.cpp | 4 +- src/Ontology/Transaction.cpp | 8 +- src/Polkadot/Entry.cpp | 12 +- src/Polkadot/Extrinsic.cpp | 7 +- src/Ripple/Address.cpp | 4 +- src/Ripple/Entry.cpp | 11 +- src/Ripple/Signer.cpp | 25 +- src/Ripple/Transaction.cpp | 12 +- src/Ripple/XAddress.cpp | 17 +- src/Solana/Program.cpp | 20 +- src/Solana/Signer.cpp | 271 ++++++++---------- src/Solana/Transaction.cpp | 27 +- src/THORChain/TWSwap.cpp | 100 +++---- src/Tezos/Forging.cpp | 9 +- src/Tezos/Forging.h | 2 +- src/Tezos/OperationList.cpp | 9 +- src/Tezos/OperationList.h | 5 +- src/Tezos/Signer.cpp | 1 - src/Theta/Transaction.cpp | 22 +- src/Theta/Transaction.h | 4 +- src/Tron/Serialization.cpp | 148 +++++----- src/Tron/Signer.cpp | 29 +- src/VeChain/Transaction.cpp | 8 +- src/Zcash/TAddress.cpp | 9 - src/Zcash/TAddress.h | 2 +- src/Zcash/Transaction.cpp | 27 +- src/Zilliqa/Address.cpp | 6 +- src/Zilliqa/AddressChecksum.cpp | 11 +- src/Zilliqa/Entry.cpp | 15 +- src/Zilliqa/Signer.cpp | 8 +- tests/Aeternity/AddressTests.cpp | 12 +- tests/Aeternity/SignerTests.cpp | 7 +- tests/Aeternity/TWAnySignerTests.cpp | 9 +- tests/Aeternity/TransactionTests.cpp | 7 +- tests/Aion/RLPTests.cpp | 9 +- tests/Aion/SignerTests.cpp | 7 +- tests/Aion/TWAnySignerTests.cpp | 9 +- tests/Aion/TransactionTests.cpp | 9 +- tests/Base64Tests.cpp | 9 +- tests/BaseEncoding.cpp | 21 +- tests/Binance/TWAnySignerTests.cpp | 7 +- tests/BinanceSmartChain/SignerTests.cpp | 17 +- tests/Bitcoin/FeeCalculatorTests.cpp | 8 +- tests/Bitcoin/InputSelectorTests.cpp | 18 +- tests/Bitcoin/TWBitcoinSigningTests.cpp | 48 ++-- tests/Bitcoin/TWBitcoinTransactionTests.cpp | 12 +- tests/Bitcoin/TransactionPlanTests.cpp | 18 +- tests/Bitcoin/TxComparisonHelper.cpp | 37 +-- tests/Bitcoin/TxComparisonHelper.h | 10 +- tests/BitcoinGold/TWSignerTests.cpp | 23 +- tests/Cardano/TransactionTests.cpp | 49 ++-- tests/CborTests.cpp | 81 +++--- tests/Cosmos/ProtobufTests.cpp | 8 +- tests/Cosmos/SignerTests.cpp | 13 +- tests/Cosmos/StakingTests.cpp | 8 +- tests/Cosmos/TWAnySignerTests.cpp | 7 +- tests/CryptoOrg/AddressTests.cpp | 7 +- tests/CryptoOrg/SignerTests.cpp | 8 +- tests/Decred/AddressTests.cpp | 7 +- tests/DigiByte/TWDigiByteTests.cpp | 34 +-- tests/ECash/TWECashTests.cpp | 31 +- tests/EOS/AssetTests.cpp | 7 +- tests/EOS/NameTests.cpp | 14 +- tests/EOS/SignatureTests.cpp | 21 +- tests/EOS/TWAnySignerTests.cpp | 7 +- tests/Elrond/TransactionFactoryTests.cpp | 14 +- tests/Ethereum/AbiTests.cpp | 5 +- tests/Ethereum/ContractCallTests.cpp | 18 +- tests/Ethereum/RLPTests.cpp | 97 ++++--- tests/Ethereum/TWAnySignerTests.cpp | 44 ++- tests/Ethereum/ValueDecoderTests.cpp | 28 +- tests/Ethereum/ValueEncoderTests.cpp | 10 +- tests/FIO/AddressTests.cpp | 7 +- tests/FIO/EncryptionTests.cpp | 16 +- tests/FIO/SignerTests.cpp | 16 +- tests/FIO/TWFIOTests.cpp | 12 +- tests/FIO/TransactionBuilderTests.cpp | 9 +- tests/Groestlcoin/AddressTests.cpp | 7 +- .../Groestlcoin/TWGroestlcoinSigningTests.cpp | 8 +- tests/IoTeX/StakingTests.cpp | 12 +- tests/IoTeX/TWAnySignerTests.cpp | 8 +- tests/Kusama/AddressTests.cpp | 7 +- tests/Kusama/TWAnySignerTests.cpp | 5 +- tests/Monacoin/TWMonacoinTransactionTests.cpp | 11 +- tests/NEAR/AccountTests.cpp | 8 +- tests/NEAR/AddressTests.cpp | 13 +- tests/NEO/CoinReferenceTests.cpp | 9 +- tests/NEO/SignerTests.cpp | 16 +- tests/NEO/TWAnySignerTests.cpp | 11 +- tests/NEO/TransactionAttributeTests.cpp | 12 +- tests/NEO/TransactionOutputTests.cpp | 10 +- tests/NEO/TransactionTests.cpp | 15 +- tests/NEO/WitnessTests.cpp | 8 +- tests/NULS/AddressTests.cpp | 12 +- tests/NULS/TWAnySignerTests.cpp | 7 +- tests/Nebulas/AddressTests.cpp | 19 +- tests/Nebulas/TWAnySignerTests.cpp | 19 +- tests/Nebulas/TransactionTests.cpp | 20 +- tests/Ontology/AddressTests.cpp | 7 +- tests/Ontology/OngTests.cpp | 7 +- tests/Ontology/OntTests.cpp | 7 +- tests/Ontology/ParamsBuilderTests.cpp | 5 +- tests/Ontology/TransactionTests.cpp | 5 +- tests/Osmosis/AddressTests.cpp | 10 +- tests/Osmosis/SignerTests.cpp | 11 +- tests/Osmosis/TWAnySignerTests.cpp | 8 +- .../Ravencoin/TWRavencoinTransactionTests.cpp | 17 +- tests/Ripple/AddressTests.cpp | 25 +- tests/Ronin/TWAnySignerTests.cpp | 8 +- tests/Solana/TransactionTests.cpp | 6 +- tests/Stellar/TransactionTests.cpp | 10 +- tests/Terra/SignerTestsClassic.cpp | 8 +- tests/Tezos/ForgingTests.cpp | 9 +- tests/Tezos/PublicKeyTests.cpp | 5 +- tests/Theta/TransactionTests.cpp | 7 +- tests/VeChain/TWAnySignerTests.cpp | 7 +- tests/WalletConsoleTests.cpp | 37 ++- tests/Waves/TWAnySignerTests.cpp | 9 +- tests/Waves/TransactionTests.cpp | 43 ++- tests/Zilliqa/AddressTests.cpp | 22 +- tests/Zilliqa/SignerTests.cpp | 9 +- tests/Zilliqa/TWAnySignerTests.cpp | 7 +- 253 files changed, 2214 insertions(+), 2245 deletions(-) delete mode 100644 src/Bitcoin/Address.cpp delete mode 100644 src/Harmony/Transaction.cpp delete mode 100644 src/Zcash/TAddress.cpp diff --git a/codegen/lib/templates/newcoin/Address.cpp.erb b/codegen/lib/templates/newcoin/Address.cpp.erb index 0f15d92edcc..e9eb3b1412f 100644 --- a/codegen/lib/templates/newcoin/Address.cpp.erb +++ b/codegen/lib/templates/newcoin/Address.cpp.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,7 +6,7 @@ #include "Address.h" -using namespace TW::<%= format_name(coin) %>; +namespace TW::<%= format_name(coin) %> { bool Address::isValid(const std::string& string) { // TODO: Finalize implementation @@ -29,3 +29,5 @@ std::string Address::string() const { // TODO: Finalize implementation return "TODO"; } + +} // namespace TW::<%= format_name(coin) %> diff --git a/codegen/lib/templates/newcoin/Address.h.erb b/codegen/lib/templates/newcoin/Address.h.erb index 8ba3008d088..9c6f60df4f6 100644 --- a/codegen/lib/templates/newcoin/Address.h.erb +++ b/codegen/lib/templates/newcoin/Address.h.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/codegen/lib/templates/newcoin/AddressTests.cpp.erb b/codegen/lib/templates/newcoin/AddressTests.cpp.erb index 9953e01fbdc..ca9d99d3139 100644 --- a/codegen/lib/templates/newcoin/AddressTests.cpp.erb +++ b/codegen/lib/templates/newcoin/AddressTests.cpp.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,8 +11,7 @@ #include #include -using namespace TW; -using namespace TW::<%= format_name(coin) %>; +namespace TW::<%= format_name(coin) %>::tests { TEST(<%= format_name(coin) %>Address, Valid) { ASSERT_TRUE(Address::isValid("__ADD_VALID_ADDRESS_HERE__")); @@ -46,3 +45,5 @@ TEST(<%= format_name(coin) %>Address, FromString) { auto address = Address("__ADD_VALID_ADDRESS_HERE__"); ASSERT_EQ(address.string(), "__ADD_SAME_VALID_ADDRESS_HERE__"); } + +} // namespace TW::<%= format_name(coin) %>::tests diff --git a/codegen/lib/templates/newcoin/AddressTests.kt.erb b/codegen/lib/templates/newcoin/AddressTests.kt.erb index f118db94a20..34781800a4c 100644 --- a/codegen/lib/templates/newcoin/AddressTests.kt.erb +++ b/codegen/lib/templates/newcoin/AddressTests.kt.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/codegen/lib/templates/newcoin/Entry.cpp.erb b/codegen/lib/templates/newcoin/Entry.cpp.erb index 348e884d9f0..d0585ed64b9 100644 --- a/codegen/lib/templates/newcoin/Entry.cpp.erb +++ b/codegen/lib/templates/newcoin/Entry.cpp.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,19 +9,20 @@ #include "Address.h" #include "Signer.h" -using namespace TW::<%= format_name(coin) %>; -using namespace std; +namespace TW::<%= format_name(coin) %> { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress(TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::<%= format_name(coin) %> diff --git a/codegen/lib/templates/newcoin/Entry.h.erb b/codegen/lib/templates/newcoin/Entry.h.erb index b5105bac6ae..1b58f5f78cd 100644 --- a/codegen/lib/templates/newcoin/Entry.h.erb +++ b/codegen/lib/templates/newcoin/Entry.h.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,7 +12,7 @@ namespace TW::<%= format_name(coin) %> { /// Entry point for implementation of <%= format_name(coin) %> coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry : public CoinEntry { public: virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; diff --git a/codegen/lib/templates/newcoin/Proto.erb b/codegen/lib/templates/newcoin/Proto.erb index d7bdb047f8e..3065a609020 100644 --- a/codegen/lib/templates/newcoin/Proto.erb +++ b/codegen/lib/templates/newcoin/Proto.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/codegen/lib/templates/newcoin/Signer.cpp.erb b/codegen/lib/templates/newcoin/Signer.cpp.erb index 381832fb176..7dec6579529 100644 --- a/codegen/lib/templates/newcoin/Signer.cpp.erb +++ b/codegen/lib/templates/newcoin/Signer.cpp.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,9 +8,7 @@ #include "Address.h" #include "../PublicKey.h" -using namespace TW; -using namespace TW::<%= name %>; - +namespace TW::<%= name %> { Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { // TODO: Check and finalize implementation @@ -24,3 +22,5 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { protoOutput.set_encoded(encoded.data(), encoded.size()); return protoOutput; } + +} // namespace TW::<%= name %> diff --git a/codegen/lib/templates/newcoin/Signer.h.erb b/codegen/lib/templates/newcoin/Signer.h.erb index 7b04793f3c8..1261f9c6149 100644 --- a/codegen/lib/templates/newcoin/Signer.h.erb +++ b/codegen/lib/templates/newcoin/Signer.h.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/codegen/lib/templates/newcoin/SignerTests.cpp.erb b/codegen/lib/templates/newcoin/SignerTests.cpp.erb index 27eb5ef11ee..9df8b26ee1e 100644 --- a/codegen/lib/templates/newcoin/SignerTests.cpp.erb +++ b/codegen/lib/templates/newcoin/SignerTests.cpp.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,8 +12,7 @@ #include -using namespace TW; -using namespace TW::<%= format_name(coin) %>; +namespace TW::<%= format_name(coin) %>::tests { // TODO: Add tests @@ -32,3 +31,5 @@ TEST(<%= format_name(coin) %>Signer, Sign) { //ASSERT_EQ(hex(serialized), "__RESULT__"); //ASSERT_EQ(...) } + +} // namespace TW::<%= format_name(coin) %>::tests diff --git a/codegen/lib/templates/newcoin/SignerTests.kt.erb b/codegen/lib/templates/newcoin/SignerTests.kt.erb index ba0bbafcfd9..e0512c55b1d 100644 --- a/codegen/lib/templates/newcoin/SignerTests.kt.erb +++ b/codegen/lib/templates/newcoin/SignerTests.kt.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/codegen/lib/templates/newcoin/TWAddressTests.cpp.erb b/codegen/lib/templates/newcoin/TWAddressTests.cpp.erb index 11331829f38..0a4ea03764d 100644 --- a/codegen/lib/templates/newcoin/TWAddressTests.cpp.erb +++ b/codegen/lib/templates/newcoin/TWAddressTests.cpp.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/codegen/lib/templates/newcoin/TWSignerTests.cpp.erb b/codegen/lib/templates/newcoin/TWSignerTests.cpp.erb index a59a2fdc772..4e72ef5fa5f 100644 --- a/codegen/lib/templates/newcoin/TWSignerTests.cpp.erb +++ b/codegen/lib/templates/newcoin/TWSignerTests.cpp.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/codegen/lib/templates/newcoin/Tests.swift.erb b/codegen/lib/templates/newcoin/Tests.swift.erb index 58851cb7024..583696882c5 100644 --- a/codegen/lib/templates/newcoin/Tests.swift.erb +++ b/codegen/lib/templates/newcoin/Tests.swift.erb @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Algorand/Address.cpp b/src/Algorand/Address.cpp index 3e2b8d3b1fa..b0e4ede7229 100644 --- a/src/Algorand/Address.cpp +++ b/src/Algorand/Address.cpp @@ -1,17 +1,15 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. #include "Address.h" -#include "../HexCoding.h" -#include "../Hash.h" #include "../Base32.h" #include -using namespace TW::Algorand; +namespace TW::Algorand { bool Address::isValid(const std::string& string) { if (string.size() != encodedSize) { @@ -63,3 +61,5 @@ std::string Address::string() const { std::string encoded = Base32::encode(data); return encoded; } + +} // namespace TW::Algorand diff --git a/src/Algorand/AssetTransfer.cpp b/src/Algorand/AssetTransfer.cpp index eecb4cf8335..3f4c1a4eccd 100644 --- a/src/Algorand/AssetTransfer.cpp +++ b/src/Algorand/AssetTransfer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,8 +7,7 @@ #include "AssetTransfer.h" #include "BinaryCoding.h" -using namespace TW; -using namespace TW::Algorand; +namespace TW::Algorand { Data AssetTransfer::serialize() const { Data data; @@ -59,3 +58,5 @@ Data AssetTransfer::serialize() const { return data; } + +} // namespace TW::Algorand diff --git a/src/Algorand/Entry.cpp b/src/Algorand/Entry.cpp index eb905d043d0..2f090b1ca5b 100644 --- a/src/Algorand/Entry.cpp +++ b/src/Algorand/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,16 +9,15 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Algorand; -using namespace std; +namespace TW::Algorand { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } @@ -26,6 +25,8 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D signTemplate(dataIn, dataOut); } -string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { +std::string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } + +} // namespace TW::Algorand diff --git a/src/Algorand/OptInAssetTransaction.cpp b/src/Algorand/OptInAssetTransaction.cpp index f83df502f78..e62488d48e1 100644 --- a/src/Algorand/OptInAssetTransaction.cpp +++ b/src/Algorand/OptInAssetTransaction.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,8 +7,7 @@ #include "OptInAssetTransaction.h" #include "BinaryCoding.h" -using namespace TW; -using namespace TW::Algorand; +namespace TW::Algorand { Data OptInAssetTransaction::serialize() const { Data data; @@ -56,3 +55,5 @@ Data OptInAssetTransaction::serialize() const { return data; } + +} // namespace TW::Algorand diff --git a/src/Algorand/Signer.cpp b/src/Algorand/Signer.cpp index f979b24fdf9..3f24ba4801a 100644 --- a/src/Algorand/Signer.cpp +++ b/src/Algorand/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,14 +11,13 @@ #include -using namespace TW; -using namespace TW::Algorand; +namespace TW::Algorand { const Data TRANSACTION_TAG = {84, 88}; const std::string TRANSACTION_PAY = "pay"; const std::string ASSET_TRANSACTION = "axfer"; -Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { +Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto protoOutput = Proto::SigningOutput(); auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); auto pubkey = key.getPublicKey(TWPublicKeyTypeED25519); @@ -35,7 +34,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { auto to = Address(message.to_address()); auto transaction = Transfer(from, to, fee, message.amount(), firstRound, - lastRound, note, TRANSACTION_PAY, genesisId, genesisHash); + lastRound, note, TRANSACTION_PAY, genesisId, genesisHash); auto signature = sign(key, transaction); auto serialized = transaction.BaseTransaction::serialize(signature); protoOutput.set_encoded(serialized.data(), serialized.size()); @@ -45,8 +44,8 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { auto transaction = AssetTransfer(from, to, fee, message.amount(), - message.asset_id(), firstRound, lastRound, note, - ASSET_TRANSACTION,genesisId, genesisHash); + message.asset_id(), firstRound, lastRound, note, + ASSET_TRANSACTION, genesisId, genesisHash); auto signature = sign(key, transaction); auto serialized = transaction.BaseTransaction::serialize(signature); protoOutput.set_encoded(serialized.data(), serialized.size()); @@ -55,12 +54,12 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { auto transaction = OptInAssetTransaction(from, fee, message.asset_id(), firstRound, lastRound, note, - ASSET_TRANSACTION,genesisId, genesisHash); + ASSET_TRANSACTION, genesisId, genesisHash); auto signature = sign(key, transaction); auto serialized = transaction.BaseTransaction::serialize(signature); protoOutput.set_encoded(serialized.data(), serialized.size()); } - + return protoOutput; } @@ -78,3 +77,5 @@ Data Signer::sign(const PrivateKey& privateKey, const BaseTransaction& transacti auto signature = privateKey.sign(data, TWCurveED25519); return Data(signature.begin(), signature.end()); } + +} // namespace TW::Algorand diff --git a/src/Algorand/Transfer.cpp b/src/Algorand/Transfer.cpp index 325026ea69b..dd470ddae22 100644 --- a/src/Algorand/Transfer.cpp +++ b/src/Algorand/Transfer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,10 +6,8 @@ #include "Transfer.h" #include "BinaryCoding.h" -#include "../HexCoding.h" -using namespace TW; -using namespace TW::Algorand; +namespace TW::Algorand { Data Transfer::serialize() const { /* Algorand transaction is encoded with msgpack @@ -76,3 +74,5 @@ Data Transfer::serialize() const { encodeString(type, data); return data; } + +} // namespace TW::Algorand diff --git a/src/Bech32.cpp b/src/Bech32.cpp index f1c6699eba6..a309f45c2a2 100644 --- a/src/Bech32.cpp +++ b/src/Bech32.cpp @@ -14,9 +14,11 @@ // Bech32M variant also supported (BIP350) // Max length of 90 constraint is extended here to 120 for other usages -using namespace TW::Bech32; + using namespace TW; +namespace TW::Bech32 { + namespace { /** The Bech32 character set for encoding. */ @@ -26,15 +28,14 @@ const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; constexpr std::array charset_rev = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, -1, 29, - -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, - 6, 4, 2, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, - 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1}; + -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, -1, 29, + -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, + 6, 4, 2, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, + 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1}; const uint32_t BECH32_XOR_CONST = 0x01; const uint32_t BECH32M_XOR_CONST = 0x2bc830a3; - /** Find the polynomial with value coefficients mod the generator as 30-bit. */ uint32_t polymod(const Data& values) { uint32_t chk = 1; @@ -105,7 +106,7 @@ Data create_checksum(const std::string& hrp, const Data& values, ChecksumVariant } // namespace /** Encode a Bech32 string. */ -std::string Bech32::encode(const std::string& hrp, const Data& values, ChecksumVariant variant) { +std::string encode(const std::string& hrp, const Data& values, ChecksumVariant variant) { Data checksum = create_checksum(hrp, values, variant); Data combined = values; append(combined, checksum); @@ -118,7 +119,7 @@ std::string Bech32::encode(const std::string& hrp, const Data& values, ChecksumV } /** Decode a Bech32 string. */ -std::tuple Bech32::decode(const std::string& str) { +std::tuple decode(const std::string& str) { if (str.length() > 120 || str.length() < 2) { // too long or too short return std::make_tuple(std::string(), Data(), None); @@ -141,7 +142,7 @@ std::tuple Bech32::decode(const std::string& ok = false; } size_t pos = str.rfind('1'); - if (ok && pos != str.npos && pos >= 1 && pos + 7 <= str.size()) { + if (ok && pos != std::string::npos && pos >= 1 && pos + 7 <= str.size()) { Data values; values.resize(str.size() - 1 - pos); for (size_t i = 0; i < str.size() - 1 - pos; ++i) { @@ -164,3 +165,5 @@ std::tuple Bech32::decode(const std::string& } return std::make_tuple(std::string(), Data(), None); } + +} // namespace TW::Bech32 diff --git a/src/Binance/Address.cpp b/src/Binance/Address.cpp index a7313dec8f1..67f5bab7559 100644 --- a/src/Binance/Address.cpp +++ b/src/Binance/Address.cpp @@ -1,5 +1,5 @@ // Copyright © 2017 Pieter Wuille -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,7 +10,7 @@ #include #include -using namespace TW::Binance; +namespace TW::Binance { const std::string Address::_hrp = HRP_BINANCE; const std::string Address::hrpValidator = "bva"; @@ -22,10 +22,12 @@ bool Address::isValid(const std::string& addr) { } bool Address::decode(const std::string& addr, Address& obj_out) { - for (const auto& hrp: validHrps) { + for (const auto& hrp : validHrps) { if (Bech32Address::decode(addr, obj_out, hrp)) { return true; } } return false; } + +} // namespace TW::Binance diff --git a/src/Binance/Entry.cpp b/src/Binance/Entry.cpp index 7fb78263463..e288581e3f6 100644 --- a/src/Binance/Entry.cpp +++ b/src/Binance/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,15 +11,13 @@ #include "Coin.h" #include "Signer.h" -using namespace TW::Binance; -using namespace TW; -using namespace std; +namespace TW::Binance { -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } @@ -35,7 +33,7 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D signTemplate(dataIn, dataOut); } -string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { +std::string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } @@ -109,3 +107,5 @@ Data Entry::buildTransactionInput([[maybe_unused]] TWCoinType coinType, const st const auto txInputData = data(input.SerializeAsString()); return txInputData; } + +} // namespace TW::Binance diff --git a/src/Binance/Serialization.cpp b/src/Binance/Serialization.cpp index 2869341207b..cdf0b83bb58 100644 --- a/src/Binance/Serialization.cpp +++ b/src/Binance/Serialization.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,9 +11,7 @@ #include "Ethereum/Address.h" #include "../HexCoding.h" -using namespace TW; -using namespace TW::Binance; -using namespace google::protobuf; +namespace TW::Binance { using json = nlohmann::json; @@ -27,7 +25,7 @@ static inline std::string validatorAddress(const std::string& bytes) { return Bech32Address(Address::hrpValidator, data).string(); } -json Binance::signatureJSON(const Proto::SigningInput& input) { +json signatureJSON(const Proto::SigningInput& input) { json j; j["account_number"] = std::to_string(input.account_number()); j["chain_id"] = input.chain_id(); @@ -39,7 +37,7 @@ json Binance::signatureJSON(const Proto::SigningInput& input) { return j; } -json Binance::orderJSON(const Proto::SigningInput& input) { +json orderJSON(const Proto::SigningInput& input) { json j; if (input.has_trade_order()) { j["id"] = input.trade_order().id(); @@ -98,7 +96,7 @@ json Binance::orderJSON(const Proto::SigningInput& input) { j["type"] = "cosmos-sdk/MsgSideChainDelegate"; j["value"] = { {"delegator_addr", addressString(input.side_delegate_order().delegator_addr())}, - {"validator_addr",validatorAddress(input.side_delegate_order().validator_addr())}, + {"validator_addr", validatorAddress(input.side_delegate_order().validator_addr())}, {"delegation", tokenJSON(input.side_delegate_order().delegation(), true)}, {"side_chain_id", input.side_delegate_order().chain_id()}, }; @@ -131,7 +129,7 @@ json Binance::orderJSON(const Proto::SigningInput& input) { j["description"] = input.time_relock_order().description(); // if amount is empty or omitted, set null to avoid signature verification error j["amount"] = nullptr; - if (amount.size() > 0) { + if (!amount.empty()) { j["amount"] = tokensJSON(amount); } j["lock_time"] = input.time_relock_order().lock_time(); @@ -142,30 +140,26 @@ json Binance::orderJSON(const Proto::SigningInput& input) { return j; } -json Binance::inputsJSON(const Proto::SendOrder& order) { +json inputsJSON(const Proto::SendOrder& order) { json j = json::array(); for (auto& input : order.inputs()) { - j.push_back({ - {"address", addressString(input.address())}, - {"coins", tokensJSON(input.coins())} - }); + j.push_back({{"address", addressString(input.address())}, + {"coins", tokensJSON(input.coins())}}); } return j; } -json Binance::outputsJSON(const Proto::SendOrder& order) { +json outputsJSON(const Proto::SendOrder& order) { json j = json::array(); for (auto& output : order.outputs()) { - j.push_back({ - {"address", addressString(output.address())}, - {"coins", tokensJSON(output.coins())} - }); + j.push_back({{"address", addressString(output.address())}, + {"coins", tokensJSON(output.coins())}}); } return j; } -json Binance::tokenJSON(const Proto::SendOrder_Token& token, bool stringAmount) { - json j = { {"denom", token.denom()} }; +json tokenJSON(const Proto::SendOrder_Token& token, bool stringAmount) { + json j = {{"denom", token.denom()}}; if (stringAmount) { j["amount"] = std::to_string(token.amount()); } else { @@ -174,10 +168,12 @@ json Binance::tokenJSON(const Proto::SendOrder_Token& token, bool stringAmount) return j; } -json Binance::tokensJSON(const RepeatedPtrField& tokens) { +json tokensJSON(const google::protobuf::RepeatedPtrField& tokens) { json j = json::array(); for (auto& token : tokens) { j.push_back(tokenJSON(token)); } return j; } + +} // namespace TW::Binance diff --git a/src/Binance/Signer.cpp b/src/Binance/Signer.cpp index 4a535d65e7b..81de18da848 100644 --- a/src/Binance/Signer.cpp +++ b/src/Binance/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,7 +6,6 @@ #include "Signer.h" #include "Serialization.h" -#include "../Hash.h" #include "../HexCoding.h" #include "../PrivateKey.h" @@ -16,8 +15,7 @@ #include -using namespace TW; -using namespace TW::Binance; +namespace TW::Binance { // Message prefixes // see https://docs.binance.org/api-reference/transactions.html#amino-types @@ -90,7 +88,7 @@ Proto::SigningOutput Signer::compile(const Data& signature, const PublicKey& pub const auto encoded = encodeTransaction(encodeSignature(signature, publicKey)); auto output = Proto::SigningOutput(); output.set_encoded(encoded.data(), encoded.size()); - return output; + return output; } std::string Signer::signaturePreimage() const { @@ -217,3 +215,5 @@ Data Signer::aminoWrap(const std::string& raw, const Data& typePrefix, bool pref return Data(msg.begin(), msg.end()); } + +} // namespace TW::Binance diff --git a/src/Bitcoin/Address.cpp b/src/Bitcoin/Address.cpp deleted file mode 100644 index 5aa19d29eab..00000000000 --- a/src/Bitcoin/Address.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright © 2017-2020 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -#include "Address.h" - -#include "../Base58.h" - -using namespace TW::Bitcoin; diff --git a/src/Bitcoin/CashAddress.cpp b/src/Bitcoin/CashAddress.cpp index f0c8b8d0a0c..86852f0f472 100644 --- a/src/Bitcoin/CashAddress.cpp +++ b/src/Bitcoin/CashAddress.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -14,13 +14,15 @@ #include #include -using namespace TW::Bitcoin; -using namespace TW; +namespace TW::Bitcoin { /// From https://github.com/bitcoincashorg/bitcoincash.org/blob/master/spec/cashaddr.md namespace { -enum class Version : uint8_t { p2kh = 0x00, p2sh = 0x08 }; +enum class Version : uint8_t { + p2kh = 0x00, + p2sh = 0x08 +}; constexpr size_t maxHRPSize{20}; constexpr size_t maxDataSize{104}; @@ -61,7 +63,8 @@ bool CashAddress::isValid(const std::string& hrp, const std::string& string) noe std::string(decodedHRP.data()).compare(0, std::min(hrp.size(), maxHRPSize), hrp) == 0; } -CashAddress::CashAddress(const std::string& hrp, const std::string& string) : hrp(hrp) { +CashAddress::CashAddress(const std::string& hrp, const std::string& string) + : hrp(hrp) { const auto withPrefix = details::buildPrefix(hrp, string); std::array decodedHRP{}; std::array data{}; @@ -75,7 +78,8 @@ CashAddress::CashAddress(const std::string& hrp, const std::string& string) : hr std::copy(data.begin(), data.begin() + dataLen, bytes.begin()); } -CashAddress::CashAddress(std::string hrp, const PublicKey& publicKey) : hrp(std::move(hrp)) { +CashAddress::CashAddress(std::string hrp, const PublicKey& publicKey) + : hrp(std::move(hrp)) { if (publicKey.type != TWPublicKeyTypeSECP256k1) { throw std::invalid_argument("CashAddress needs a compressed SECP256k1 public key."); } @@ -111,3 +115,5 @@ Data CashAddress::getData() const { cash_data_to_addr(data.data(), &outlen, bytes.data(), CashAddress::size); return data; } + +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/Entry.cpp b/src/Bitcoin/Entry.cpp index 6d133133ef7..33301452f64 100644 --- a/src/Bitcoin/Entry.cpp +++ b/src/Bitcoin/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,13 +11,9 @@ #include "SegwitAddress.h" #include "Signer.h" -#include +namespace TW::Bitcoin { -using namespace TW::Bitcoin; -using namespace TW; -using namespace std; - -bool Entry::validateAddress(TWCoinType coin, const string& address, byte p2pkh, byte p2sh, +bool Entry::validateAddress(TWCoinType coin, const std::string& address, byte p2pkh, byte p2sh, const char* hrp) const { switch (coin) { case TWCoinTypeBitcoin: @@ -44,7 +40,7 @@ bool Entry::validateAddress(TWCoinType coin, const string& address, byte p2pkh, } } -string Entry::normalizeAddress(TWCoinType coin, const string& address) const { +std::string Entry::normalizeAddress(TWCoinType coin, const std::string& address) const { switch (coin) { case TWCoinTypeBitcoinCash: // normalized with bitcoincash: prefix @@ -66,7 +62,7 @@ string Entry::normalizeAddress(TWCoinType coin, const string& address) const { } } -string Entry::deriveAddress(TWCoinType coin, TWDerivation derivation, const PublicKey& publicKey, +std::string Entry::deriveAddress(TWCoinType coin, TWDerivation derivation, const PublicKey& publicKey, byte p2pkh, const char* hrp) const { switch (coin) { case TWCoinTypeBitcoin: @@ -104,46 +100,44 @@ string Entry::deriveAddress(TWCoinType coin, TWDerivation derivation, const Publ } } -template +template inline Data cashAddressToData(const CashAddress&& addr) { return subData(addr.getData(), 1); } Data Entry::addressToData(TWCoinType coin, const std::string& address) const { switch (coin) { - case TWCoinTypeBitcoin: - case TWCoinTypeBitcoinGold: - case TWCoinTypeDigiByte: - case TWCoinTypeGroestlcoin: - case TWCoinTypeLitecoin: - case TWCoinTypeViacoin: - { - const auto decoded = SegwitAddress::decode(address); - if (!std::get<2>(decoded)) { - return Data(); - } - return std::get<0>(decoded).witnessProgram; - } - - case TWCoinTypeBitcoinCash: - return cashAddressToData(BitcoinCashAddress(address)); - - case TWCoinTypeECash: - return cashAddressToData(ECashAddress(address)); - - case TWCoinTypeDash: - case TWCoinTypeDogecoin: - case TWCoinTypeMonacoin: - case TWCoinTypeQtum: - case TWCoinTypeRavencoin: - case TWCoinTypeFiro: - { - const auto addr = Address(address); - return {addr.bytes.begin() + 1, addr.bytes.end()}; - } - - default: + case TWCoinTypeBitcoin: + case TWCoinTypeBitcoinGold: + case TWCoinTypeDigiByte: + case TWCoinTypeGroestlcoin: + case TWCoinTypeLitecoin: + case TWCoinTypeViacoin: { + const auto decoded = SegwitAddress::decode(address); + if (!std::get<2>(decoded)) { return Data(); + } + return std::get<0>(decoded).witnessProgram; + } + + case TWCoinTypeBitcoinCash: + return cashAddressToData(BitcoinCashAddress(address)); + + case TWCoinTypeECash: + return cashAddressToData(ECashAddress(address)); + + case TWCoinTypeDash: + case TWCoinTypeDogecoin: + case TWCoinTypeMonacoin: + case TWCoinTypeQtum: + case TWCoinTypeRavencoin: + case TWCoinTypeFiro: { + const auto addr = Address(address); + return {addr.bytes.begin() + 1, addr.bytes.end()}; + } + + default: + return Data(); } } @@ -187,3 +181,5 @@ void Entry::compile([[maybe_unused]] TWCoinType coin, const Data& txInputData, c dataOut = txCompilerTemplate(txInputData, txCompilerFunctor); } + +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/InputSelector.cpp b/src/Bitcoin/InputSelector.cpp index ada32d497d2..9564e67fa20 100644 --- a/src/Bitcoin/InputSelector.cpp +++ b/src/Bitcoin/InputSelector.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,8 +12,7 @@ #include #include -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { template uint64_t InputSelector::sum(const std::vector& amounts) noexcept { @@ -208,3 +207,5 @@ InputSelector::selectMaxAmount(int64_t byteFee) noexcept { // Explicitly instantiate template class Bitcoin::InputSelector; + +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/OutPoint.cpp b/src/Bitcoin/OutPoint.cpp index 66013356772..922f23d35de 100644 --- a/src/Bitcoin/OutPoint.cpp +++ b/src/Bitcoin/OutPoint.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,10 +8,13 @@ #include "../BinaryCoding.h" -using namespace TW::Bitcoin; +namespace TW::Bitcoin { void OutPoint::encode(Data& data) const noexcept { std::copy(std::begin(hash), std::end(hash), std::back_inserter(data)); encode32LE(index, data); // sequence is encoded in TransactionInputs } + +} // namespace TW::Bitcoin + diff --git a/src/Bitcoin/Script.cpp b/src/Bitcoin/Script.cpp index 26a468d0b14..7000814c396 100644 --- a/src/Bitcoin/Script.cpp +++ b/src/Bitcoin/Script.cpp @@ -1,35 +1,26 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Script.h" - #include "Address.h" #include "CashAddress.h" +#include "OpCodes.h" +#include "Script.h" #include "SegwitAddress.h" -#include "../Base58.h" -#include "../Coin.h" - #include "../BinaryCoding.h" -#include "../Data.h" +#include "../Coin.h" #include "../Decred/Address.h" #include "../Groestlcoin/Address.h" -#include "../Hash.h" -#include "../PublicKey.h" #include "../Zcash/TAddress.h" -#include "OpCodes.h" - #include #include #include -#include -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { Data Script::hash() const { return Hash::ripemd(Hash::sha256(bytes)); @@ -350,3 +341,5 @@ Script Script::lockScriptForAddress(const std::string& string, enum TWCoinType c } return {}; } + +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/SegwitAddress.cpp b/src/Bitcoin/SegwitAddress.cpp index 2a2619aa1f4..4e40ce06ab7 100644 --- a/src/Bitcoin/SegwitAddress.cpp +++ b/src/Bitcoin/SegwitAddress.cpp @@ -1,5 +1,5 @@ // Copyright © 2017 Pieter Wuille -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,9 +9,8 @@ #include "../Bech32.h" #include -#include -using namespace TW::Bitcoin; +namespace TW::Bitcoin { bool SegwitAddress::isValid(const std::string& string) { return std::get<2>(decode(string)); @@ -103,3 +102,5 @@ std::pair SegwitAddress::fromRaw(const std::string& hrp, co return std::make_pair(SegwitAddress(hrp, data[0], conv), true); } + +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/SignatureBuilder.cpp b/src/Bitcoin/SignatureBuilder.cpp index 46decd9be3a..cec92f1b21d 100644 --- a/src/Bitcoin/SignatureBuilder.cpp +++ b/src/Bitcoin/SignatureBuilder.cpp @@ -1,26 +1,21 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. #include "SignatureBuilder.h" - #include "SigHashType.h" #include "TransactionInput.h" #include "TransactionOutput.h" -#include "InputSelector.h" #include "../BinaryCoding.h" -#include "../Hash.h" #include "../HexCoding.h" - #include "../Groestlcoin/Transaction.h" #include "../Zcash/Transaction.h" #include "../Zcash/TransactionBuilder.h" -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { template Result SignatureBuilder::sign() { @@ -62,7 +57,7 @@ Result SignatureBuilder:: template Result SignatureBuilder::sign(Script script, size_t index, - const UTXO& utxo) { + const UTXO& utxo) { assert(index < _transaction.inputs.size()); Script redeemScript; @@ -71,7 +66,7 @@ Result SignatureBuilder::sign(Sc uint32_t signatureVersion = [this]() { if ((input.hashType & TWBitcoinSigHashTypeFork) != 0) { return WITNESS_V0; - } + } return BASE; }(); auto result = signStep(script, index, utxo, signatureVersion); @@ -238,15 +233,14 @@ Data SignatureBuilder::createSignature( const std::optional& pair, size_t index, Amount amount, - uint32_t version -) { + uint32_t version) { if (signingMode == SigningMode_SizeEstimationOnly) { // Don't sign, only estimate signature size. It is 71-72 bytes. Return placeholder. return Data(72); } const Data sighash = transaction.getSignatureHash(script, index, input.hashType, amount, - static_cast(version)); + static_cast(version)); if (signingMode == SigningMode_HashOnly) { // Don't sign, only store hash-to-be-signed + pubkeyhash. Return placeholder. @@ -345,6 +339,8 @@ Data SignatureBuilder::scriptForScriptHash(const Data& hash) const } // Explicitly instantiate a Signers for compatible transactions. -template class Bitcoin::SignatureBuilder; -template class Bitcoin::SignatureBuilder; -template class Bitcoin::SignatureBuilder; +template class SignatureBuilder; +template class SignatureBuilder; +template class SignatureBuilder; + +} // namespace TW::Bitcoin \ No newline at end of file diff --git a/src/Bitcoin/Signer.cpp b/src/Bitcoin/Signer.cpp index 6e8670f89df..ac00533c2a5 100644 --- a/src/Bitcoin/Signer.cpp +++ b/src/Bitcoin/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -13,15 +13,14 @@ #include "proto/Common.pb.h" -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { Proto::TransactionPlan Signer::plan(const Proto::SigningInput& input) noexcept { auto plan = TransactionSigner::plan(input); return plan.proto(); } -Proto::SigningOutput Signer::sign(const Proto::SigningInput &input, std::optional optionalExternalSigs) noexcept { +Proto::SigningOutput Signer::sign(const Proto::SigningInput& input, std::optional optionalExternalSigs) noexcept { Proto::SigningOutput output; auto result = TransactionSigner::sign(input, false, optionalExternalSigs); if (!result) { @@ -65,3 +64,5 @@ Proto::PreSigningOutput Signer::preImageHashes(const Proto::SigningInput& input) } return output; } + +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/SigningInput.cpp b/src/Bitcoin/SigningInput.cpp index 20b7647ec89..a244e62952b 100644 --- a/src/Bitcoin/SigningInput.cpp +++ b/src/Bitcoin/SigningInput.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,8 +6,7 @@ #include "SigningInput.h" -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { SigningInput::SigningInput(const Proto::SigningInput& input) { hashType = static_cast(input.hash_type()); @@ -15,13 +14,13 @@ SigningInput::SigningInput(const Proto::SigningInput& input) { byteFee = input.byte_fee(); toAddress = input.to_address(); changeAddress = input.change_address(); - for (auto&& key: input.private_key()) { + for (auto&& key : input.private_key()) { privateKeys.emplace_back(key); } - for (auto&& script: input.scripts()) { + for (auto&& script : input.scripts()) { scripts[script.first] = Script(script.second.begin(), script.second.end()); } - for (auto&& u: input.utxo()) { + for (auto&& u : input.utxo()) { utxos.emplace_back(u); } useMaxAmount = input.use_max_amount(); @@ -32,3 +31,5 @@ SigningInput::SigningInput(const Proto::SigningInput& input) { outputOpReturn = data(input.output_op_return()); lockTime = input.lock_time(); } + +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/Transaction.cpp b/src/Bitcoin/Transaction.cpp index b4ee1ccd4b8..1b2a17c8676 100644 --- a/src/Bitcoin/Transaction.cpp +++ b/src/Bitcoin/Transaction.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,17 +6,14 @@ #include "Transaction.h" #include "SegwitAddress.h" +#include "SignatureVersion.h" #include "SigHashType.h" -#include "../BinaryCoding.h" -#include "../Data.h" -#include "../Hash.h" -#include "SignatureVersion.h" +#include "../BinaryCoding.h" #include -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { Data Transaction::getPreImage(const Script& scriptCode, size_t index, enum TWBitcoinSigHashType hashType, uint64_t amount) const { @@ -261,3 +258,5 @@ Proto::Transaction Transaction::proto() const { return protoTx; } + +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/TransactionInput.cpp b/src/Bitcoin/TransactionInput.cpp index 6d59f5536b8..7c43f07e0aa 100644 --- a/src/Bitcoin/TransactionInput.cpp +++ b/src/Bitcoin/TransactionInput.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,7 +8,7 @@ #include "../BinaryCoding.h" -using namespace TW::Bitcoin; +namespace TW::Bitcoin { void TransactionInput::encode(Data& data) const { auto& outpoint = reinterpret_cast(previousOutput); @@ -24,3 +24,5 @@ void TransactionInput::encodeWitness(Data& data) const { std::copy(std::begin(item), std::end(item), std::back_inserter(data)); } } + +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/TransactionOutput.cpp b/src/Bitcoin/TransactionOutput.cpp index e21b9668737..7f36e02fce7 100644 --- a/src/Bitcoin/TransactionOutput.cpp +++ b/src/Bitcoin/TransactionOutput.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,9 +8,11 @@ #include "../BinaryCoding.h" -using namespace TW::Bitcoin; +namespace TW::Bitcoin { void TransactionOutput::encode(Data& data) const { encode64LE(value, data); script.encode(data); } + +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/TransactionSigner.cpp b/src/Bitcoin/TransactionSigner.cpp index f48e707d6dc..0e87be108e8 100644 --- a/src/Bitcoin/TransactionSigner.cpp +++ b/src/Bitcoin/TransactionSigner.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,8 +12,7 @@ #include "../Zcash/Transaction.h" #include "../Zcash/TransactionBuilder.h" -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { template TransactionPlan TransactionSigner::plan(const SigningInput& input) { @@ -30,8 +29,8 @@ Result TransactionSigner(plan, input.toAddress, input.changeAddress, input.coinType, input.lockTime); SigningMode signingMode = - estimationMode ? SigningMode_SizeEstimationOnly : - optionalExternalSigs.has_value() ? SigningMode_External : SigningMode_Normal; + estimationMode ? SigningMode_SizeEstimationOnly : optionalExternalSigs.has_value() ? SigningMode_External + : SigningMode_Normal; SignatureBuilder signer(std::move(input), plan, transaction, signingMode, optionalExternalSigs); return signer.sign(); } @@ -57,3 +56,5 @@ Result TransactionSigner; template class Bitcoin::TransactionSigner; template class Bitcoin::TransactionSigner; + +} // namespace TW::Bitcoin diff --git a/src/Cardano/AddressV2.cpp b/src/Cardano/AddressV2.cpp index a6dba3d96a7..4ee32568cfb 100644 --- a/src/Cardano/AddressV2.cpp +++ b/src/Cardano/AddressV2.cpp @@ -1,47 +1,42 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. #include "AddressV2.h" -#include "../Cbor.h" -#include "../Data.h" #include "../Base58.h" +#include "../Cbor.h" #include "../Crc.h" -#include "../HexCoding.h" -#include "../Hash.h" #include -using namespace TW; -using namespace TW::Cardano; -using namespace std; +namespace TW::Cardano { bool AddressV2::parseAndCheck(const std::string& addr, Data& root_out, Data& attrs_out, byte& type_out) { // Decode Bas58, decode payload + crc, decode root, attr Data base58decoded = Base58::bitcoin.decode(addr); if (base58decoded.size() == 0) { - throw invalid_argument("Invalid address: could not Base58 decode"); + throw std::invalid_argument("Invalid address: could not Base58 decode"); } auto elems = Cbor::Decode(base58decoded).getArrayElements(); if (elems.size() < 2) { - throw invalid_argument("Could not parse address payload from CBOR data"); + throw std::invalid_argument("Could not parse address payload from CBOR data"); } auto tag = elems[0].getTagValue(); if (tag != PayloadTag) { - throw invalid_argument("wrong tag value"); + throw std::invalid_argument("wrong tag value"); } Data payload = elems[0].getTagElement().getBytes(); uint64_t crcPresent = (uint32_t)elems[1].getValue(); uint32_t crcComputed = TW::Crc::crc32(payload); if (crcPresent != crcComputed) { - throw invalid_argument("CRC mismatch"); + throw std::invalid_argument("CRC mismatch"); } // parse payload, 3 elements auto payloadElems = Cbor::Decode(payload).getArrayElements(); if (payloadElems.size() < 3) { - throw invalid_argument("Could not parse address root and attrs from CBOR data"); + throw std::invalid_argument("Could not parse address root and attrs from CBOR data"); } root_out = payloadElems[0].getBytes(); attrs_out = payloadElems[1].encoded(); // map, but encoded as bytes @@ -54,10 +49,12 @@ bool AddressV2::isValid(const std::string& string) { Data root; Data attrs; byte type = 0; - if (!parseAndCheck(string, root, attrs, type)) { return false; } + if (!parseAndCheck(string, root, attrs, type)) { + return false; + } // valid return true; - } catch (exception& ex) { + } catch (std::exception& ex) { return false; } } @@ -90,8 +87,8 @@ Data AddressV2::getCborData() const { Cbor::Encode::uint(type), }); auto payloadData = cbor1.encoded(); - - // crc checksum + + // crc checksum auto crc = TW::Crc::crc32(payloadData); // second pack: tag, base, crc auto cbor2 = Cbor::Encode::array({ @@ -101,25 +98,29 @@ Data AddressV2::getCborData() const { return cbor2.encoded(); } -string AddressV2::string() const { +std::string AddressV2::string() const { // Base58 encode the CBOR data return Base58::bitcoin.encode(getCborData()); } Data AddressV2::keyHash(const TW::Data& xpub) { - if (xpub.size() != 64) { throw invalid_argument("invalid xbub length"); } + if (xpub.size() != 64) { + throw std::invalid_argument("invalid xbub length"); + } // hash of follwoing Cbor-array: [0, [0, xbub], {} ] // 3rd entry map is empty map for V2, contains derivation path for V1 + // clang-format off Data cborData = Cbor::Encode::array({ Cbor::Encode::uint(0), - Cbor::Encode::array({ - Cbor::Encode::uint(0), - Cbor::Encode::bytes(xpub) - }), + Cbor::Encode::array({Cbor::Encode::uint(0), + Cbor::Encode::bytes(xpub)}), Cbor::Encode::map({}), }).encoded(); + // clang-format on // SHA3 hash, then blake Data firstHash = Hash::sha3_256(cborData); Data blake = Hash::blake2b(firstHash, 28); return blake; } + +} // namespace TW::Cardano \ No newline at end of file diff --git a/src/Cardano/AddressV3.cpp b/src/Cardano/AddressV3.cpp index 81726329e23..2a0b67ec25a 100644 --- a/src/Cardano/AddressV3.cpp +++ b/src/Cardano/AddressV3.cpp @@ -7,22 +7,16 @@ #include "AddressV3.h" #include "AddressV2.h" #include -#include "../Data.h" #include "../Bech32.h" #include "../Base32.h" -#include "../Crc.h" #include "../HexCoding.h" -#include "../Hash.h" #include -using namespace TW; -using namespace TW::Cardano; -using namespace std; +namespace TW::Cardano { bool AddressV3::checkLength(Kind kind, size_t length) noexcept { - switch (kind) - { + switch (kind) { case Kind_Base: return (length == EncodedSize2); @@ -37,7 +31,7 @@ bool AddressV3::checkLength(Kind kind, size_t length) noexcept { } bool AddressV3::parseAndCheckV3(const Data& raw, NetworkId& networkId, Kind& kind, Data& bytes) noexcept { - if (raw.size() < 1ul) { + if (raw.empty()) { // too short, cannot extract kind and networkId return false; } @@ -56,7 +50,7 @@ bool AddressV3::parseAndCheckV3(const Data& raw, NetworkId& networkId, Kind& kin bool AddressV3::parseAndCheckV3(const std::string& addr, NetworkId& networkId, Kind& kind, Data& bytes) noexcept { try { auto bech = Bech32::decode(addr); - if (std::get<1>(bech).size() == 0) { + if (std::get<1>(bech).empty()) { // empty Bech data return false; } @@ -170,8 +164,7 @@ AddressV3::Kind AddressV3::kindFromFirstByte(uint8_t first) { return (Kind)((first & 0xF0) >> 4); } -void AddressV3::operator=(const AddressV3& other) -{ +void AddressV3::operator=(const AddressV3& other) { networkId = other.networkId; kind = other.kind; bytes = other.bytes; @@ -189,12 +182,12 @@ std::string AddressV3::getHrp(Kind kind) noexcept { } } -string AddressV3::string() const { +std::string AddressV3::string() const { const auto hrp = getHrp(kind); return string(hrp); } -string AddressV3::string(const std::string& hrp) const { +std::string AddressV3::string(const std::string& hrp) const { if (legacyAddressV2.has_value()) { return legacyAddressV2->string(); } @@ -219,3 +212,5 @@ Data AddressV3::data() const { TW::append(raw, bytes); return raw; } + +} // namespace TW::Cardano diff --git a/src/Cardano/Entry.cpp b/src/Cardano/Entry.cpp index e76beaf769d..154b44ac407 100644 --- a/src/Cardano/Entry.cpp +++ b/src/Cardano/Entry.cpp @@ -8,21 +8,16 @@ #include "AddressV3.h" #include "Signer.h" -#include "../proto/Cardano.pb.h" -#include - -using namespace TW::Cardano; -using namespace TW; -using namespace std; +namespace TW::Cardano { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return AddressV3::isValidLegacy(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return AddressV3(publicKey).string(); } @@ -37,3 +32,5 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D void Entry::plan([[maybe_unused]] TWCoinType coin, const Data& dataIn, Data& dataOut) const { planTemplate(dataIn, dataOut); } + +} // namespace TW::Cardano diff --git a/src/Cardano/Signer.cpp b/src/Cardano/Signer.cpp index fab8c008eb3..ca1c14c3fd6 100644 --- a/src/Cardano/Signer.cpp +++ b/src/Cardano/Signer.cpp @@ -7,20 +7,17 @@ #include "Signer.h" #include "AddressV3.h" -#include "PrivateKey.h" #include "Cbor.h" #include "HexCoding.h" +#include "PrivateKey.h" -#include +#include #include #include -#include #include +#include -using namespace TW::Cardano; -using namespace TW; -using namespace std; - +namespace TW::Cardano { static const Data placeholderPrivateKey = parse_hex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); static const auto PlaceholderFee = 170000; @@ -40,7 +37,7 @@ Proto::SigningOutput Signer::sign() { Common::Proto::SigningError Signer::buildTransactionAux(Transaction& tx, const Proto::SigningInput& input, const TransactionPlan& plan) { tx = Transaction(); - for (const auto& i: plan.utxos) { + for (const auto& i : plan.utxos) { tx.inputs.emplace_back(i.txHash, i.outputIndex); } @@ -65,10 +62,10 @@ Common::Proto::SigningError Signer::buildTransactionAux(Transaction& tx, const P return Common::Proto::OK; } -Common::Proto::SigningError Signer::assembleSignatures(vector>& signatures, const Proto::SigningInput& input, const TransactionPlan& plan, const Data& txId, bool sizeEstimationOnly) { +Common::Proto::SigningError Signer::assembleSignatures(std::vector>& signatures, const Proto::SigningInput& input, const TransactionPlan& plan, const Data& txId, bool sizeEstimationOnly) { signatures.clear(); // Private keys and corresponding addresses - map privateKeys; + std::map privateKeys; for (auto i = 0; i < input.private_key_size(); ++i) { const auto privateKeyData = data(input.private_key(i)); if (!PrivateKey::isValid(privateKeyData)) { @@ -81,8 +78,8 @@ Common::Proto::SigningError Signer::assembleSignatures(vector>& } // collect every unique input UTXO address - vector addresses; - for (auto& u: plan.utxos) { + std::vector addresses; + for (auto& u : plan.utxos) { if (!AddressV3::isValid(u.address)) { return Common::Proto::Error_invalid_address; } @@ -92,7 +89,7 @@ Common::Proto::SigningError Signer::assembleSignatures(vector>& } // create signature for each address - for (auto& a: addresses) { + for (auto& a : addresses) { const auto privKeyFind = privateKeys.find(a); Data privateKeyData; if (privKeyFind != privateKeys.end()) { @@ -115,10 +112,11 @@ Common::Proto::SigningError Signer::assembleSignatures(vector>& return Common::Proto::OK; } -Cbor::Encode cborizeSignatures(const vector>& signatures) { +Cbor::Encode cborizeSignatures(const std::vector>& signatures) { // signatures as Cbor - vector sigsCbor; - for (auto& s: signatures) { + // clang-format off + std::vector sigsCbor; + for (auto& s : signatures) { sigsCbor.emplace_back(Cbor::Encode::array({ Cbor::Encode::bytes(s.first), Cbor::Encode::bytes(s.second) @@ -127,11 +125,12 @@ Cbor::Encode cborizeSignatures(const vector>& signatures) { // Cbor-encode txAux & signatures return Cbor::Encode::map({ - make_pair( + std::make_pair( Cbor::Encode::uint(0), Cbor::Encode::array(sigsCbor) ) }); + // clang-format on } Proto::SigningOutput Signer::signWithPlan() { @@ -150,8 +149,8 @@ Proto::SigningOutput Signer::signWithPlan() { return ret; } - ret.set_encoded(string(encoded.begin(), encoded.end())); - ret.set_tx_id(string(txId.begin(), txId.end())); + ret.set_encoded(std::string(encoded.begin(), encoded.end())); + ret.set_tx_id(std::string(txId.begin(), txId.end())); ret.set_error(Common::Proto::OK); return ret; @@ -169,7 +168,7 @@ Common::Proto::SigningError Signer::encodeTransaction(Data& encoded, Data& txId, } txId = txAux.getId(); - vector> signatures; + std::vector> signatures; const auto sigError = assembleSignatures(signatures, input, plan, txId, sizeEstimationOnly); if (sigError != Common::Proto::OK) { return sigError; @@ -190,15 +189,15 @@ Common::Proto::SigningError Signer::encodeTransaction(Data& encoded, Data& txId, } // Select a subset of inputs, to cover desired coin amount. Simple algorithm: pick largest ones. -vector selectInputsSimpleNative(const vector& inputs, Amount amount) { - auto ii = vector(inputs); +std::vector selectInputsSimpleNative(const std::vector& inputs, Amount amount) { + auto ii = std::vector(inputs); sort(ii.begin(), ii.end(), [](TxInput t1, TxInput t2) { return t1.amount > t2.amount; }); - auto selected = vector(); + auto selected = std::vector(); Amount selectedAmount = 0; - for (const auto& i: ii) { + for (const auto& i : ii) { selected.push_back(i); selectedAmount += i.amount; if (selectedAmount >= amount) { @@ -209,15 +208,15 @@ vector selectInputsSimpleNative(const vector& inputs, Amount a } // Select a subset of inputs, to cover desired token amount. Simple algorithm: pick largest ones. -void selectInputsSimpleToken(const vector& inputs, string key, uint256_t amount, vector& selectedInputs) { - uint256_t selectedAmount = std::accumulate(selectedInputs.begin(), selectedInputs.end(), uint256_t(0), [key]([[maybe_unused]] uint256_t sum, const TxInput& si){ return si.tokenBundle.getAmount(key); }); +void selectInputsSimpleToken(const std::vector& inputs, std::string key, uint256_t amount, std::vector& selectedInputs) { + uint256_t selectedAmount = std::accumulate(selectedInputs.begin(), selectedInputs.end(), uint256_t(0), [key]([[maybe_unused]] uint256_t sum, const TxInput& si) { return si.tokenBundle.getAmount(key); }); if (selectedAmount >= amount) { return; // already covered } // sort inputs descending - auto ii = vector(inputs); + auto ii = std::vector(inputs); std::sort(ii.begin(), ii.end(), [key](TxInput t1, TxInput t2) { return t1.tokenBundle.getAmount(key) > t2.tokenBundle.getAmount(key); }); - for (const auto& i: ii) { + for (const auto& i : ii) { if (static_cast(distance(selectedInputs.begin(), find(selectedInputs.begin(), selectedInputs.end(), i))) < selectedInputs.size()) { // already selected continue; @@ -232,7 +231,7 @@ void selectInputsSimpleToken(const vector& inputs, string key, uint256_ } // Select a subset of inputs, to cover desired amount. Simple algorithm: pick largest ones -vector Signer::selectInputsWithTokens(const vector& inputs, Amount amount, const TokenBundle& requestedTokens) { +std::vector Signer::selectInputsWithTokens(const std::vector& inputs, Amount amount, const TokenBundle& requestedTokens) { auto selected = selectInputsSimpleNative(inputs, amount); for (auto iter = requestedTokens.bundle.begin(); iter != requestedTokens.bundle.end(); ++iter) { const auto& ta = iter->second; @@ -242,13 +241,13 @@ vector Signer::selectInputsWithTokens(const vector& inputs, Am } // Create a simple plan, used for estimation -TransactionPlan simplePlan(Amount amount, const TokenBundle& requestedTokens, const vector& selectedInputs, bool maxAmount) { +TransactionPlan simplePlan(Amount amount, const TokenBundle& requestedTokens, const std::vector& selectedInputs, bool maxAmount) { TransactionPlan plan; plan.amount = amount; plan.utxos = selectedInputs; // Sum availableAmount plan.availableAmount = 0; - for (auto& u: plan.utxos) { + for (auto& u : plan.utxos) { plan.availableAmount += u.amount; for (auto iter = u.tokenBundle.bundle.begin(); iter != u.tokenBundle.bundle.end(); ++iter) { plan.availableTokens.add(iter->second); @@ -258,11 +257,11 @@ TransactionPlan simplePlan(Amount amount, const TokenBundle& requestedTokens, co // adjust/compute output amount and output tokens if (!maxAmount) { // reduce amount if needed - plan.amount = max(Amount(0), min(plan.amount, plan.availableAmount - plan.fee)); + plan.amount = std::max(Amount(0), std::min(plan.amount, plan.availableAmount - plan.fee)); plan.outputTokens = requestedTokens; } else { // max available amount - plan.amount = max(Amount(0), plan.availableAmount - plan.fee); + plan.amount = std::max(Amount(0), plan.availableAmount - plan.fee); plan.outputTokens = plan.availableTokens; // use all } @@ -279,8 +278,8 @@ TransactionPlan simplePlan(Amount amount, const TokenBundle& requestedTokens, co } // Estimates size of transaction in bytes. -uint64_t estimateTxSize(const Proto::SigningInput& input, Amount amount, const TokenBundle& requestedTokens, const vector& selectedInputs) { - auto inputs = vector(); +uint64_t estimateTxSize(const Proto::SigningInput& input, Amount amount, const TokenBundle& requestedTokens, const std::vector& selectedInputs) { + auto inputs = std::vector(); for (auto i = 0; i < input.utxos_size(); ++i) { inputs.emplace_back(TxInput::fromProto(input.utxos(i))); } @@ -305,7 +304,7 @@ Amount txFeeFunction(uint64_t txSizeInBytes) { return fee; } -Amount Signer::estimateFee(const Proto::SigningInput& input, Amount amount, const TokenBundle& requestedTokens, const vector selectedInputs) { +Amount Signer::estimateFee(const Proto::SigningInput& input, Amount amount, const TokenBundle& requestedTokens, const std::vector selectedInputs) { return txFeeFunction(estimateTxSize(input, amount, requestedTokens, selectedInputs)); } @@ -318,7 +317,7 @@ TransactionPlan Signer::doPlan() const { return plan; } // Check input UTXOs, process, sum ADA and token amounts - auto utxos = vector(); + auto utxos = std::vector(); uint64_t inputSum = 0; for (auto i = 0; i < input.utxos_size(); ++i) { const auto& utxo = input.utxos(i); @@ -364,7 +363,7 @@ TransactionPlan Signer::doPlan() const { // Sum availableAmount plan.availableAmount = 0; - for (auto& u: plan.utxos) { + for (auto& u : plan.utxos) { plan.availableAmount += u.amount; for (auto iter = u.tokenBundle.bundle.begin(); iter != u.tokenBundle.bundle.end(); ++iter) { plan.availableTokens.add(iter->second); @@ -395,17 +394,17 @@ TransactionPlan Signer::doPlan() const { plan.fee = estimateFee(input, plan.amount, requestedTokens, plan.utxos); } else { // fee provided, use it (capped) - plan.fee = max(Amount(0), min(plan.availableAmount - plan.amount, input.transfer_message().force_fee())); + plan.fee = std::max(Amount(0), std::min(plan.availableAmount - plan.amount, input.transfer_message().force_fee())); } assert(plan.fee >= 0 && plan.fee < plan.availableAmount); // adjust/compute output amount if (!maxAmount) { // reduce amount if needed - plan.amount = max(Amount(0), min(plan.amount, plan.availableAmount - plan.fee)); + plan.amount = std::max(Amount(0), std::min(plan.amount, plan.availableAmount - plan.fee)); } else { // max available amount - plan.amount = max(Amount(0), plan.availableAmount - plan.fee); + plan.amount = std::max(Amount(0), plan.availableAmount - plan.fee); } assert(plan.amount >= 0 && plan.amount <= plan.availableAmount); @@ -439,3 +438,5 @@ TransactionPlan Signer::doPlan() const { return plan; } + +} // namespace TW::Cardano diff --git a/src/Cardano/Transaction.cpp b/src/Cardano/Transaction.cpp index 905c4980c25..8abd2f89799 100644 --- a/src/Cardano/Transaction.cpp +++ b/src/Cardano/Transaction.cpp @@ -10,10 +10,7 @@ #include "Hash.h" #include "HexCoding.h" -using namespace TW::Cardano; -using namespace TW; -using namespace std; - +namespace TW::Cardano { TokenAmount TokenAmount::fromProto(const Proto::TokenAmount& proto) { auto ret = TokenAmount(); @@ -42,7 +39,7 @@ TokenBundle TokenBundle::fromProto(const Proto::TokenBundle& proto) { Proto::TokenBundle TokenBundle::toProto() const { Proto::TokenBundle proto; - for (const auto& t: bundle) { + for (const auto& t : bundle) { *(proto.add_token()) = t.second.toProto(); } return proto; @@ -67,17 +64,17 @@ uint256_t TokenBundle::getAmount(const std::string& key) const { return findkey->second.amount; } -unordered_set TokenBundle::getPolicyIds() const { - unordered_set policyIds; +std::unordered_set TokenBundle::getPolicyIds() const { + std::unordered_set policyIds; std::transform(bundle.cbegin(), bundle.cend(), std::inserter(policyIds, policyIds.begin()), - [](auto&& cur){ return cur.second.policyId; }); + [](auto&& cur) { return cur.second.policyId; }); return policyIds; } -vector TokenBundle::getByPolicyId(const string& policyId) const { - vector filtered; - for (const auto& t: bundle) { +std::vector TokenBundle::getByPolicyId(const std::string& policyId) const { + std::vector filtered; + for (const auto& t : bundle) { if (t.second.policyId == policyId) { filtered.push_back(t.second); } @@ -85,7 +82,9 @@ vector TokenBundle::getByPolicyId(const string& policyId) const { return filtered; } -uint64_t roundupBytesToWords(uint64_t b) { return ((b + 7) / 8); } +uint64_t roundupBytesToWords(uint64_t b) { + return ((b + 7) / 8); +} const uint64_t TokenBundle::MinUtxoValue = 1000000; @@ -100,7 +99,7 @@ uint64_t TokenBundle::minAdaAmountHelper(uint64_t numPids, uint64_t numAssets, u static const uint64_t pidSize = 28; uint64_t sizeB = 6 + roundupBytesToWords((numAssets * 12) + sumAssetNameLengths + (numPids * pidSize)); - return max(MinUtxoValue, (MinUtxoValue / adaOnlyUTxOSize) * (utxoEntrySizeWithoutVal + sizeB)); + return std::max(MinUtxoValue, (MinUtxoValue / adaOnlyUTxOSize) * (utxoEntrySizeWithoutVal + sizeB)); } uint64_t TokenBundle::minAdaAmount() const { @@ -109,12 +108,12 @@ uint64_t TokenBundle::minAdaAmount() const { return MinUtxoValue; } - unordered_set policyIdRegistry; - unordered_set assetNameRegistry; + std::unordered_set policyIdRegistry; + std::unordered_set assetNameRegistry; uint64_t numPids = 0; uint64_t numAssets = 0; uint64_t sumAssetNameLengths = 0; - for (const auto& t: bundle) { + for (const auto& t : bundle) { policyIdRegistry.emplace(t.second.policyId); if (t.second.assetName.length() > 0) { assetNameRegistry.emplace(t.second.assetName); @@ -122,7 +121,7 @@ uint64_t TokenBundle::minAdaAmount() const { } numPids = uint64_t(policyIdRegistry.size()); numAssets = uint64_t(assetNameRegistry.size()); - for_each(assetNameRegistry.begin(), assetNameRegistry.end(), [&sumAssetNameLengths](string a){ sumAssetNameLengths += a.length(); }); + for_each(assetNameRegistry.begin(), assetNameRegistry.end(), [&sumAssetNameLengths](std::string a) { sumAssetNameLengths += a.length(); }); return minAdaAmountHelper(numPids, numAssets, sumAssetNameLengths); } @@ -145,13 +144,15 @@ Proto::TxInput TxInput::toProto() const { txInput.mutable_out_point()->set_output_index(outputIndex); txInput.set_address(address.data(), address.size()); txInput.set_amount(amount); - for (const auto& token: tokenBundle.bundle) { + for (const auto& token : tokenBundle.bundle) { *txInput.add_token_amount() = token.second.toProto(); } return txInput; } -bool TW::Cardano::operator==(const TxInput& i1, const TxInput& i2) { return i1.outputIndex == i2.outputIndex && i1.txHash == i2.txHash; } +bool operator==(const TxInput& i1, const TxInput& i2) { + return i1.outputIndex == i2.outputIndex && i1.txHash == i2.txHash; +} TransactionPlan TransactionPlan::fromProto(const Proto::TransactionPlan& proto) { auto ret = TransactionPlan(); @@ -181,16 +182,16 @@ Proto::TransactionPlan TransactionPlan::toProto() const { plan.set_amount(amount); plan.set_fee(fee); plan.set_change(change); - for (const auto& token: availableTokens.bundle) { + for (const auto& token : availableTokens.bundle) { *plan.add_available_tokens() = token.second.toProto(); } - for (const auto& token: outputTokens.bundle) { + for (const auto& token : outputTokens.bundle) { *plan.add_output_tokens() = token.second.toProto(); } - for (const auto& token: changeTokens.bundle) { + for (const auto& token : changeTokens.bundle) { *plan.add_change_tokens() = token.second.toProto(); } - for (const auto& u: utxos) { + for (const auto& u : utxos) { *plan.add_utxos() = u.toProto(); } plan.set_error(error); @@ -198,13 +199,15 @@ Proto::TransactionPlan TransactionPlan::toProto() const { } Cbor::Encode cborizeInputs(const std::vector& inputs) { + // clang-format off std::vector ii; - for (const auto& i: inputs) { + for (const auto& i : inputs) { ii.push_back(Cbor::Encode::array({ Cbor::Encode::bytes(i.txHash), Cbor::Encode::uint(i.outputIndex) })); } + // clang-format on return Cbor::Encode::array(ii); } @@ -216,11 +219,11 @@ Cbor::Encode cborizeOutputAmounts(const Amount& amount, const TokenBundle& token // native and token amounts // tokens: organized in two levels: by policyId and by assetName const auto policyIds = tokenBundle.getPolicyIds(); - map tokensMap; - for (const auto& policy: policyIds) { + std::map tokensMap; + for (const auto& policy : policyIds) { const auto& subTokens = tokenBundle.getByPolicyId(policy); - map subTokensMap; - for (const auto& token: subTokens) { + std::map subTokensMap; + for (const auto& token : subTokens) { subTokensMap.emplace( Cbor::Encode::bytes(data(token.assetName)), Cbor::Encode::uint(uint64_t(token.amount)) // 64 bits @@ -228,25 +231,28 @@ Cbor::Encode cborizeOutputAmounts(const Amount& amount, const TokenBundle& token } tokensMap.emplace( Cbor::Encode::bytes(parse_hex(policy)), - Cbor::Encode::map(subTokensMap) - ); + Cbor::Encode::map(subTokensMap)); } + // clang-format off return Cbor::Encode::array({ Cbor::Encode::uint(amount), Cbor::Encode::map(tokensMap) }); + // clang-format on } Cbor::Encode cborizeOutput(const TxOutput& output) { + // clang-format off return Cbor::Encode::array({ Cbor::Encode::bytes(output.address), cborizeOutputAmounts(output.amount, output.tokenBundle) }); + // clang-format on } Cbor::Encode cborizeOutputs(const std::vector& outputs) { std::vector oo; - for (const auto& o: outputs) { + for (const auto& o : outputs) { oo.push_back(cborizeOutput(o)); } return Cbor::Encode::array(oo); @@ -258,10 +264,10 @@ Data Transaction::encode() const { // Encode elements in a map, with fixed numbers as keys Cbor::Encode encode = Cbor::Encode::map({ - make_pair(Cbor::Encode::uint(0), ii), - make_pair(Cbor::Encode::uint(1), oo), - make_pair(Cbor::Encode::uint(2), Cbor::Encode::uint(fee)), - make_pair(Cbor::Encode::uint(3), Cbor::Encode::uint(ttl)), + std::make_pair(Cbor::Encode::uint(0), ii), + std::make_pair(Cbor::Encode::uint(1), oo), + std::make_pair(Cbor::Encode::uint(2), Cbor::Encode::uint(fee)), + std::make_pair(Cbor::Encode::uint(3), Cbor::Encode::uint(ttl)), }); // Note: following fields are not included: // 4 certificates, 5 withdrawals, 7 AUXILIARY_DATA_HASH, 8 VALIDITY_INTERVAL_START @@ -274,3 +280,5 @@ Data Transaction::getId() const { const auto hash = Hash::blake2b(encoded, 32); return hash; } + +} // namespace TW::Cardano diff --git a/src/Cosmos/Signer.cpp b/src/Cosmos/Signer.cpp index 7da012e0e3e..6ef51e88af2 100644 --- a/src/Cosmos/Signer.cpp +++ b/src/Cosmos/Signer.cpp @@ -1,11 +1,10 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. #include "Signer.h" -#include "../proto/Cosmos.pb.h" #include "JsonSerialization.h" #include "ProtobufSerialization.h" @@ -13,17 +12,16 @@ #include "Data.h" #include -using namespace TW; -using namespace TW::Cosmos; +namespace TW::Cosmos { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input, TWCoinType coin) noexcept { switch (input.signing_mode()) { - case Proto::JSON: - return signJsonSerialized(input); - - case Proto::Protobuf: - default: - return signProtobuf(input, coin); + case Proto::JSON: + return signJsonSerialized(input); + + case Proto::Protobuf: + default: + return signProtobuf(input, coin); } } @@ -72,3 +70,5 @@ std::string Signer::signJSON(const std::string& json, const Data& key, TWCoinTyp auto output = Signer::sign(input, coin); return output.json(); } + +} // namespace TW::Cosmos diff --git a/src/Decred/Address.cpp b/src/Decred/Address.cpp index dd5bf2fd667..cd3685f9463 100644 --- a/src/Decred/Address.cpp +++ b/src/Decred/Address.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,13 +8,9 @@ #include "../Base58.h" #include "../Coin.h" -#include "../Hash.h" #include -using namespace TW; -using namespace TW::Decred; - namespace TW::Decred { static const auto keyhashSize = Hash::ripemdSize; diff --git a/src/Decred/Entry.cpp b/src/Decred/Entry.cpp index 9704a99c842..2bfc7149e39 100644 --- a/src/Decred/Entry.cpp +++ b/src/Decred/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,15 +9,13 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Decred; -using namespace TW; -using namespace std; +namespace TW::Decred { -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] TW::byte p2sh, [[maybe_unused]] const char* hrp) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] TW::byte p2sh, [[maybe_unused]] const char* hrp) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] const char* hrp) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] const char* hrp) const { return Address(publicKey).string(); } @@ -33,3 +31,5 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D void Entry::plan([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { planTemplate(dataIn, dataOut); } + +} // namespace TW::Decred diff --git a/src/Decred/OutPoint.cpp b/src/Decred/OutPoint.cpp index 27cb836c50a..e33f39badd4 100644 --- a/src/Decred/OutPoint.cpp +++ b/src/Decred/OutPoint.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,10 +8,12 @@ #include "../BinaryCoding.h" -using namespace TW::Decred; +namespace TW::Decred { void OutPoint::encode(Data& data) const { std::copy(std::begin(hash), std::end(hash), std::back_inserter(data)); encode32LE(index, data); data.push_back(static_cast(tree)); } + +} // namespace TW::Decred diff --git a/src/Decred/Signer.cpp b/src/Decred/Signer.cpp index 413203c48eb..5cb610c137e 100644 --- a/src/Decred/Signer.cpp +++ b/src/Decred/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,23 +10,18 @@ #include "TransactionOutput.h" #include "../Bitcoin/SigHashType.h" #include "../Bitcoin/SignatureBuilder.h" - #include "../BinaryCoding.h" -#include "../Hash.h" #include "../HexCoding.h" -#include "Bitcoin/OpCodes.h" - -using namespace TW; -using namespace TW::Decred; +namespace TW::Decred { Bitcoin::Proto::TransactionPlan Signer::plan(const Bitcoin::Proto::SigningInput& input) noexcept { - auto signer = Signer(std::move(input)); + auto signer = Signer(input); return signer.txPlan.proto(); } Proto::SigningOutput Signer::sign(const Bitcoin::Proto::SigningInput& input) noexcept { - auto signer = Signer(std::move(input)); + auto signer = Signer(input); auto result = signer.sign(); auto output = Proto::SigningOutput(); if (!result) { @@ -47,7 +42,7 @@ Proto::SigningOutput Signer::sign(const Bitcoin::Proto::SigningInput& input) noe } Result Signer::sign() { - if (txPlan.utxos.size() == 0 || _transaction.inputs.size() == 0) { + if (txPlan.utxos.empty() || _transaction.inputs.empty()) { return Result::failure(Common::Proto::Error_missing_input_utxos); } @@ -206,3 +201,5 @@ Data Signer::scriptForScriptHash(const Data& hash) const { } return Data(it->second.begin(), it->second.end()); } + +} // namespace TW::Decred diff --git a/src/Decred/Transaction.cpp b/src/Decred/Transaction.cpp index 763731527e7..958a843cd49 100644 --- a/src/Decred/Transaction.cpp +++ b/src/Decred/Transaction.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,14 +8,10 @@ #include "../Bitcoin/SigHashType.h" #include "../BinaryCoding.h" -#include "../Hash.h" - -#include "Bitcoin/SignatureVersion.h" #include -using namespace TW; -using namespace TW::Decred; +namespace TW::Decred { namespace { // Indicates the serialization does not include any witness data. @@ -239,3 +235,5 @@ std::size_t sigHashWitnessSize(const std::vector& inputs, signScript.bytes.size(); } } // namespace + +} // namespace TW::Decred diff --git a/src/Decred/TransactionInput.cpp b/src/Decred/TransactionInput.cpp index 0cf57aba6d8..47308501e2e 100644 --- a/src/Decred/TransactionInput.cpp +++ b/src/Decred/TransactionInput.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,7 +8,7 @@ #include "../BinaryCoding.h" -using namespace TW::Decred; +namespace TW::Decred { void TransactionInput::encode(Data& data) const { previousOutput.encode(data); @@ -21,3 +21,5 @@ void TransactionInput::encodeWitness(Data& data) const { encode32LE(blockIndex, data); script.encode(data); } + +} // namespace TW::Decred diff --git a/src/Decred/TransactionOutput.cpp b/src/Decred/TransactionOutput.cpp index 9bc46efde7d..1aadfd41d37 100644 --- a/src/Decred/TransactionOutput.cpp +++ b/src/Decred/TransactionOutput.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,10 +8,12 @@ #include "../BinaryCoding.h" -using namespace TW::Decred; +namespace TW::Decred { void TransactionOutput::encode(Data& data) const { encode64LE(value, data); encode16LE(version, data); script.encode(data); } + +} // namespace TW::Decred \ No newline at end of file diff --git a/src/EOS/Action.cpp b/src/EOS/Action.cpp index 37bb5dea766..e47c40f2fa2 100644 --- a/src/EOS/Action.cpp +++ b/src/EOS/Action.cpp @@ -6,10 +6,8 @@ #include "Action.h" #include "../HexCoding.h" -#include "../EOS/Serialization.h" -using namespace TW; -using namespace TW::EOS; +namespace TW::EOS { void PermissionLevel::serialize(Data& o) const { actor.serialize(o); @@ -40,11 +38,11 @@ json Action::serialize() const noexcept { return obj; } -TransferAction::TransferAction( const std::string& currency, - const std::string& from, - const std::string& to, - const Asset& asset, - const std::string& memo) { +TransferAction::TransferAction(const std::string& currency, + const std::string& from, + const std::string& to, + const Asset& asset, + const std::string& memo) { account = Name(currency); name = Name("transfer"); authorization.emplace_back(PermissionLevel(Name(from), Name("active"))); @@ -62,3 +60,5 @@ void TransferAction::setData(const std::string& from, const std::string& to, con asset.serialize(data); encodeString(memo, data); } + +} // namespace TW::EOS diff --git a/src/EOS/Address.cpp b/src/EOS/Address.cpp index 7d8d1a6d8fa..db97a6d7853 100644 --- a/src/EOS/Address.cpp +++ b/src/EOS/Address.cpp @@ -4,16 +4,15 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include "Address.h" #include "../Base58.h" #include "../BinaryCoding.h" -#include "Address.h" #include #include -using namespace TW; -using namespace TW::EOS; +namespace TW::EOS { bool Address::isValid(const std::string& string) { return extractKeyData(string); @@ -22,11 +21,15 @@ bool Address::isValid(const std::string& string) { /// Determines whether the given byte vector is a valid keyBuffer /// Verifies the buffer's size and it's checksum bytes bool Address::isValid(const Data& bytes, EOS::Type type) { - if (bytes.size() != KeyDataSize) return false; + if (bytes.size() != KeyDataSize) { + return false; + } // last Address::ChecksumSize bytes are a checksum uint32_t checksum = decode32LE(bytes.data() + PublicKeyDataSize); - if (createChecksum(bytes, type) != checksum) return false; + if (createChecksum(bytes, type) != checksum) { + return false; + } return true; } @@ -48,15 +51,15 @@ uint32_t Address::createChecksum(const Data& bytes, Type type) { break; case Type::ModernK1: - ripemd160_Update(&ctx, - (const uint8_t *) Modern::K1::prefix.c_str(), - static_cast(Modern::K1::prefix.size())); + ripemd160_Update(&ctx, + (const uint8_t*)Modern::K1::prefix.c_str(), + static_cast(Modern::K1::prefix.size())); break; case Type::ModernR1: - ripemd160_Update(&ctx, - (const uint8_t *) Modern::R1::prefix.c_str(), - static_cast(Modern::R1::prefix.size())); + ripemd160_Update(&ctx, + (const uint8_t*)Modern::R1::prefix.c_str(), + static_cast(Modern::R1::prefix.size())); break; } @@ -67,9 +70,9 @@ uint32_t Address::createChecksum(const Data& bytes, Type type) { } /// Extracts and verifies the key data from a base58 string. -/// If the second arg is provided, the keyData and isTestNet +/// If the second arg is provided, the keyData and isTestNet /// properties of that object are set from the extracted data. -bool Address::extractKeyData(const std::string& string, Address *address) { +bool Address::extractKeyData(const std::string& string, Address* address) { // verify if the string has one of the valid prefixes Type type; size_t prefixSize; @@ -111,14 +114,16 @@ Address::Address(const std::string& string) { } /// Initializes a EOS address from raw bytes -Address::Address(const Data& data, Type type) : keyData(data), type(type) { +Address::Address(const Data& data, Type type) + : keyData(data), type(type) { if (!isValid(data, type)) { throw std::invalid_argument("Invalid byte size!"); } } /// Initializes a EOS address from a public key. -Address::Address(const PublicKey& publicKey, Type type) : type(type) { +Address::Address(const PublicKey& publicKey, Type type) + : type(type) { assert(PublicKeyDataSize == TW::PublicKey::secp256k1Size); // copy the raw, compressed key data @@ -136,3 +141,5 @@ Address::Address(const PublicKey& publicKey, Type type) : type(type) { std::string Address::string() const { return prefix() + Base58::bitcoin.encode(keyData); } + +} // namespace TW::EOS diff --git a/src/EOS/Asset.cpp b/src/EOS/Asset.cpp index 80638ceae43..e2f246315e1 100644 --- a/src/EOS/Asset.cpp +++ b/src/EOS/Asset.cpp @@ -10,7 +10,7 @@ #include #include -using namespace TW::EOS; +namespace TW::EOS { static const int64_t Precision = 1000; static const uint8_t MaxDecimals = 18; @@ -21,12 +21,12 @@ Asset::Asset(int64_t amount, uint8_t decimals, const std::string& symbol) { } this->symbol |= decimals; - if (symbol.size() < 1 || symbol.size() > 7) { + if (symbol.empty() || symbol.size() > 7) { throw std::invalid_argument("Symbol size invalid!"); } for (std::size_t i = 0; i < symbol.size(); i++) { - uint64_t c = symbol[i]; + uint64_t c = (unsigned char) symbol[i]; if (c < 'A' || c > 'Z') { throw std::invalid_argument("Invalid symbol " + symbol + ".\n Symbol can only have upper case alphabets!"); } @@ -61,8 +61,8 @@ Asset Asset::fromString(std::string assetString) { if (dotPosition != string::npos) { decimals = static_cast(amountString.size() - dotPosition - 1); } - - int64_t precision = static_cast(pow(10, static_cast(decimals))); + + auto precision = static_cast(pow(10, static_cast(decimals))); // Parse amount int64_t intPart, fractPart = 0; @@ -110,10 +110,10 @@ std::string Asset::string() const { auto decimals = getDecimals(); - int charsWritten = snprintf(buffer, maxBufferSize, "%.*f %s", - decimals, - static_cast(amount) / Precision, - getSymbol().c_str()); + int charsWritten = snprintf(buffer, maxBufferSize, "%.*f %s", + decimals, + static_cast(amount) / Precision, + getSymbol().c_str()); if (charsWritten < 0 || charsWritten > maxBufferSize) { throw std::runtime_error("Failed to create string representation of asset!"); @@ -133,3 +133,5 @@ std::string Asset::getSymbol() const noexcept { return str; } + +} // namespace TW::EOS diff --git a/src/EOS/Entry.cpp b/src/EOS/Entry.cpp index 36dc5df0da7..fa3af508bb4 100644 --- a/src/EOS/Entry.cpp +++ b/src/EOS/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,19 +9,20 @@ #include "Address.h" #include "Signer.h" -using namespace TW::EOS; -using namespace std; +namespace TW::EOS { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} diff --git a/src/EOS/Name.cpp b/src/EOS/Name.cpp index e42a5af8bf0..9cb6805bf87 100644 --- a/src/EOS/Name.cpp +++ b/src/EOS/Name.cpp @@ -10,8 +10,7 @@ #include #include -using namespace TW; -using namespace TW::EOS; +namespace TW::EOS { Name::Name(const std::string& str) { if (str.size() > 13) { @@ -28,7 +27,7 @@ Name::Name(const std::string& str) { value |= (toSymbol(str[i]) & 0x0f); } -uint64_t Name::toSymbol(char c) const noexcept { +uint64_t Name::toSymbol(char c) noexcept { if (c >= 'a' && c <= 'z') return c - 'a' + 6; @@ -41,22 +40,24 @@ uint64_t Name::toSymbol(char c) const noexcept { std::string Name::string() const noexcept { static const char* charMap = ".12345abcdefghijklmnopqrstuvwxyz"; - std::string str(13,'.'); + std::string str(13, '.'); uint64_t tmp = value; str[12] = charMap[tmp & 0x0f]; tmp >>= 4; - for( uint32_t i = 1; i <= 12; ++i ) { + for (uint32_t i = 1; i <= 12; ++i) { char c = charMap[tmp & 0x1f]; - str[12-i] = c; + str[12 - i] = c; tmp >>= 5; } - boost::algorithm::trim_right_if( str, []( char c ){ return c == '.'; } ); + boost::algorithm::trim_right_if(str, [](char c) { return c == '.'; }); return str; } -void Name::serialize(Data& o) const noexcept { +void Name::serialize(Data& o) const noexcept { encode64LE(value, o); } + +} // namespace TW::EOS diff --git a/src/EOS/Name.h b/src/EOS/Name.h index 1bef7d31b7e..a3fca26df6f 100644 --- a/src/EOS/Name.h +++ b/src/EOS/Name.h @@ -16,7 +16,7 @@ class Name { Name() = default; Name(const std::string& str); - uint64_t toSymbol(char c) const noexcept; + static uint64_t toSymbol(char c) noexcept; std::string string() const noexcept; void serialize(TW::Data& o) const noexcept; diff --git a/src/EOS/PackedTransaction.cpp b/src/EOS/PackedTransaction.cpp index c0f0955b996..a1d3e74ea3d 100644 --- a/src/EOS/PackedTransaction.cpp +++ b/src/EOS/PackedTransaction.cpp @@ -8,14 +8,14 @@ #include "../HexCoding.h" -using namespace TW; -using namespace TW::EOS; +namespace TW::EOS { -PackedTransaction::PackedTransaction(const Transaction& transaction, CompressionType type) noexcept : compression(type) { +PackedTransaction::PackedTransaction(const Transaction& transaction, CompressionType type) noexcept + : compression(type) { transaction.serialize(packedTrx); const Data& cfd = transaction.contextFreeData; - if (cfd.size()) { + if (!cfd.empty()) { packedCFD.push_back(1); encodeVarInt64(cfd.size(), packedCFD); append(packedCFD, cfd); @@ -49,3 +49,5 @@ json PackedTransaction::serialize() const noexcept { return obj; } + +} // namespace TW::EOS diff --git a/src/EOS/Signer.cpp b/src/EOS/Signer.cpp index 12a0c2833b6..b01ba0051e9 100644 --- a/src/EOS/Signer.cpp +++ b/src/EOS/Signer.cpp @@ -7,21 +7,16 @@ #include "Signer.h" #include "Asset.h" #include "PackedTransaction.h" -#include "../proto/Common.pb.h" -#include "../HexCoding.h" #include -#include -#include -using namespace TW; -using namespace TW::EOS; +namespace TW::EOS { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { Proto::SigningOutput output; try { // create an asset object - auto assetData = input.asset(); + const auto& assetData = input.asset(); auto asset = Asset(assetData.amount(), static_cast(assetData.decimals()), assetData.symbol()); @@ -31,7 +26,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { // create a Transaction and add the transfer action auto tx = Transaction(Data(input.reference_block_id().begin(), input.reference_block_id().end()), - input.reference_block_time()); + input.reference_block_time()); tx.actions.push_back(action); // get key type @@ -93,7 +88,7 @@ TW::Data Signer::hash(const Transaction& transaction) const noexcept { transaction.serialize(hashInput); Data cfdHash(Hash::sha256Size); // default value for empty cfd - if (transaction.contextFreeData.size()) { + if (!transaction.contextFreeData.empty()) { cfdHash = Hash::sha256(transaction.contextFreeData); } @@ -103,8 +98,12 @@ TW::Data Signer::hash(const Transaction& transaction) const noexcept { // canonical check for EOS int Signer::isCanonical([[maybe_unused]] uint8_t by, uint8_t sig[64]) { + // clang-format off return !(sig[0] & 0x80) && !(sig[0] == 0 && !(sig[1] & 0x80)) && !(sig[32] & 0x80) && !(sig[32] == 0 && !(sig[33] & 0x80)); + // clang-format on } + +} // namespace TW::EOS diff --git a/src/EOS/Transaction.cpp b/src/EOS/Transaction.cpp index 8189f8ef042..72c2791b460 100644 --- a/src/EOS/Transaction.cpp +++ b/src/EOS/Transaction.cpp @@ -5,7 +5,6 @@ // file LICENSE at the root of the source code distribution tree. #include "../Base58.h" -#include "../Hash.h" #include "../HexCoding.h" #include "Transaction.h" @@ -15,10 +14,10 @@ #include #include -using namespace TW; -using namespace TW::EOS; +namespace TW::EOS { -Signature::Signature(const Data& sig, Type type) : data(sig), type(type) { +Signature::Signature(const Data& sig, Type type) + : data(sig), type(type) { if (sig.size() != DataSize) { throw std::invalid_argument("Invalid signature size!"); } @@ -54,7 +53,7 @@ std::string Signature::string() const noexcept { // drop the subPrefix and append the checksum to the bufer buffer.resize(DataSize); - for(size_t i = 0; i < ChecksumSize; i++) { + for (size_t i = 0; i < ChecksumSize; i++) { buffer.push_back(hash[i]); } @@ -85,7 +84,7 @@ void Transaction::setReferenceBlock(const Data& refBlockId) { refBlockPrefix = decode32LE(refBlockId.data() + 8); } -void Transaction::serialize(Data& os) const noexcept{ +void Transaction::serialize(Data& os) const noexcept { encode32LE(expiration, os); encode16LE(refBlockNumber, os); @@ -104,10 +103,10 @@ std::string Transaction::formatDate(int32_t date) { constexpr size_t DateSize = 19; constexpr size_t BufferSize = DateSize + 1; char formattedDate[BufferSize]; - time_t time = static_cast(date); + auto time = static_cast(date); const size_t len = strftime(formattedDate, BufferSize, "%FT%T", std::gmtime(&time)); assert(len == DateSize); - return std::string(formattedDate, len); + return {formattedDate, len}; } json Transaction::serialize() const { @@ -135,3 +134,5 @@ json Transaction::serialize() const { return obj; } + +} // namespace TW::EOS diff --git a/src/Elrond/Codec.cpp b/src/Elrond/Codec.cpp index ccf524c46a4..dbdf0859291 100644 --- a/src/Elrond/Codec.cpp +++ b/src/Elrond/Codec.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,8 +9,7 @@ #include "HexCoding.h" #include "uint256.h" -using namespace TW; -using namespace TW::Elrond; +namespace TW::Elrond { std::string Codec::encodeString(const std::string& value) { std::string encoded = hex(TW::data(value)); @@ -42,3 +41,5 @@ std::string Codec::encodeAddress(const Address& address) { std::string encoded = hex(address.getKeyHash()); return encoded; } + +} // namespace TW::Elrond diff --git a/src/Elrond/GasEstimator.cpp b/src/Elrond/GasEstimator.cpp index 2445b64dd45..6db7cbc9580 100644 --- a/src/Elrond/GasEstimator.cpp +++ b/src/Elrond/GasEstimator.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,15 +6,12 @@ #include "GasEstimator.h" -#include "../proto/Elrond.pb.h" - -using namespace TW; -using namespace TW::Elrond; +namespace TW::Elrond { // Additional gas to account for eventual increases in gas requirements (thus avoid breaking changes in clients of TW-core). const uint64_t ADDITIONAL_GAS_FOR_ESDT_TRANSFER = 100000; -// Additional gas to account for extra blockchain operations (e.g. data movement (between accounts) for NFTs), +// Additional gas to account for extra blockchain operations (e.g. data movement (between accounts) for NFTs), // and for eventual increases in gas requirements (thus avoid breaking changes in clients of TW-core). const uint64_t ADDITIONAL_GAS_FOR_ESDT_NFT_TRANSFER = 500000; @@ -23,17 +20,17 @@ GasEstimator::GasEstimator(const NetworkConfig& networkConfig) { } uint64_t GasEstimator::forEGLDTransfer(size_t dataLength) const { - uint64_t gasLimit = - this->networkConfig.getMinGasLimit() + + uint64_t gasLimit = + this->networkConfig.getMinGasLimit() + this->networkConfig.getGasPerDataByte() * dataLength; return gasLimit; } uint64_t GasEstimator::forESDTTransfer(size_t dataLength) const { - uint64_t gasLimit = - this->networkConfig.getMinGasLimit() + - this->networkConfig.getGasCostESDTTransfer() + + uint64_t gasLimit = + this->networkConfig.getMinGasLimit() + + this->networkConfig.getGasCostESDTTransfer() + this->networkConfig.getGasPerDataByte() * dataLength + ADDITIONAL_GAS_FOR_ESDT_TRANSFER; @@ -41,11 +38,13 @@ uint64_t GasEstimator::forESDTTransfer(size_t dataLength) const { } uint64_t GasEstimator::forESDTNFTTransfer(size_t dataLength) const { - uint64_t gasLimit = - this->networkConfig.getMinGasLimit() + - this->networkConfig.getGasCostESDTNFTTransfer() + + uint64_t gasLimit = + this->networkConfig.getMinGasLimit() + + this->networkConfig.getGasCostESDTNFTTransfer() + this->networkConfig.getGasPerDataByte() * dataLength + ADDITIONAL_GAS_FOR_ESDT_NFT_TRANSFER; return gasLimit; } + +} // namespace TW::Elrond diff --git a/src/Elrond/NetworkConfig.cpp b/src/Elrond/NetworkConfig.cpp index 98f5f6295a9..ba514e9183f 100644 --- a/src/Elrond/NetworkConfig.cpp +++ b/src/Elrond/NetworkConfig.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,12 +8,10 @@ #include -using namespace TW; -using namespace TW::Elrond; -using namespace std::chrono; +namespace TW::Elrond { -NetworkConfig::NetworkConfig() : - chainId("1") /* Mainnet */ { +NetworkConfig::NetworkConfig() + : chainId("1") /* Mainnet */ { } const std::string& NetworkConfig::getChainId() const { @@ -65,7 +63,7 @@ void NetworkConfig::setGasCostESDTNFTTransfer(uint32_t value) { } NetworkConfig NetworkConfig::GetDefault() { - const uint64_t timestamp = duration_cast(system_clock::now().time_since_epoch()).count(); + const uint64_t timestamp = duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); return GetByTimestamp(timestamp); } @@ -83,3 +81,5 @@ NetworkConfig NetworkConfig::GetByTimestamp(uint64_t timestamp) { return networkConfig; } + +} // namespace TW::Elrond diff --git a/src/Elrond/Signer.cpp b/src/Elrond/Signer.cpp index dcbd5d0144b..f26e6c0460c 100644 --- a/src/Elrond/Signer.cpp +++ b/src/Elrond/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,16 +8,13 @@ #include "Address.h" #include "Serialization.h" #include "TransactionFactory.h" -#include "../PublicKey.h" #include "HexCoding.h" #include -using namespace TW; -using namespace TW::Elrond; -using namespace TW::Elrond::Proto; +namespace TW::Elrond { -SigningOutput Signer::sign(const SigningInput &input) noexcept { +Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { TransactionFactory factory; auto transaction = factory.create(input); @@ -41,3 +38,5 @@ std::string Signer::signJSON(const std::string& json, const Data& key) { auto output = sign(input); return output.encoded(); } + +} // namespace TW::Elrond diff --git a/src/Elrond/Transaction.cpp b/src/Elrond/Transaction.cpp index 9345d50e143..24c8373e9c5 100644 --- a/src/Elrond/Transaction.cpp +++ b/src/Elrond/Transaction.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,21 +6,11 @@ #include "Transaction.h" -using namespace TW; -using namespace TW::Elrond; +namespace TW::Elrond { -Transaction::Transaction() : - nonce(0), - sender(""), - senderUsername(""), - receiver(""), - receiverUsername(""), - value("0"), - data(""), - gasPrice(0), - gasLimit(0), - chainID(""), - version(0), - options(0) { +Transaction::Transaction() + : nonce(0), sender(""), senderUsername(""), receiver(""), receiverUsername(""), value("0"), data(""), gasPrice(0), gasLimit(0), chainID(""), version(0), options(0) { } +} // namespace TW::Elrond + diff --git a/src/Elrond/TransactionFactory.cpp b/src/Elrond/TransactionFactory.cpp index d454bec8e1e..4e3a271165e 100644 --- a/src/Elrond/TransactionFactory.cpp +++ b/src/Elrond/TransactionFactory.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,21 +8,19 @@ #include "Codec.h" -using namespace TW; -using namespace TW::Elrond; +namespace TW::Elrond { const int TX_VERSION = 1; -TransactionFactory::TransactionFactory() : - TransactionFactory(NetworkConfig::GetDefault()) { +TransactionFactory::TransactionFactory() + : TransactionFactory(NetworkConfig::GetDefault()) { } -TransactionFactory::TransactionFactory(const NetworkConfig& networkConfig) : - networkConfig(networkConfig), - gasEstimator(networkConfig) { +TransactionFactory::TransactionFactory(const NetworkConfig& networkConfig) + : networkConfig(networkConfig), gasEstimator(networkConfig) { } -Transaction TransactionFactory::create(const Proto::SigningInput &input) { +Transaction TransactionFactory::create(const Proto::SigningInput& input) { if (input.has_egld_transfer()) { return fromEGLDTransfer(input); } else if (input.has_esdt_transfer()) { @@ -35,7 +33,7 @@ Transaction TransactionFactory::create(const Proto::SigningInput &input) { } /// Copies the input fields into a transaction object, without any other logic. -Transaction TransactionFactory::fromGenericAction(const Proto::SigningInput &input) { +Transaction TransactionFactory::fromGenericAction(const Proto::SigningInput& input) { auto action = input.generic_action(); Transaction transaction; @@ -55,7 +53,7 @@ Transaction TransactionFactory::fromGenericAction(const Proto::SigningInput &inp return transaction; } -Transaction TransactionFactory::fromEGLDTransfer(const Proto::SigningInput &input) { +Transaction TransactionFactory::fromEGLDTransfer(const Proto::SigningInput& input) { auto transfer = input.egld_transfer(); uint64_t estimatedGasLimit = this->gasEstimator.forEGLDTransfer(0); @@ -75,12 +73,12 @@ Transaction TransactionFactory::fromEGLDTransfer(const Proto::SigningInput &inpu return transaction; } -Transaction TransactionFactory::fromESDTTransfer(const Proto::SigningInput &input) { +Transaction TransactionFactory::fromESDTTransfer(const Proto::SigningInput& input) { auto transfer = input.esdt_transfer(); std::string encodedTokenIdentifier = Codec::encodeString(transfer.token_identifier()); std::string encodedAmount = Codec::encodeBigInt(transfer.amount()); - std::string data = prepareFunctionCall("ESDTTransfer", { encodedTokenIdentifier, encodedAmount }); + std::string data = prepareFunctionCall("ESDTTransfer", {encodedTokenIdentifier, encodedAmount}); uint64_t estimatedGasLimit = this->gasEstimator.forESDTTransfer(data.size()); Transaction transaction; @@ -99,16 +97,16 @@ Transaction TransactionFactory::fromESDTTransfer(const Proto::SigningInput &inpu return transaction; } -Transaction TransactionFactory::fromESDTNFTTransfer(const Proto::SigningInput &input) { +Transaction TransactionFactory::fromESDTNFTTransfer(const Proto::SigningInput& input) { auto transfer = input.esdtnft_transfer(); std::string encodedCollection = Codec::encodeString(transfer.token_collection()); std::string encodedNonce = Codec::encodeUint64(transfer.token_nonce()); std::string encodedQuantity = Codec::encodeBigInt(transfer.amount()); std::string encodedReceiver = Codec::encodeAddress(transfer.accounts().receiver()); - std::string data = prepareFunctionCall("ESDTNFTTransfer", { encodedCollection, encodedNonce, encodedQuantity, encodedReceiver }); + std::string data = prepareFunctionCall("ESDTNFTTransfer", {encodedCollection, encodedNonce, encodedQuantity, encodedReceiver}); uint64_t estimatedGasLimit = this->gasEstimator.forESDTNFTTransfer(data.size()); - + Transaction transaction; transaction.nonce = transfer.accounts().sender_nonce(); // For NFT, SFT and MetaESDT, transaction.sender == transaction.receiver. @@ -149,3 +147,5 @@ std::string TransactionFactory::prepareFunctionCall(const std::string& function, return result; } + +} // namespace TW::Elrond diff --git a/src/Ethereum/ABI/Bytes.cpp b/src/Ethereum/ABI/Bytes.cpp index 986bfa66216..0b40d521bb1 100644 --- a/src/Ethereum/ABI/Bytes.cpp +++ b/src/Ethereum/ABI/Bytes.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,8 +12,7 @@ #include -using namespace TW::Ethereum::ABI; -using namespace TW; +namespace TW::Ethereum::ABI { void ParamByteArray::encodeBytes(const Data& bytes, Data& data) { ValueEncoder::encodeUInt256(uint256_t(bytes.size()), data); @@ -126,3 +125,5 @@ Data ParamString::hashStruct() const { hash = Hash::keccak256(encoded); return hash; } + +} // namespace TW::Ethereum::ABI diff --git a/src/Ethereum/ABI/Function.cpp b/src/Ethereum/ABI/Function.cpp index b2c067fcb26..9057d539d74 100644 --- a/src/Ethereum/ABI/Function.cpp +++ b/src/Ethereum/ABI/Function.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,12 +6,9 @@ #include "Function.h" -#include "../../Data.h" - #include -using namespace TW; -using namespace TW::Ethereum::ABI; +namespace TW::Ethereum::ABI { Data Function::getSignature() const { auto typ = getType(); @@ -28,14 +25,18 @@ void Function::encode(Data& data) const { bool Function::decodeOutput(const Data& encoded, size_t& offset_inout) { // read parameter values - if (!_outParams.decode(encoded, offset_inout)) { return false; } + if (!_outParams.decode(encoded, offset_inout)) { + return false; + } return true; } bool Function::decodeInput(const Data& encoded, size_t& offset_inout) { // read 4-byte hash auto p = ParamByteArrayFix(4); - if (!p.decode(encoded, offset_inout)) { return false; } + if (!p.decode(encoded, offset_inout)) { + return false; + } std::vector hash = p.getVal(); // adjust offset; hash is NOT padded to 32 bytes offset_inout = offset_inout - 32 + 4; @@ -46,6 +47,10 @@ bool Function::decodeInput(const Data& encoded, size_t& offset_inout) { return false; } // read parameters - if (!_inParams.decode(encoded, offset_inout)) { return false; } + if (!_inParams.decode(encoded, offset_inout)) { + return false; + } return true; } + +} // namespace TW::Ethereum::ABI diff --git a/src/Ethereum/ABI/ParamAddress.cpp b/src/Ethereum/ABI/ParamAddress.cpp index 43491026210..2d06aca161e 100644 --- a/src/Ethereum/ABI/ParamAddress.cpp +++ b/src/Ethereum/ABI/ParamAddress.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,8 +8,7 @@ #include #include -using namespace TW::Ethereum::ABI; -using namespace TW; +namespace TW::Ethereum::ABI { Data ParamAddress::getData() const { Data data = store(getVal(), bytes); @@ -20,3 +19,5 @@ bool ParamAddress::setValueJson(const std::string& value) { setVal(load(parse_hex(value))); return true; } + +} // namespace TW::Ethereum::ABI diff --git a/src/Ethereum/ABI/ParamNumber.cpp b/src/Ethereum/ABI/ParamNumber.cpp index ba4308cc985..07c05516883 100644 --- a/src/Ethereum/ABI/ParamNumber.cpp +++ b/src/Ethereum/ABI/ParamNumber.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -15,9 +15,7 @@ #include #include -using namespace TW; -using namespace TW::Ethereum::ABI; - +namespace TW::Ethereum::ABI { bool ParamUInt256::setUInt256FromValueJson(uint256_t& dest, const std::string& value) { // try hex string or number @@ -38,21 +36,31 @@ bool ParamInt256::setInt256FromValueJson(int256_t& dest, const std::string& valu } bool ParamBool::setValueJson(const std::string& value) { - if (value == "true" || value == "1") { setVal(true); return true; } - if (value == "false" || value == "0") { setVal(false); return true; } + if (value == "true" || value == "1") { + setVal(true); + return true; + } + if (value == "false" || value == "0") { + setVal(false); + return true; + } return false; } bool ParamUInt8::setValueJson(const std::string& value) { uint16_t val; - if (!boost::conversion::detail::try_lexical_convert(value, val)) { return false; } + if (!boost::conversion::detail::try_lexical_convert(value, val)) { + return false; + } setVal(static_cast(val)); return true; } bool ParamInt8::setValueJson(const std::string& value) { int16_t val; - if (!boost::conversion::detail::try_lexical_convert(value, val)) { return false; } + if (!boost::conversion::detail::try_lexical_convert(value, val)) { + return false; + } setVal(static_cast(val)); return true; } @@ -103,7 +111,8 @@ bool ParamIntN::decode(const Data& encoded, size_t& offset_inout) { return res; } -void ParamIntN::init() -{ +void ParamIntN::init() { _mask = ParamUIntN::maskForBits(bits); } + +} // namespace TW::Ethereum::ABI diff --git a/src/Ethereum/ABI/ParamStruct.cpp b/src/Ethereum/ABI/ParamStruct.cpp index 9346daa497c..7910c0db7f5 100644 --- a/src/Ethereum/ABI/ParamStruct.cpp +++ b/src/Ethereum/ABI/ParamStruct.cpp @@ -7,7 +7,6 @@ #include "ParamStruct.h" #include "ValueEncoder.h" #include "ParamFactory.h" -#include "ParamAddress.h" #include #include @@ -17,14 +16,13 @@ #include #include -using namespace TW::Ethereum::ABI; -using namespace TW; +namespace TW::Ethereum::ABI { + using json = nlohmann::json; static const Data EipStructPrefix = parse_hex("1901"); static const auto Eip712Domain = "EIP712Domain"; - std::string ParamNamed::getType() const { return _param->getType() + " " + _name; } @@ -64,7 +62,7 @@ std::string ParamSetNamed::getType() const { Data ParamSetNamed::encodeHashes() const { Data hashes; - for (auto p: _params) { + for (auto p : _params) { append(hashes, p->hashStruct()); } return hashes; @@ -87,8 +85,8 @@ std::string ParamSetNamed::getExtraTypes(std::vector& ignoreList) c return lhs.compare(rhs) < 0; }); - for (auto& p: params) { - auto pType = p->_param->getType(); + for (auto& p : params) { + auto pType = p->_param->getType(); if (std::find(ignoreList.begin(), ignoreList.end(), pType) == ignoreList.end()) { types += p->getExtraTypes(ignoreList); ignoreList.push_back(pType); @@ -98,7 +96,7 @@ std::string ParamSetNamed::getExtraTypes(std::vector& ignoreList) c } std::shared_ptr ParamSetNamed::findParamByName(const std::string& name) const { - for (auto& p: _params) { + for (auto& p : _params) { if (p->_name == name) { return p; } @@ -181,11 +179,11 @@ Data ParamStruct::hashStructJson(const std::string& messageJson) { return Hash::keccak256(hashes); } } - return {}; // fallback + return {}; // fallback } std::shared_ptr findType(const std::string& typeName, const std::vector>& types) { - for (auto& t: types) { + for (auto& t : types) { if (t->getType() == typeName) { return t; } @@ -249,7 +247,7 @@ std::shared_ptr ParamStruct::makeStruct(const std::string& structTy tmp->setProto(subStruct); params.push_back(std::make_shared(name, tmp)); } else { - for (const auto& e: value) { + for (const auto& e : value) { auto subStruct = makeStruct(arrayType, e.dump(), typesJson); if (!subStruct) { throw std::invalid_argument("Could not process array sub-struct " + arrayType + " " + e.dump()); @@ -300,7 +298,7 @@ std::shared_ptr ParamStruct::makeType(const std::string& structName throw std::invalid_argument("Expecting array"); } std::vector> params; - for(auto& p2: jsonValue) { + for (auto& p2 : jsonValue) { auto name = p2["name"].get(); auto type = p2["type"].get(); if (name.empty() || type.empty()) { @@ -383,3 +381,5 @@ std::vector> ParamStruct::makeTypes(const std::stri throw std::invalid_argument("Could not process Json"); } } + +} // namespace TW::Ethereum::ABI diff --git a/src/Ethereum/ABI/Parameters.cpp b/src/Ethereum/ABI/Parameters.cpp index 40d1413434e..3cc66daefd9 100644 --- a/src/Ethereum/ABI/Parameters.cpp +++ b/src/Ethereum/ABI/Parameters.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,8 +11,7 @@ #include #include -using namespace TW::Ethereum::ABI; -using namespace TW; +namespace TW::Ethereum::ABI { ParamSet::~ParamSet() { _params.clear(); @@ -69,7 +68,7 @@ std::string ParamSet::getType() const { } bool ParamSet::isDynamic() const { - for (const auto& p: _params) { + for (const auto& p : _params) { if (p->isDynamic()) { return true; } @@ -80,7 +79,7 @@ bool ParamSet::isDynamic() const { size_t ParamSet::getSize() const { // 2-pass encoding size_t s = 0; - for (auto p: _params) { + for (auto p : _params) { if (p->isDynamic() || p->getSize() > ValueEncoder::encodedIntSize) { // offset used s += 32; @@ -156,7 +155,7 @@ bool ParamSet::decode(const Data& encoded, size_t& offset_inout) { Data ParamSet::encodeHashes() const { Data hashes; - for (auto p: _params) { + for (auto p : _params) { append(hashes, p->hashStruct()); } return hashes; @@ -170,3 +169,5 @@ Data Parameters::hashStruct() const { } return hash; } + +} // namespace TW::Ethereum::ABI diff --git a/src/Ethereum/ABI/Tuple.cpp b/src/Ethereum/ABI/Tuple.cpp index 72c6a6a66d2..c674592ff2b 100644 --- a/src/Ethereum/ABI/Tuple.cpp +++ b/src/Ethereum/ABI/Tuple.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,14 +6,12 @@ #include "Tuple.h" -#include "Data.h" - #include -using namespace TW; -using namespace TW::Ethereum::ABI; - +namespace TW::Ethereum::ABI { int ParamTuple::addParam(std::shared_ptr param) { return _params.addParam(param); } + +} // namespace TW::Ethereum::ABI \ No newline at end of file diff --git a/src/Ethereum/Address.cpp b/src/Ethereum/Address.cpp index a59c7b5f035..48d013bde0c 100644 --- a/src/Ethereum/Address.cpp +++ b/src/Ethereum/Address.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,10 +6,9 @@ #include "Address.h" #include "AddressChecksum.h" -#include "../Hash.h" #include "../HexCoding.h" -using namespace TW::Ethereum; +namespace TW::Ethereum { bool Address::isValid(const std::string& string) { if (string.size() != 42 || string[0] != '0' || string[1] != 'x') { @@ -45,3 +44,5 @@ Address::Address(const PublicKey& publicKey) { std::string Address::string() const { return checksumed(*this); } + +} // namespace TW::Ethereum diff --git a/src/Ethereum/AddressChecksum.cpp b/src/Ethereum/AddressChecksum.cpp index 73e3c93d2df..da69f905a7e 100644 --- a/src/Ethereum/AddressChecksum.cpp +++ b/src/Ethereum/AddressChecksum.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,14 +6,12 @@ #include "AddressChecksum.h" -#include "../Hash.h" #include "../HexCoding.h" #include -using namespace TW; -using namespace TW::Ethereum; +namespace TW::Ethereum { -std::string Ethereum::checksumed(const Address& address) { +std::string checksumed(const Address& address) { const auto addressString = hex(address.bytes); const auto hash = hex(Hash::keccak256(addressString)); @@ -32,3 +30,5 @@ std::string Ethereum::checksumed(const Address& address) { return string; } + +} // namespace TW::Ethereum diff --git a/src/Ethereum/Entry.cpp b/src/Ethereum/Entry.cpp index e06875cdd48..f5a7c7ab87e 100644 --- a/src/Ethereum/Entry.cpp +++ b/src/Ethereum/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,8 +11,8 @@ #include "proto/TransactionCompiler.pb.h" -using namespace TW::Ethereum; -using namespace TW; +namespace TW::Ethereum { + using namespace std; bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { @@ -71,7 +71,7 @@ Data Entry::buildTransactionInput([[maybe_unused]] TWCoinType coinType, [[maybe_ auto chainIdData = store(uint256_t(1)); if (chainId.length() > 0) { // parse amount - uint256_t chainIdUint256 { chainId }; + uint256_t chainIdUint256{chainId}; chainIdData = store(chainIdUint256); } input.set_chain_id(chainIdData.data(), chainIdData.size()); @@ -90,3 +90,5 @@ Data Entry::buildTransactionInput([[maybe_unused]] TWCoinType coinType, [[maybe_ const auto txInputData = data(input.SerializeAsString()); return txInputData; } + +} // namespace TW::Ethereum diff --git a/src/Ethereum/RLP.cpp b/src/Ethereum/RLP.cpp index 5d794867f8d..50817bbd467 100644 --- a/src/Ethereum/RLP.cpp +++ b/src/Ethereum/RLP.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,14 +6,11 @@ #include "RLP.h" -#include "../Data.h" -#include "../uint256.h" #include "../BinaryCoding.h" #include -using namespace TW; -using namespace TW::Ethereum; +namespace TW::Ethereum { Data RLP::encode(const uint256_t& value) noexcept { using boost::multiprecision::cpp_int; @@ -63,7 +60,7 @@ Data RLP::encodeHeader(uint64_t size, uint8_t smallTag, uint8_t largeTag) noexce Data RLP::putVarInt(uint64_t i) noexcept { Data bytes; // accumulate bytes here, in reverse order do { - // take LSB byte, append + // take LSB byte, append bytes.push_back(i & 0xff); i = i >> 8; } while (i); @@ -93,7 +90,7 @@ uint64_t RLP::parseVarInt(size_t size, const Data& data, size_t index) { RLP::DecodedItem RLP::decodeList(const Data& input) { RLP::DecodedItem item; auto remainder = input; - while(true) { + while (true) { auto listItem = RLP::decode(remainder); item.decoded.push_back(listItem.decoded[0]); if (listItem.remainder.size() == 0) { @@ -142,7 +139,7 @@ RLP::DecodedItem RLP::decode(const Data& input) { item.remainder = subData(input, 1 + strLen); return item; - } + } if (prefix <= 0xbf) { // b8--bf: long string auto lenOfStrLen = size_t(prefix - 0xb7); @@ -154,7 +151,7 @@ RLP::DecodedItem RLP::decode(const Data& input) { item.decoded.push_back(data); item.remainder = subData(input, 1 + lenOfStrLen + strLen); return item; - } + } if (prefix <= 0xf7) { // c0--f7: a list between 0-55 bytes long auto listLen = size_t(prefix - 0xc0); @@ -174,8 +171,8 @@ RLP::DecodedItem RLP::decode(const Data& input) { } item.remainder = subData(input, 1 + listLen); return item; - } - // f8--ff + } + // f8--ff auto lenOfListLen = size_t(prefix - 0xf7); auto listLen = static_cast(parseVarInt(lenOfListLen, input, 1)); if (listLen < 56) { @@ -193,3 +190,5 @@ RLP::DecodedItem RLP::decode(const Data& input) { item.remainder = subData(input, 1 + lenOfListLen + listLen); return item; } + +} // namespace TW::Ethereum diff --git a/src/Ethereum/Signer.cpp b/src/Ethereum/Signer.cpp index 6e743fcf1cb..edfca7a0620 100644 --- a/src/Ethereum/Signer.cpp +++ b/src/Ethereum/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,8 +10,7 @@ #include #include -using namespace TW; -using namespace TW::Ethereum; +namespace TW::Ethereum { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { try { @@ -127,140 +126,134 @@ std::shared_ptr Signer::build(const Proto::SigningInput& input) uint256_t maxInclusionFeePerGas = load(input.max_inclusion_fee_per_gas()); uint256_t maxFeePerGas = load(input.max_fee_per_gas()); switch (input.transaction().transaction_oneof_case()) { - case Proto::Transaction::kTransfer: - { - switch (input.tx_mode()) { - case Proto::TransactionMode::Legacy: - default: - return TransactionNonTyped::buildNativeTransfer( - nonce, gasPrice, gasLimit, - /* to: */ toAddress, - /* amount: */ load(input.transaction().transfer().amount()), - /* optional data: */ Data(input.transaction().transfer().data().begin(), input.transaction().transfer().data().end())); - - case Proto::TransactionMode::Enveloped: // Eip1559 - return TransactionEip1559::buildNativeTransfer( - nonce, maxInclusionFeePerGas, maxFeePerGas, gasLimit, - /* to: */ toAddress, - /* amount: */ load(input.transaction().transfer().amount()), - /* optional data: */ Data(input.transaction().transfer().data().begin(), input.transaction().transfer().data().end())); - } - } - - case Proto::Transaction::kErc20Transfer: - { - Data tokenToAddress = addressStringToData(input.transaction().erc20_transfer().to()); - switch (input.tx_mode()) { - case Proto::TransactionMode::Legacy: - default: - return TransactionNonTyped::buildERC20Transfer( - nonce, gasPrice, gasLimit, - /* tokenContract: */ toAddress, - /* toAddress */ tokenToAddress, - /* amount: */ load(input.transaction().erc20_transfer().amount())); - - case Proto::TransactionMode::Enveloped: // Eip1559 - return TransactionEip1559::buildERC20Transfer( - nonce, maxInclusionFeePerGas, maxFeePerGas, gasLimit, - /* tokenContract: */ toAddress, - /* toAddress */ tokenToAddress, - /* amount: */ load(input.transaction().erc20_transfer().amount())); - } - } - - case Proto::Transaction::kErc20Approve: - { - Data spenderAddress = addressStringToData(input.transaction().erc20_approve().spender()); - switch (input.tx_mode()) { - case Proto::TransactionMode::Legacy: - default: - return TransactionNonTyped::buildERC20Approve( - nonce, gasPrice, gasLimit, - /* tokenContract: */ toAddress, - /* toAddress */ spenderAddress, - /* amount: */ load(input.transaction().erc20_approve().amount())); - - case Proto::TransactionMode::Enveloped: // Eip1559 - return TransactionEip1559::buildERC20Approve( - nonce, maxInclusionFeePerGas, maxFeePerGas, gasLimit, - /* tokenContract: */ toAddress, - /* toAddress */ spenderAddress, - /* amount: */ load(input.transaction().erc20_approve().amount())); - } - } - - case Proto::Transaction::kErc721Transfer: - { - Data tokenToAddress = addressStringToData(input.transaction().erc721_transfer().to()); - Data tokenFromAddress = addressStringToData(input.transaction().erc721_transfer().from()); - switch (input.tx_mode()) { - case Proto::TransactionMode::Legacy: - default: - return TransactionNonTyped::buildERC721Transfer( - nonce, gasPrice, gasLimit, - /* tokenContract: */ toAddress, - /* fromAddress: */ tokenFromAddress, - /* toAddress */ tokenToAddress, - /* tokenId: */ load(input.transaction().erc721_transfer().token_id())); - - case Proto::TransactionMode::Enveloped: // Eip1559 - return TransactionEip1559::buildERC721Transfer( - nonce, maxInclusionFeePerGas, maxFeePerGas, gasLimit, - /* tokenContract: */ toAddress, - /* fromAddress: */ tokenFromAddress, - /* toAddress */ tokenToAddress, - /* tokenId: */ load(input.transaction().erc721_transfer().token_id())); - } - } - - case Proto::Transaction::kErc1155Transfer: - { - Data tokenToAddress = addressStringToData(input.transaction().erc1155_transfer().to()); - Data tokenFromAddress = addressStringToData(input.transaction().erc1155_transfer().from()); - switch (input.tx_mode()) { - case Proto::TransactionMode::Legacy: - default: - return TransactionNonTyped::buildERC1155Transfer( - nonce, gasPrice, gasLimit, - /* tokenContract: */ toAddress, - /* fromAddress: */ tokenFromAddress, - /* toAddress */ tokenToAddress, - /* tokenId: */ load(input.transaction().erc1155_transfer().token_id()), - /* value */ load(input.transaction().erc1155_transfer().value()), - /* data */ Data(input.transaction().erc1155_transfer().data().begin(), input.transaction().erc1155_transfer().data().end())); - - case Proto::TransactionMode::Enveloped: // Eip1559 - return TransactionEip1559::buildERC1155Transfer( - nonce, maxInclusionFeePerGas, maxFeePerGas, gasLimit, - /* tokenContract: */ toAddress, - /* fromAddress: */ tokenFromAddress, - /* toAddress */ tokenToAddress, - /* tokenId: */ load(input.transaction().erc1155_transfer().token_id()), - /* value */ load(input.transaction().erc1155_transfer().value()), - /* data */ Data(input.transaction().erc1155_transfer().data().begin(), input.transaction().erc1155_transfer().data().end())); - } - } - - case Proto::Transaction::kContractGeneric: + case Proto::Transaction::kTransfer: { + switch (input.tx_mode()) { + case Proto::TransactionMode::Legacy: default: - { - switch (input.tx_mode()) { - case Proto::TransactionMode::Legacy: - default: - return TransactionNonTyped::buildNativeTransfer( - nonce, gasPrice, gasLimit, - /* to: */ toAddress, - /* amount: */ load(input.transaction().contract_generic().amount()), - /* transaction: */ Data(input.transaction().contract_generic().data().begin(), input.transaction().contract_generic().data().end())); - - case Proto::TransactionMode::Enveloped: // Eip1559 - return TransactionEip1559::buildNativeTransfer( - nonce, maxInclusionFeePerGas, maxFeePerGas, gasLimit, - /* to: */ toAddress, - /* amount: */ load(input.transaction().contract_generic().amount()), - /* transaction: */ Data(input.transaction().contract_generic().data().begin(), input.transaction().contract_generic().data().end())); - } - } + return TransactionNonTyped::buildNativeTransfer( + nonce, gasPrice, gasLimit, + /* to: */ toAddress, + /* amount: */ load(input.transaction().transfer().amount()), + /* optional data: */ Data(input.transaction().transfer().data().begin(), input.transaction().transfer().data().end())); + + case Proto::TransactionMode::Enveloped: // Eip1559 + return TransactionEip1559::buildNativeTransfer( + nonce, maxInclusionFeePerGas, maxFeePerGas, gasLimit, + /* to: */ toAddress, + /* amount: */ load(input.transaction().transfer().amount()), + /* optional data: */ Data(input.transaction().transfer().data().begin(), input.transaction().transfer().data().end())); + } + } + + case Proto::Transaction::kErc20Transfer: { + Data tokenToAddress = addressStringToData(input.transaction().erc20_transfer().to()); + switch (input.tx_mode()) { + case Proto::TransactionMode::Legacy: + default: + return TransactionNonTyped::buildERC20Transfer( + nonce, gasPrice, gasLimit, + /* tokenContract: */ toAddress, + /* toAddress */ tokenToAddress, + /* amount: */ load(input.transaction().erc20_transfer().amount())); + + case Proto::TransactionMode::Enveloped: // Eip1559 + return TransactionEip1559::buildERC20Transfer( + nonce, maxInclusionFeePerGas, maxFeePerGas, gasLimit, + /* tokenContract: */ toAddress, + /* toAddress */ tokenToAddress, + /* amount: */ load(input.transaction().erc20_transfer().amount())); + } + } + + case Proto::Transaction::kErc20Approve: { + Data spenderAddress = addressStringToData(input.transaction().erc20_approve().spender()); + switch (input.tx_mode()) { + case Proto::TransactionMode::Legacy: + default: + return TransactionNonTyped::buildERC20Approve( + nonce, gasPrice, gasLimit, + /* tokenContract: */ toAddress, + /* toAddress */ spenderAddress, + /* amount: */ load(input.transaction().erc20_approve().amount())); + + case Proto::TransactionMode::Enveloped: // Eip1559 + return TransactionEip1559::buildERC20Approve( + nonce, maxInclusionFeePerGas, maxFeePerGas, gasLimit, + /* tokenContract: */ toAddress, + /* toAddress */ spenderAddress, + /* amount: */ load(input.transaction().erc20_approve().amount())); + } + } + + case Proto::Transaction::kErc721Transfer: { + Data tokenToAddress = addressStringToData(input.transaction().erc721_transfer().to()); + Data tokenFromAddress = addressStringToData(input.transaction().erc721_transfer().from()); + switch (input.tx_mode()) { + case Proto::TransactionMode::Legacy: + default: + return TransactionNonTyped::buildERC721Transfer( + nonce, gasPrice, gasLimit, + /* tokenContract: */ toAddress, + /* fromAddress: */ tokenFromAddress, + /* toAddress */ tokenToAddress, + /* tokenId: */ load(input.transaction().erc721_transfer().token_id())); + + case Proto::TransactionMode::Enveloped: // Eip1559 + return TransactionEip1559::buildERC721Transfer( + nonce, maxInclusionFeePerGas, maxFeePerGas, gasLimit, + /* tokenContract: */ toAddress, + /* fromAddress: */ tokenFromAddress, + /* toAddress */ tokenToAddress, + /* tokenId: */ load(input.transaction().erc721_transfer().token_id())); + } + } + + case Proto::Transaction::kErc1155Transfer: { + Data tokenToAddress = addressStringToData(input.transaction().erc1155_transfer().to()); + Data tokenFromAddress = addressStringToData(input.transaction().erc1155_transfer().from()); + switch (input.tx_mode()) { + case Proto::TransactionMode::Legacy: + default: + return TransactionNonTyped::buildERC1155Transfer( + nonce, gasPrice, gasLimit, + /* tokenContract: */ toAddress, + /* fromAddress: */ tokenFromAddress, + /* toAddress */ tokenToAddress, + /* tokenId: */ load(input.transaction().erc1155_transfer().token_id()), + /* value */ load(input.transaction().erc1155_transfer().value()), + /* data */ Data(input.transaction().erc1155_transfer().data().begin(), input.transaction().erc1155_transfer().data().end())); + + case Proto::TransactionMode::Enveloped: // Eip1559 + return TransactionEip1559::buildERC1155Transfer( + nonce, maxInclusionFeePerGas, maxFeePerGas, gasLimit, + /* tokenContract: */ toAddress, + /* fromAddress: */ tokenFromAddress, + /* toAddress */ tokenToAddress, + /* tokenId: */ load(input.transaction().erc1155_transfer().token_id()), + /* value */ load(input.transaction().erc1155_transfer().value()), + /* data */ Data(input.transaction().erc1155_transfer().data().begin(), input.transaction().erc1155_transfer().data().end())); + } + } + + case Proto::Transaction::kContractGeneric: + default: { + switch (input.tx_mode()) { + case Proto::TransactionMode::Legacy: + default: + return TransactionNonTyped::buildNativeTransfer( + nonce, gasPrice, gasLimit, + /* to: */ toAddress, + /* amount: */ load(input.transaction().contract_generic().amount()), + /* transaction: */ Data(input.transaction().contract_generic().data().begin(), input.transaction().contract_generic().data().end())); + + case Proto::TransactionMode::Enveloped: // Eip1559 + return TransactionEip1559::buildNativeTransfer( + nonce, maxInclusionFeePerGas, maxFeePerGas, gasLimit, + /* to: */ toAddress, + /* amount: */ load(input.transaction().contract_generic().amount()), + /* transaction: */ Data(input.transaction().contract_generic().data().begin(), input.transaction().contract_generic().data().end())); + } + } } } @@ -268,3 +261,5 @@ Signature Signer::sign(const PrivateKey& privateKey, const uint256_t& chainID, s auto preHash = transaction->preHash(chainID); return Signer::sign(privateKey, preHash, transaction->usesReplayProtection(), chainID); } + +} // namespace TW::Ethereum diff --git a/src/Ethereum/Transaction.cpp b/src/Ethereum/Transaction.cpp index 6ab37bf09e4..d033dbb6f80 100644 --- a/src/Ethereum/Transaction.cpp +++ b/src/Ethereum/Transaction.cpp @@ -6,45 +6,47 @@ #include "Transaction.h" #include "ABI/Function.h" -#include "ABI/ParamBase.h" #include "ABI/ParamAddress.h" -#include "RLP.h" +#include "ABI/ParamBase.h" #include "HexCoding.h" +#include "RLP.h" -using namespace TW::Ethereum::ABI; -using namespace TW::Ethereum; -using namespace TW; - +namespace TW::Ethereum { static const Data EmptyListEncoded = parse_hex("c0"); -std::shared_ptr TransactionNonTyped::buildNativeTransfer(const uint256_t& nonce, - const uint256_t& gasPrice, const uint256_t& gasLimit, - const Data& toAddress, const uint256_t& amount, const Data& data) { +std::shared_ptr +TransactionNonTyped::buildNativeTransfer(const uint256_t& nonce, + const uint256_t& gasPrice, const uint256_t& gasLimit, + const Data& toAddress, const uint256_t& amount, const Data& data) { return std::make_shared(nonce, gasPrice, gasLimit, toAddress, amount, data); } -std::shared_ptr TransactionNonTyped::buildERC20Transfer(const uint256_t& nonce, - const uint256_t& gasPrice, const uint256_t& gasLimit, - const Data& tokenContract, const Data& toAddress, const uint256_t& amount) { +std::shared_ptr +TransactionNonTyped::buildERC20Transfer(const uint256_t& nonce, + const uint256_t& gasPrice, const uint256_t& gasLimit, + const Data& tokenContract, const Data& toAddress, const uint256_t& amount) { return std::make_shared(nonce, gasPrice, gasLimit, tokenContract, 0, buildERC20TransferCall(toAddress, amount)); } -std::shared_ptr TransactionNonTyped::buildERC20Approve(const uint256_t& nonce, - const uint256_t& gasPrice, const uint256_t& gasLimit, - const Data& tokenContract, const Data& spenderAddress, const uint256_t& amount) { +std::shared_ptr +TransactionNonTyped::buildERC20Approve(const uint256_t& nonce, + const uint256_t& gasPrice, const uint256_t& gasLimit, + const Data& tokenContract, const Data& spenderAddress, const uint256_t& amount) { return std::make_shared(nonce, gasPrice, gasLimit, tokenContract, 0, buildERC20ApproveCall(spenderAddress, amount)); } -std::shared_ptr TransactionNonTyped::buildERC721Transfer(const uint256_t& nonce, - const uint256_t& gasPrice, const uint256_t& gasLimit, - const Data& tokenContract, const Data& from, const Data& to, const uint256_t& tokenId) { +std::shared_ptr +TransactionNonTyped::buildERC721Transfer(const uint256_t& nonce, + const uint256_t& gasPrice, const uint256_t& gasLimit, + const Data& tokenContract, const Data& from, const Data& to, const uint256_t& tokenId) { return std::make_shared(nonce, gasPrice, gasLimit, tokenContract, 0, buildERC721TransferFromCall(from, to, tokenId)); } -std::shared_ptr TransactionNonTyped::buildERC1155Transfer(const uint256_t& nonce, - const uint256_t& gasPrice, const uint256_t& gasLimit, - const Data& tokenContract, const Data& from, const Data& to, const uint256_t& tokenId, const uint256_t& value, const Data& data) { +std::shared_ptr +TransactionNonTyped::buildERC1155Transfer(const uint256_t& nonce, + const uint256_t& gasPrice, const uint256_t& gasLimit, + const Data& tokenContract, const Data& from, const Data& to, const uint256_t& tokenId, const uint256_t& value, const Data& data) { return std::make_shared(nonce, gasPrice, gasLimit, tokenContract, 0, buildERC1155TransferFromCall(from, to, tokenId, value, data)); } @@ -81,44 +83,52 @@ Data TransactionNonTyped::encoded(const Signature& signature, [[maybe_unused]] c } Data TransactionNonTyped::buildERC20TransferCall(const Data& to, const uint256_t& amount) { - auto func = Function("transfer", std::vector>{ - std::make_shared(to), - std::make_shared(amount) + // clang-format off + auto func = ABI::Function("transfer", std::vector>{ + std::make_shared(to), + std::make_shared(amount) }); + // clang-format on Data payload; func.encode(payload); return payload; } Data TransactionNonTyped::buildERC20ApproveCall(const Data& spender, const uint256_t& amount) { - auto func = Function("approve", std::vector>{ - std::make_shared(spender), - std::make_shared(amount) + // clang-format off + auto func = ABI::Function("approve", std::vector>{ + std::make_shared(spender), + std::make_shared(amount) }); + // clang-format on Data payload; func.encode(payload); return payload; } Data TransactionNonTyped::buildERC721TransferFromCall(const Data& from, const Data& to, const uint256_t& tokenId) { - auto func = Function("transferFrom", std::vector>{ - std::make_shared(from), - std::make_shared(to), - std::make_shared(tokenId) + // clang-format off + auto func = ABI::Function("transferFrom", std::vector>{ + std::make_shared(from), + std::make_shared(to), + std::make_shared(tokenId) }); + // clang-format on Data payload; func.encode(payload); return payload; } Data TransactionNonTyped::buildERC1155TransferFromCall(const Data& from, const Data& to, const uint256_t& tokenId, const uint256_t& value, const Data& data) { - auto func = Function("safeTransferFrom", std::vector>{ - std::make_shared(from), - std::make_shared(to), - std::make_shared(tokenId), - std::make_shared(value), - std::make_shared(data) + // clang-format off + auto func = ABI::Function("safeTransferFrom", std::vector>{ + std::make_shared(from), + std::make_shared(to), + std::make_shared(tokenId), + std::make_shared(value), + std::make_shared(data) }); + // clang-format on Data payload; func.encode(payload); return payload; @@ -167,32 +177,39 @@ Data TransactionEip1559::encoded(const Signature& signature, const uint256_t cha return envelope; } -std::shared_ptr TransactionEip1559::buildNativeTransfer(const uint256_t& nonce, - const uint256_t& maxInclusionFeePerGas, const uint256_t& maxFeePerGas, const uint256_t& gasPrice, - const Data& toAddress, const uint256_t& amount, const Data& data) { +std::shared_ptr +TransactionEip1559::buildNativeTransfer(const uint256_t& nonce, + const uint256_t& maxInclusionFeePerGas, const uint256_t& maxFeePerGas, const uint256_t& gasPrice, + const Data& toAddress, const uint256_t& amount, const Data& data) { return std::make_shared(nonce, maxInclusionFeePerGas, maxFeePerGas, gasPrice, toAddress, amount, data); } -std::shared_ptr TransactionEip1559::buildERC20Transfer(const uint256_t& nonce, - const uint256_t& maxInclusionFeePerGas, const uint256_t& maxFeePerGas, const uint256_t& gasPrice, - const Data& tokenContract, const Data& toAddress, const uint256_t& amount) { +std::shared_ptr +TransactionEip1559::buildERC20Transfer(const uint256_t& nonce, + const uint256_t& maxInclusionFeePerGas, const uint256_t& maxFeePerGas, const uint256_t& gasPrice, + const Data& tokenContract, const Data& toAddress, const uint256_t& amount) { return std::make_shared(nonce, maxInclusionFeePerGas, maxFeePerGas, gasPrice, tokenContract, 0, TransactionNonTyped::buildERC20TransferCall(toAddress, amount)); } -std::shared_ptr TransactionEip1559::buildERC20Approve(const uint256_t& nonce, - const uint256_t& maxInclusionFeePerGas, const uint256_t& maxFeePerGas, const uint256_t& gasPrice, - const Data& tokenContract, const Data& spenderAddress, const uint256_t& amount) { +std::shared_ptr +TransactionEip1559::buildERC20Approve(const uint256_t& nonce, + const uint256_t& maxInclusionFeePerGas, const uint256_t& maxFeePerGas, const uint256_t& gasPrice, + const Data& tokenContract, const Data& spenderAddress, const uint256_t& amount) { return std::make_shared(nonce, maxInclusionFeePerGas, maxFeePerGas, gasPrice, tokenContract, 0, TransactionNonTyped::buildERC20ApproveCall(spenderAddress, amount)); } -std::shared_ptr TransactionEip1559::buildERC721Transfer(const uint256_t& nonce, - const uint256_t& maxInclusionFeePerGas, const uint256_t& maxFeePerGas, const uint256_t& gasPrice, - const Data& tokenContract, const Data& from, const Data& to, const uint256_t& tokenId) { +std::shared_ptr +TransactionEip1559::buildERC721Transfer(const uint256_t& nonce, + const uint256_t& maxInclusionFeePerGas, const uint256_t& maxFeePerGas, const uint256_t& gasPrice, + const Data& tokenContract, const Data& from, const Data& to, const uint256_t& tokenId) { return std::make_shared(nonce, maxInclusionFeePerGas, maxFeePerGas, gasPrice, tokenContract, 0, TransactionNonTyped::buildERC721TransferFromCall(from, to, tokenId)); } -std::shared_ptr TransactionEip1559::buildERC1155Transfer(const uint256_t& nonce, - const uint256_t& maxInclusionFeePerGas, const uint256_t& maxFeePerGas, const uint256_t& gasPrice, - const Data& tokenContract, const Data& from, const Data& to, const uint256_t& tokenId, const uint256_t& value, const Data& data) { +std::shared_ptr +TransactionEip1559::buildERC1155Transfer(const uint256_t& nonce, + const uint256_t& maxInclusionFeePerGas, const uint256_t& maxFeePerGas, const uint256_t& gasPrice, + const Data& tokenContract, const Data& from, const Data& to, const uint256_t& tokenId, const uint256_t& value, const Data& data) { return std::make_shared(nonce, maxInclusionFeePerGas, maxFeePerGas, gasPrice, tokenContract, 0, TransactionNonTyped::buildERC1155TransferFromCall(from, to, tokenId, value, data)); } + +} // namespace TW::Ethereum diff --git a/src/FIO/Actor.cpp b/src/FIO/Actor.cpp index 550b52489bd..f30c351e34f 100644 --- a/src/FIO/Actor.cpp +++ b/src/FIO/Actor.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,49 +8,50 @@ #include -using namespace TW::FIO; -using namespace std; +namespace TW::FIO { -static const auto pattern = regex(R"(\b([a-z1-5]{3,})[.@]?\b)"); -string Actor::actor(const Address& addr) -{ +static const auto pattern = std::regex(R"(\b([a-z1-5]{3,})[.@]?\b)"); +std::string Actor::actor(const Address& addr) { uint64_t shortenedKey = shortenKey(addr.bytes); - string name13 = name(shortenedKey); + std::string name13 = name(shortenedKey); // trim to 12 chracters return name13.substr(0, 12); } bool Actor::validate(const std::string& addr) { - smatch match; + std::smatch match; return regex_search(addr, match, pattern); } -uint64_t Actor::shortenKey(const array& addrKey) -{ +uint64_t Actor::shortenKey(const std::array& addrKey) { uint64_t res = 0; int i = 1; // Ignore key head int len = 0; while (len <= 12) { assert(i < 33); // Means the key has > 20 bytes with trailing zeroes... - + auto trimmed_char = uint64_t(addrKey[i] & (len == 12 ? 0x0f : 0x1f)); - if (trimmed_char == 0) { i++; continue; } // Skip a zero and move to next + if (trimmed_char == 0) { + i++; + continue; + } // Skip a zero and move to next auto shuffle = len == 12 ? 0 : 5 * (12 - len) - 1; res |= trimmed_char << shuffle; - len++; i++; + len++; + i++; } return res; } -string Actor::name(uint64_t shortKey) { +std::string Actor::name(uint64_t shortKey) { static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz"; - string str(13,'.'); //We are forcing the string to be 13 characters + std::string str(13, '.'); // We are forcing the string to be 13 characters uint64_t tmp = shortKey; - for(uint32_t i = 0; i <= 12; i++ ) { + for (uint32_t i = 0; i <= 12; i++) { char c = charmap[tmp & (i == 0 ? 0x0f : 0x1f)]; str[12 - i] = c; tmp >>= (i == 0 ? 4 : 5); @@ -58,3 +59,5 @@ string Actor::name(uint64_t shortKey) { return str; } + +} // namespace TW::FIO diff --git a/src/FIO/Entry.cpp b/src/FIO/Entry.cpp index 2bb73f10a5e..a9194cb53ae 100644 --- a/src/FIO/Entry.cpp +++ b/src/FIO/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,19 +9,20 @@ #include "Address.h" #include "Signer.h" -using namespace TW::FIO; -using namespace std; +namespace TW::FIO { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::FIO diff --git a/src/Filecoin/Address.cpp b/src/Filecoin/Address.cpp index f4598d0f9b2..56fc2b9963b 100644 --- a/src/Filecoin/Address.cpp +++ b/src/Filecoin/Address.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust. +// Copyright © 2017-2022 Trust. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,10 +10,8 @@ #include #include "../Base32.h" -#include "../Data.h" -using namespace TW; -using namespace TW::Filecoin; +namespace TW::Filecoin { static const char BASE32_ALPHABET_FILECOIN[] = "abcdefghijklmnopqrstuvwxyz234567"; static constexpr size_t checksumSize = 4; @@ -179,3 +177,5 @@ std::string Address::string() const { return s; } + +} // namespace TW::Filecoin diff --git a/src/Filecoin/Entry.cpp b/src/Filecoin/Entry.cpp index deeb0ff4a96..5ab6065a3ca 100644 --- a/src/Filecoin/Entry.cpp +++ b/src/Filecoin/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,17 +9,16 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Filecoin; -using namespace std; +namespace TW::Filecoin { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } @@ -28,6 +27,8 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D signTemplate(dataIn, dataOut); } -string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { +std::string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } + +} // namespace TW::Filecoin diff --git a/src/Filecoin/Signer.cpp b/src/Filecoin/Signer.cpp index 88f48a7e740..67676a9eeb7 100644 --- a/src/Filecoin/Signer.cpp +++ b/src/Filecoin/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust. +// Copyright © 2017-2022 Trust. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,8 +8,7 @@ #include "HexCoding.h" #include -using namespace TW; -using namespace TW::Filecoin; +namespace TW::Filecoin { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { // Load private key and transaction from Protobuf input. @@ -24,8 +23,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { /* value */ load(input.value()), /* gasLimit */ input.gas_limit(), /* gasFeeCap */ load(input.gas_fee_cap()), - /* gasPremium */ load(input.gas_premium()) - ); + /* gasPremium */ load(input.gas_premium())); // Sign transaction. auto signature = sign(key, transaction); @@ -50,3 +48,5 @@ std::string Signer::signJSON(const std::string& json, const Data& key) { auto output = Signer::sign(input); return output.json(); } + +} // namespace TW::Filecoin diff --git a/src/Filecoin/Transaction.cpp b/src/Filecoin/Transaction.cpp index ff9a2960fcc..311f71ecf97 100644 --- a/src/Filecoin/Transaction.cpp +++ b/src/Filecoin/Transaction.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust. +// Copyright © 2017-2022 Trust. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,12 +8,12 @@ #include #include "Base64.h" +namespace TW::Filecoin { + using json = nlohmann::json; -using namespace TW; -using namespace TW::Filecoin; // encodeBigInt encodes a Filecoin BigInt to CBOR. -Data TW::Filecoin::encodeBigInt(const uint256_t& value) { +Data encodeBigInt(const uint256_t& value) { if (value.is_zero()) { return {}; } @@ -61,6 +61,7 @@ Data Transaction::cid() const { return cid; } std::string Transaction::serialize(Data& signature) const { + // clang-format off json tx = { {"Message", json{ {"To", to.string()}, @@ -78,5 +79,8 @@ std::string Transaction::serialize(Data& signature) const { } }, }; + // clang-format on return tx.dump(); } + +} // namespace TW::Filecoin diff --git a/src/Groestlcoin/Address.cpp b/src/Groestlcoin/Address.cpp index 85a4258842f..290b097ad69 100644 --- a/src/Groestlcoin/Address.cpp +++ b/src/Groestlcoin/Address.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,9 +9,7 @@ #include "../Base58.h" #include -#include - -using namespace TW::Groestlcoin; +namespace TW::Groestlcoin { bool Address::isValid(const std::string& string) { const auto decoded = Base58::bitcoin.decodeCheck(string, Hash::HasherGroestl512d); @@ -60,3 +58,5 @@ Address::Address(const PublicKey& publicKey, uint8_t prefix) { std::string Address::string() const { return Base58::bitcoin.encodeCheck(bytes, Hash::HasherGroestl512d); } + +} // namespace TW::Groestlcoin diff --git a/src/Groestlcoin/Entry.cpp b/src/Groestlcoin/Entry.cpp index c98d916b3da..ae12284620a 100644 --- a/src/Groestlcoin/Entry.cpp +++ b/src/Groestlcoin/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,15 +10,13 @@ #include "../Bitcoin/SegwitAddress.h" #include "Signer.h" -using namespace TW::Groestlcoin; -using namespace std; +namespace TW::Groestlcoin { -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const { - return TW::Bitcoin::SegwitAddress::isValid(address, hrp) - || Address::isValid(address, {p2pkh, p2sh}); +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const { + return TW::Bitcoin::SegwitAddress::isValid(address, hrp) || Address::isValid(address, {p2pkh, p2sh}); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TW::byte p2pkh, const char* hrp) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TW::byte p2pkh, const char* hrp) const { return TW::Bitcoin::SegwitAddress(publicKey, hrp).string(); } @@ -29,3 +27,5 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D void Entry::plan([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { planTemplate(dataIn, dataOut); } + +} // namespace TW::Groestlcoin diff --git a/src/Groestlcoin/Signer.cpp b/src/Groestlcoin/Signer.cpp index d395fadc901..7b87e290ff6 100644 --- a/src/Groestlcoin/Signer.cpp +++ b/src/Groestlcoin/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,8 +12,7 @@ #include "HexCoding.h" #include "Transaction.h" -using namespace TW; -using namespace TW::Groestlcoin; +namespace TW::Groestlcoin { using TransactionBuilder = Bitcoin::TransactionBuilder; @@ -46,3 +45,5 @@ SigningOutput Signer::sign(const SigningInput& input) noexcept { output.set_transaction_id(hex(txHash)); return output; } + +} // namespace TW::Groestlcoin diff --git a/src/Harmony/Signer.cpp b/src/Harmony/Signer.cpp index 5d0d7aefe82..1c7d2c4a803 100644 --- a/src/Harmony/Signer.cpp +++ b/src/Harmony/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,8 +9,6 @@ #include "../HexCoding.h" #include -using namespace TW; - namespace TW::Harmony { std::tuple Signer::values(const uint256_t& chainID, @@ -338,7 +336,7 @@ void Signer::sign(const PrivateKey& privateKey, const Data& hash, T& transaction Data Signer::rlpNoHash(const Transaction& transaction, const bool include_vrs) const noexcept { auto encoded = Data(); - using namespace TW::Ethereum; + using RLP = TW::Ethereum::RLP; append(encoded, RLP::encode(transaction.nonce)); append(encoded, RLP::encode(transaction.gasPrice)); append(encoded, RLP::encode(transaction.gasLimit)); @@ -363,7 +361,8 @@ template Data Signer::rlpNoHash(const Staking& transaction, const bool include_vrs) const noexcept { auto encoded = Data(); - using namespace TW::Ethereum; + using RLP = TW::Ethereum::RLP; + append(encoded, RLP::encode(transaction.directive)); append(encoded, rlpNoHashDirective(transaction)); @@ -384,7 +383,7 @@ Data Signer::rlpNoHash(const Staking& transaction, const bool include Data Signer::rlpNoHashDirective(const Staking& transaction) const noexcept { auto encoded = Data(); - using namespace TW::Ethereum; + using RLP = TW::Ethereum::RLP; append(encoded, RLP::encode(transaction.stakeMsg.validatorAddress.getKeyHash())); @@ -435,7 +434,7 @@ Data Signer::rlpNoHashDirective(const Staking& transaction) con Data Signer::rlpNoHashDirective(const Staking& transaction) const noexcept { auto encoded = Data(); - using namespace TW::Ethereum; + using RLP = TW::Ethereum::RLP; append(encoded, RLP::encode(transaction.stakeMsg.validatorAddress.getKeyHash())); @@ -468,7 +467,7 @@ Data Signer::rlpNoHashDirective(const Staking& transaction) const Data Signer::rlpNoHashDirective(const Staking& transaction) const noexcept { auto encoded = Data(); - using namespace TW::Ethereum; + using RLP = TW::Ethereum::RLP; append(encoded, RLP::encode(transaction.stakeMsg.delegatorAddress.getKeyHash())); append(encoded, RLP::encode(transaction.stakeMsg.validatorAddress.getKeyHash())); append(encoded, RLP::encode(transaction.stakeMsg.amount)); @@ -477,7 +476,7 @@ Data Signer::rlpNoHashDirective(const Staking& transaction) const noex Data Signer::rlpNoHashDirective(const Staking& transaction) const noexcept { auto encoded = Data(); - using namespace TW::Ethereum; + using RLP = TW::Ethereum::RLP; append(encoded, RLP::encode(transaction.stakeMsg.delegatorAddress.getKeyHash())); append(encoded, RLP::encode(transaction.stakeMsg.validatorAddress.getKeyHash())); append(encoded, RLP::encode(transaction.stakeMsg.amount)); @@ -486,7 +485,7 @@ Data Signer::rlpNoHashDirective(const Staking& transaction) const no Data Signer::rlpNoHashDirective(const Staking& transaction) const noexcept { auto encoded = Data(); - using namespace TW::Ethereum; + using RLP = TW::Ethereum::RLP; append(encoded, RLP::encode(transaction.stakeMsg.delegatorAddress.getKeyHash())); return RLP::encodeList(encoded); } diff --git a/src/Harmony/Staking.cpp b/src/Harmony/Staking.cpp index a3f6291bbd8..7e99697541b 100644 --- a/src/Harmony/Staking.cpp +++ b/src/Harmony/Staking.cpp @@ -3,7 +3,3 @@ // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. - -#include "Staking.h" - -using namespace TW::Harmony; diff --git a/src/Harmony/Transaction.cpp b/src/Harmony/Transaction.cpp deleted file mode 100644 index b63874ff7fb..00000000000 --- a/src/Harmony/Transaction.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © 2017-2020 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -#include "Transaction.h" - -using namespace TW::Harmony; diff --git a/src/Icon/Address.cpp b/src/Icon/Address.cpp index 08aaf4e60bd..6f219a3b537 100644 --- a/src/Icon/Address.cpp +++ b/src/Icon/Address.cpp @@ -6,15 +6,10 @@ #include "Address.h" -#include "../Hash.h" #include "../HexCoding.h" -#include "../PrivateKey.h" #include -using namespace TW; -using namespace TW::Icon; - namespace TW::Icon { static const std::string addressPrefix = "hx"; diff --git a/src/Icon/Address.h b/src/Icon/Address.h index 1c2a8645f1c..8c699e91f71 100644 --- a/src/Icon/Address.h +++ b/src/Icon/Address.h @@ -23,7 +23,7 @@ class Address { /// Address data consisting of a prefix byte followed by the public key /// hash. - std::array bytes; + std::array bytes{}; /// Address type. enum AddressType type; diff --git a/src/Icon/Entry.cpp b/src/Icon/Entry.cpp index 688d5d2b288..66c6ff5d2ad 100644 --- a/src/Icon/Entry.cpp +++ b/src/Icon/Entry.cpp @@ -9,19 +9,20 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Icon; -using namespace std; +namespace TW::Icon { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey, Icon::TypeAddress).string(); } void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Icon diff --git a/src/Icon/Signer.cpp b/src/Icon/Signer.cpp index 9028f327d3c..b9c290c867e 100644 --- a/src/Icon/Signer.cpp +++ b/src/Icon/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,17 +10,14 @@ #include "../Hash.h" #include "../HexCoding.h" #include "../PrivateKey.h" -#include "../uint256.h" #include #include #include -#include #include -using namespace TW; -using namespace TW::Icon; +namespace TW::Icon { std::string to_hex(int64_t i) { std::stringstream ss; @@ -92,3 +89,5 @@ Proto::SigningOutput Signer::sign() const noexcept { return output; } + +} // namespace TW::Icon diff --git a/src/IoTeX/Signer.cpp b/src/IoTeX/Signer.cpp index 6b0e6d6ec1a..11f4f9d9067 100644 --- a/src/IoTeX/Signer.cpp +++ b/src/IoTeX/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,12 +6,11 @@ #include "Signer.h" #include "Hash.h" -#include "HexCoding.h" -#include "IoTeX/Staking.h" #include "PrivateKey.h" using namespace TW; -using namespace TW::IoTeX; + +namespace TW::IoTeX { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto signer = Signer(input); @@ -48,3 +47,5 @@ void Signer::toActionCore() { action.ParseFromString(input.SerializeAsString()); action.DiscardUnknownFields(); } + +} // namespace TW::IoTeX diff --git a/src/Keystore/AESParameters.cpp b/src/Keystore/AESParameters.cpp index 146e1a12727..6aa7bfdc5b0 100644 --- a/src/Keystore/AESParameters.cpp +++ b/src/Keystore/AESParameters.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,7 +11,8 @@ #include using namespace TW; -using namespace TW::Keystore; + +namespace TW::Keystore { AESParameters::AESParameters() { iv = Data(blockSize, 0); @@ -33,3 +34,5 @@ nlohmann::json AESParameters::json() const { j[CodingKeys::iv] = hex(iv); return j; } + +} // namespace TW::Keystore diff --git a/src/Keystore/Account.cpp b/src/Keystore/Account.cpp index 05fe5e427e8..6c061ce30e7 100644 --- a/src/Keystore/Account.cpp +++ b/src/Keystore/Account.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,21 +8,21 @@ #include "../Base64.h" #include "../Coin.h" -#include "../HexCoding.h" using namespace TW; -using namespace TW::Keystore; + +namespace TW::Keystore { namespace CodingKeys { - static const auto address = "address"; - static const auto derivation = "derivation"; - static const auto derivationPath = "derivationPath"; - static const auto extendedPublicKey = "extendedPublicKey"; - static const auto indices = "indices"; - static const auto value = "value"; - static const auto hardened = "hardened"; - static const auto coin = "coin"; - static const auto publicKey = "publicKey"; +static const auto address = "address"; +static const auto derivation = "derivation"; +static const auto derivationPath = "derivationPath"; +static const auto extendedPublicKey = "extendedPublicKey"; +static const auto indices = "indices"; +static const auto value = "value"; +static const auto hardened = "hardened"; +static const auto coin = "coin"; +static const auto publicKey = "publicKey"; } // namespace CodingKeys Account::Account(const nlohmann::json& json) { @@ -80,3 +80,5 @@ nlohmann::json Account::json() const { } return j; } + +} // namespace TW::Keystore diff --git a/src/Keystore/EncryptionParameters.cpp b/src/Keystore/EncryptionParameters.cpp index 27adea5f10c..052a35b043d 100644 --- a/src/Keystore/EncryptionParameters.cpp +++ b/src/Keystore/EncryptionParameters.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,7 +7,6 @@ #include "EncryptionParameters.h" #include "../Hash.h" -#include "../HexCoding.h" #include #include @@ -17,7 +16,8 @@ #include using namespace TW; -using namespace TW::Keystore; + +namespace TW::Keystore { template static Data computeMAC(Iter begin, Iter end, const Data& key) { @@ -71,8 +71,8 @@ nlohmann::json EncryptionParameters::json() const { return j; } -EncryptedPayload::EncryptedPayload(const Data& password, const Data& data, const EncryptionParameters& params) : - params(std::move(params)), _mac() { +EncryptedPayload::EncryptedPayload(const Data& password, const Data& data, const EncryptionParameters& params) + : params(std::move(params)), _mac() { auto scryptParams = boost::get(params.kdfParams); auto derivedKey = Data(scryptParams.desiredKeyLength); scrypt(reinterpret_cast(password.data()), password.size(), scryptParams.salt.data(), @@ -104,15 +104,15 @@ Data EncryptedPayload::decrypt(const Data& password) const { auto scryptParams = boost::get(params.kdfParams); derivedKey.resize(scryptParams.defaultDesiredKeyLength); scrypt(password.data(), password.size(), scryptParams.salt.data(), - scryptParams.salt.size(), scryptParams.n, scryptParams.r, scryptParams.p, derivedKey.data(), - scryptParams.defaultDesiredKeyLength); + scryptParams.salt.size(), scryptParams.n, scryptParams.r, scryptParams.p, derivedKey.data(), + scryptParams.defaultDesiredKeyLength); mac = computeMAC(derivedKey.end() - 16, derivedKey.end(), encrypted); } else if (params.kdfParams.which() == 1) { auto pbkdf2Params = boost::get(params.kdfParams); derivedKey.resize(pbkdf2Params.defaultDesiredKeyLength); pbkdf2_hmac_sha256(password.data(), static_cast(password.size()), pbkdf2Params.salt.data(), - static_cast(pbkdf2Params.salt.size()), pbkdf2Params.iterations, derivedKey.data(), - pbkdf2Params.defaultDesiredKeyLength); + static_cast(pbkdf2Params.salt.size()), pbkdf2Params.iterations, derivedKey.data(), + pbkdf2Params.defaultDesiredKeyLength); mac = computeMAC(derivedKey.end() - 16, derivedKey.end(), encrypted); } else { throw DecryptionError::unsupportedKDF; @@ -158,3 +158,5 @@ nlohmann::json EncryptedPayload::json() const { j[CodingKeys::mac] = hex(_mac); return j; } + +} // namespace TW::Keystore diff --git a/src/Keystore/PBKDF2Parameters.cpp b/src/Keystore/PBKDF2Parameters.cpp index fef2ebe5197..d364184db07 100644 --- a/src/Keystore/PBKDF2Parameters.cpp +++ b/src/Keystore/PBKDF2Parameters.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,12 +7,13 @@ #include "PBKDF2Parameters.h" #include -#include using namespace TW; -using namespace TW::Keystore; -PBKDF2Parameters::PBKDF2Parameters() : salt(32) { +namespace TW::Keystore { + +PBKDF2Parameters::PBKDF2Parameters() + : salt(32) { random_buffer(salt.data(), salt.size()); } @@ -41,3 +42,5 @@ nlohmann::json PBKDF2Parameters::json() const { j[CodingKeys::iterations] = iterations; return j; } + +} // namespace TW::Keystore diff --git a/src/Keystore/ScryptParameters.cpp b/src/Keystore/ScryptParameters.cpp index 623cc070e61..cc32e0357a0 100644 --- a/src/Keystore/ScryptParameters.cpp +++ b/src/Keystore/ScryptParameters.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,20 +10,22 @@ #include using namespace TW; -using namespace TW::Keystore; + +namespace TW::Keystore { ScryptParameters ScryptParameters::Minimal = ScryptParameters(Data(), minimalN, defaultR, minimalP, defaultDesiredKeyLength); ScryptParameters ScryptParameters::Weak = ScryptParameters(Data(), weakN, defaultR, weakP, defaultDesiredKeyLength); ScryptParameters ScryptParameters::Standard = ScryptParameters(Data(), standardN, defaultR, standardP, defaultDesiredKeyLength); -ScryptParameters::ScryptParameters() : salt(32) { +ScryptParameters::ScryptParameters() + : salt(32) { random_buffer(salt.data(), salt.size()); } #pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" std::optional ScryptParameters::validate() const { - if (desiredKeyLength > ((1ULL << 32) - 1) * 32) { // depending on size_t size on platform, may be always false + if (desiredKeyLength > ((1ULL << 32) - 1) * 32) { // depending on size_t size on platform, may be always false return ScryptValidationError::desiredKeyLengthTooLarge; } if (static_cast(r) * static_cast(p) >= (1 << 30)) { @@ -44,12 +46,14 @@ std::optional ScryptParameters::validate() const { // ----------------- namespace CodingKeys::SP { + static const auto salt = "salt"; static const auto desiredKeyLength = "dklen"; static const auto n = "n"; static const auto p = "p"; static const auto r = "r"; -} // namespace CodingKeys + +} // namespace CodingKeys::SP ScryptParameters::ScryptParameters(const nlohmann::json& json) { salt = parse_hex(json[CodingKeys::SP::salt].get()); @@ -72,3 +76,5 @@ nlohmann::json ScryptParameters::json() const { j[CodingKeys::SP::r] = r; return j; } + +} // namespace TW::Keystore diff --git a/src/Keystore/StoredKey.cpp b/src/Keystore/StoredKey.cpp index 68124a9df72..add26c2ca26 100644 --- a/src/Keystore/StoredKey.cpp +++ b/src/Keystore/StoredKey.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -14,18 +14,17 @@ #define BOOST_UUID_RANDOM_PROVIDER_FORCE_POSIX 1 #include -#include #include #include #include #include #include -#include #include using namespace TW; -using namespace TW::Keystore; + +namespace TW::Keystore { StoredKey StoredKey::createWithMnemonic(const std::string& name, const Data& password, const std::string& mnemonic, TWStoredKeyEncryptionLevel encryptionLevel) { if (!Mnemonic::isValid(mnemonic)) { @@ -302,6 +301,7 @@ StoredKey StoredKey::createWithJson(const nlohmann::json& json) { } namespace CodingKeys::SK { + static const auto address = "address"; static const auto type = "type"; static const auto name = "name"; @@ -310,7 +310,8 @@ static const auto crypto = "crypto"; static const auto activeAccounts = "activeAccounts"; static const auto version = "version"; static const auto coin = "coin"; -} // namespace CodingKeys + +} // namespace CodingKeys::SK namespace UppercaseCodingKeys { static const auto crypto = "Crypto"; @@ -410,3 +411,5 @@ StoredKey StoredKey::load(const std::string& path) { return createWithJson(j); } + +} // namespace TW::Keystore diff --git a/src/Kusama/Entry.cpp b/src/Kusama/Entry.cpp index e7a1002934d..28e56d9bfb0 100644 --- a/src/Kusama/Entry.cpp +++ b/src/Kusama/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,17 +9,15 @@ #include "Address.h" #include "Polkadot/Signer.h" -using namespace TW::Kusama; -using namespace TW; -using namespace std; +namespace TW::Kusama { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } @@ -31,3 +29,5 @@ Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& a void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Kusama diff --git a/src/NEAR/Account.cpp b/src/NEAR/Account.cpp index bf9762fbb3c..0bb0bbf42fd 100644 --- a/src/NEAR/Account.cpp +++ b/src/NEAR/Account.cpp @@ -8,10 +8,10 @@ #include -using namespace TW; -using namespace TW::NEAR; +namespace TW::NEAR { static auto pattern = std::regex(R"(^(([a-z\d]+[\-_])*[a-z\d]+\.)*([a-z\d]+[\-_])*[a-z\d]+$)"); + bool Account::isValid(const std::string& string) { // https://docs.near.org/docs/concepts/account#account-id-rules if (string.size() < 2 || string.size() > 64) { @@ -20,3 +20,5 @@ bool Account::isValid(const std::string& string) { std::smatch match; return regex_search(string, match, pattern); } + +} // namespace TW::NEAR diff --git a/src/NEAR/Serialization.cpp b/src/NEAR/Serialization.cpp index e972e91741b..9997fc84128 100644 --- a/src/NEAR/Serialization.cpp +++ b/src/NEAR/Serialization.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,10 +9,7 @@ #include "../BinaryCoding.h" #include "../PrivateKey.h" -using namespace TW; -using namespace TW::NEAR; -using namespace TW::NEAR::Proto; - +namespace TW::NEAR { static void writeU8(Data& data, uint8_t number) { data.push_back(number); @@ -30,7 +27,8 @@ static void writeU128(Data& data, const std::string& numberData) { data.insert(std::end(data), std::begin(numberData), std::end(numberData)); } -template static void writeRawBuffer(Data& data, const T& buf) { +template +static void writeRawBuffer(Data& data, const T& buf) { data.insert(std::end(data), std::begin(buf), std::end(buf)); } @@ -81,16 +79,16 @@ static void writeFunctionCallPermission(Data& data, const Proto::FunctionCallPer static void writeAccessKey(Data& data, const Proto::AccessKey& accessKey) { writeU64(data, accessKey.nonce()); switch (accessKey.permission_case()) { - case Proto::AccessKey::kFunctionCall: - writeU8(data, 0); - writeFunctionCallPermission(data, accessKey.function_call()); - break; - case Proto::AccessKey::kFullAccess: - writeU8(data, 1); - break; - case AccessKey::PERMISSION_NOT_SET: - break; - } + case Proto::AccessKey::kFunctionCall: + writeU8(data, 0); + writeFunctionCallPermission(data, accessKey.function_call()); + break; + case Proto::AccessKey::kFullAccess: + writeU8(data, 1); + break; + case Proto::AccessKey::PERMISSION_NOT_SET: + break; + } } static void writeAddKey(Data& data, const Proto::AddKey& addKey) { @@ -109,30 +107,30 @@ static void writeDeleteAccount(Data& data, const Proto::DeleteAccount& deleteAcc static void writeAction(Data& data, const Proto::Action& action) { writeU8(data, action.payload_case() - Proto::Action::kCreateAccount); switch (action.payload_case()) { - case Proto::Action::kTransfer: - writeTransfer(data, action.transfer()); - return; - case Proto::Action::kFunctionCall: - writeFunctionCall(data, action.function_call()); - return; - case Proto::Action::kStake: - writeStake(data, action.stake()); - return; - case Proto::Action::kAddKey: - writeAddKey(data, action.add_key()); - return; - case Proto::Action::kDeleteKey: - writeDeleteKey(data, action.delete_key()); - return; - case Proto::Action::kDeleteAccount: - writeDeleteAccount(data, action.delete_account()); - return; - default: - return; + case Proto::Action::kTransfer: + writeTransfer(data, action.transfer()); + return; + case Proto::Action::kFunctionCall: + writeFunctionCall(data, action.function_call()); + return; + case Proto::Action::kStake: + writeStake(data, action.stake()); + return; + case Proto::Action::kAddKey: + writeAddKey(data, action.add_key()); + return; + case Proto::Action::kDeleteKey: + writeDeleteKey(data, action.delete_key()); + return; + case Proto::Action::kDeleteAccount: + writeDeleteAccount(data, action.delete_account()); + return; + default: + return; } } -Data TW::NEAR::transactionData(const Proto::SigningInput& input) { +Data transactionData(const Proto::SigningInput& input) { Data data; writeString(data, input.signer_id()); auto key = PrivateKey(input.private_key()); @@ -151,10 +149,12 @@ Data TW::NEAR::transactionData(const Proto::SigningInput& input) { return data; } -Data TW::NEAR::signedTransactionData(const Data& transactionData, const Data& signatureData) { +Data signedTransactionData(const Data& transactionData, const Data& signatureData) { Data data; writeRawBuffer(data, transactionData); writeU8(data, 0); writeRawBuffer(data, signatureData); return data; } + +} // namespace TW::NEAR diff --git a/src/NEAR/Signer.cpp b/src/NEAR/Signer.cpp index bdb4cf47fed..65031bce7a2 100644 --- a/src/NEAR/Signer.cpp +++ b/src/NEAR/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,8 +10,7 @@ #include "../Hash.h" #include "../PrivateKey.h" -using namespace TW; -using namespace TW::NEAR; +namespace TW::NEAR { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto transaction = transactionData(input); @@ -24,3 +23,5 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { output.set_hash(hash.data(), hash.size()); return output; } + +} // namespace TW::NEAR diff --git a/src/NEO/Entry.cpp b/src/NEO/Entry.cpp index 86e99889f30..f9e55d72637 100644 --- a/src/NEO/Entry.cpp +++ b/src/NEO/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,10 +9,11 @@ #include "Address.h" #include "Signer.h" -using namespace TW::NEO; using namespace TW; using namespace std; +namespace TW::NEO { + bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const string& address, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] TW::byte p2sh, [[maybe_unused]] const char* hrp) const { return Address::isValid(address); } @@ -33,3 +34,5 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D void Entry::plan([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { planTemplate(dataIn, dataOut); } + +} // namespace TW::NEO diff --git a/src/NEO/Signer.cpp b/src/NEO/Signer.cpp index 1449f328d7d..3329497f39f 100644 --- a/src/NEO/Signer.cpp +++ b/src/NEO/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,19 +6,15 @@ #include "Signer.h" #include "Script.h" -#include "../Hash.h" #include "../HexCoding.h" -#include "../PrivateKey.h" -#include "../PublicKey.h" -#include "../proto/NEO.pb.h" -#include "../proto/Common.pb.h" -using namespace TW; -using namespace TW::NEO; using namespace std; +using namespace TW; +namespace TW::NEO { -Signer::Signer(const PrivateKey& priKey) : privateKey(std::move(priKey)) { +Signer::Signer(const PrivateKey& priKey) + : privateKey(std::move(priKey)) { auto pub = privateKey.getPublicKey(TWPublicKeyTypeNIST256p1); publicKey = pub.bytes; address = Address(pub); @@ -224,3 +220,5 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { return output; } + +} // namespace TW::NEO diff --git a/src/NEO/Transaction.cpp b/src/NEO/Transaction.cpp index 66b88d9ef83..5108a85e581 100644 --- a/src/NEO/Transaction.cpp +++ b/src/NEO/Transaction.cpp @@ -1,28 +1,25 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include - #include "../uint256.h" -#include "../Data.h" #include "../Hash.h" #include "Transaction.h" #include "MinerTransaction.h" using namespace std; - using namespace TW; -using namespace TW::NEO; + +namespace TW::NEO { int64_t Transaction::size() const { return serialize().size(); } void Transaction::deserialize(const Data& data, int initial_pos) { - type = (TransactionType) data[initial_pos++]; + type = (TransactionType)data[initial_pos++]; version = data[initial_pos++]; initial_pos = deserializeExclusiveData(data, initial_pos); attributes.clear(); @@ -33,15 +30,15 @@ void Transaction::deserialize(const Data& data, int initial_pos) { Serializable::deserialize(outputs, data, initial_pos); } -Transaction * Transaction::deserializeFrom(const Data& data, int initial_pos) { - Transaction * resp = nullptr; - switch ((TransactionType) data[initial_pos]) { - case TransactionType::TT_MinerTransaction: - resp = new MinerTransaction(); - break; - default: - throw std::invalid_argument("Transaction::deserializeFrom Invalid transaction type"); - break; +Transaction* Transaction::deserializeFrom(const Data& data, int initial_pos) { + Transaction* resp = nullptr; + switch ((TransactionType)data[initial_pos]) { + case TransactionType::TT_MinerTransaction: + resp = new MinerTransaction(); + break; + default: + throw std::invalid_argument("Transaction::deserializeFrom Invalid transaction type"); + break; } resp->deserialize(data, initial_pos); return resp; @@ -49,27 +46,27 @@ Transaction * Transaction::deserializeFrom(const Data& data, int initial_pos) { Data Transaction::serialize() const { Data resp; - resp.push_back((byte) type); + resp.push_back((byte)type); resp.push_back(version); append(resp, serializeExclusiveData()); append(resp, Serializable::serialize(attributes)); append(resp, Serializable::serialize(inInputs)); append(resp, Serializable::serialize(outputs)); - if(witnesses.size()) - { - resp.push_back((byte) witnesses.size()); - for (const auto& witnesse : witnesses) - append(resp, witnesse.serialize()); - } + if (witnesses.size()) { + resp.push_back((byte)witnesses.size()); + for (const auto& witnesse : witnesses) + append(resp, witnesse.serialize()); + } return resp; } -bool Transaction::operator==(const Transaction &other) const { +bool Transaction::operator==(const Transaction& other) const { if (this == &other) { return true; } + // clang-format off return this->type == other.type && this->version == other.version && this->attributes.size() == other.attributes.size() @@ -78,6 +75,7 @@ bool Transaction::operator==(const Transaction &other) const { && this->attributes == other.attributes && this->inInputs == other.inInputs && this->outputs == other.outputs; + // clang-format on } Data Transaction::getHash() const { @@ -87,3 +85,5 @@ Data Transaction::getHash() const { uint256_t Transaction::getHashUInt256() const { return load(getHash()); } + +} // namespace TW::NEO diff --git a/src/Nano/Address.cpp b/src/Nano/Address.cpp index ba16435bfd6..9788472b089 100644 --- a/src/Nano/Address.cpp +++ b/src/Nano/Address.cpp @@ -1,5 +1,5 @@ // Copyright © 2019 Mart Roosmaa. -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,7 +10,7 @@ #include -using namespace TW::Nano; +namespace TW::Nano { const std::string kPrefixNano{"nano_"}; const std::string kPrefixXrb{"xrb_"}; @@ -21,14 +21,12 @@ bool Address::isValid(const std::string& address) { valid = nano_validate_address( kPrefixNano.c_str(), kPrefixNano.length(), address.c_str(), address.length(), - nullptr - ); + nullptr); if (!valid) { valid = nano_validate_address( kPrefixXrb.c_str(), kPrefixXrb.length(), address.c_str(), address.length(), - nullptr - ); + nullptr); } return valid; @@ -68,11 +66,13 @@ std::string Address::string() const { std::array out = {0}; size_t count = nano_get_address( - bytes.data(), - kPrefixNano.c_str(), kPrefixNano.length(), - out.data(), out.size()); + bytes.data(), + kPrefixNano.c_str(), kPrefixNano.length(), + out.data(), out.size()); // closing \0 assert(count < out.size()); out[count] = 0; - return std::string(out.data()); + return {out.data()}; } + +} // namespace TW::Nano diff --git a/src/Nano/Entry.cpp b/src/Nano/Entry.cpp index 2d276894700..6cfdb73e52b 100644 --- a/src/Nano/Entry.cpp +++ b/src/Nano/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,17 +9,15 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Nano; -using namespace TW; -using namespace std; +namespace TW::Nano { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } @@ -32,6 +30,8 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D signTemplate(dataIn, dataOut); } -string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { +std::string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } + +} // namespace TW::Nano diff --git a/src/Nervos/CellDep.cpp b/src/Nervos/CellDep.cpp index 9b07566d121..a9acf139ae3 100644 --- a/src/Nervos/CellDep.cpp +++ b/src/Nervos/CellDep.cpp @@ -5,11 +5,10 @@ // file LICENSE at the root of the source code distribution tree. #include "CellDep.h" -#include "Constants.h" #include "../BinaryCoding.h" -using namespace TW::Nervos; +namespace TW::Nervos { CellDep::CellDep(const Proto::CellDep& cellDep) : outPoint(cellDep.out_point()) { @@ -36,3 +35,5 @@ void CellDep::encode(Data& data) const { nlohmann::json CellDep::json() const { return nlohmann::json{{"out_point", outPoint.json()}, {"dep_type", DepTypeString[depType]}}; } + +} // namespace TW::Nervos diff --git a/src/Nervos/CellInput.cpp b/src/Nervos/CellInput.cpp index f0c6298b6f1..61810b9686b 100644 --- a/src/Nervos/CellInput.cpp +++ b/src/Nervos/CellInput.cpp @@ -7,10 +7,7 @@ #include "CellInput.h" #include "Serialization.h" -#include "../BinaryCoding.h" -#include "../HexCoding.h" - -using namespace TW::Nervos; +namespace TW::Nervos { void CellInput::encode(Data& data) const { encode64LE(since, data); @@ -21,3 +18,5 @@ nlohmann::json CellInput::json() const { return nlohmann::json{{"previous_output", previousOutput.json()}, {"since", Serialization::numberToHex(since)}}; } + +} // namespace TW::Nervos diff --git a/src/Nervos/CellOutput.cpp b/src/Nervos/CellOutput.cpp index 0af131ee645..ed1d98b86b8 100644 --- a/src/Nervos/CellOutput.cpp +++ b/src/Nervos/CellOutput.cpp @@ -7,10 +7,7 @@ #include "CellOutput.h" #include "Serialization.h" -#include "Serialization.h" -#include "../BinaryCoding.h" - -using namespace TW::Nervos; +namespace TW::Nervos { void CellOutput::encode(Data& data) const { Data capacityData; @@ -27,3 +24,5 @@ nlohmann::json CellOutput::json() const { {"lock", lock.json()}, {"type", type.json()}}; } + +} // namespace TW::Nervos diff --git a/src/Nervos/OutPoint.cpp b/src/Nervos/OutPoint.cpp index 2a04632b586..a9cfbb1599d 100644 --- a/src/Nervos/OutPoint.cpp +++ b/src/Nervos/OutPoint.cpp @@ -7,10 +7,7 @@ #include "OutPoint.h" #include "Serialization.h" -#include "../BinaryCoding.h" -#include "../HexCoding.h" - -using namespace TW::Nervos; +namespace TW::Nervos { void OutPoint::encode(Data& data) const { data.insert(data.end(), txHash.begin(), txHash.end()); @@ -21,3 +18,5 @@ nlohmann::json OutPoint::json() const { return nlohmann::json{{"tx_hash", hexEncoded(txHash)}, {"index", Serialization::numberToHex(uint64_t(index))}}; } + +} // namespace TW::Nervos \ No newline at end of file diff --git a/src/Nervos/Script.cpp b/src/Nervos/Script.cpp index d70ebb35f08..b0f688f5797 100644 --- a/src/Nervos/Script.cpp +++ b/src/Nervos/Script.cpp @@ -7,17 +7,12 @@ #include "Script.h" #include "Constants.h" #include "Serialization.h" - #include "../Bech32.h" -#include "../BinaryCoding.h" -#include "../Data.h" #include #include -#include -using namespace TW; -using namespace TW::Nervos; +namespace TW::Nervos { Data Script::hash() const { Data data; @@ -50,3 +45,5 @@ nlohmann::json Script::json() const { {"args", hexEncoded(args)}}; } } + +} // namespace TW::Nervos diff --git a/src/Nervos/Signer.cpp b/src/Nervos/Signer.cpp index 1191f6fbd0a..3a39ed1eb45 100644 --- a/src/Nervos/Signer.cpp +++ b/src/Nervos/Signer.cpp @@ -8,8 +8,7 @@ #include "Transaction.h" #include "TransactionPlan.h" -using namespace TW; -using namespace TW::Nervos; +namespace TW::Nervos { Proto::TransactionPlan Signer::plan(const Proto::SigningInput& signingInput) noexcept { TransactionPlan txPlan; @@ -52,3 +51,5 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& signingInput) noexc return output; } + +} // namespace TW::Nervos diff --git a/src/Nervos/Transaction.cpp b/src/Nervos/Transaction.cpp index 8e00e953efc..bf61915e2f8 100644 --- a/src/Nervos/Transaction.cpp +++ b/src/Nervos/Transaction.cpp @@ -7,20 +7,15 @@ #include "Transaction.h" #include "Constants.h" #include "Serialization.h" -#include "../BinaryCoding.h" -#include "../HexCoding.h" #include #include #include #include -#include -#include #include -using namespace TW; -using namespace TW::Nervos; +namespace TW::Nervos { Data Transaction::hash() const { Data data; @@ -213,3 +208,5 @@ Common::Proto::SigningError Transaction::signWitnesses(const PrivateKey& private return Common::Proto::OK; } + +} // namespace TW::Nervos diff --git a/src/Nervos/Witness.cpp b/src/Nervos/Witness.cpp index 979d06c4b0a..73a7e37fed8 100644 --- a/src/Nervos/Witness.cpp +++ b/src/Nervos/Witness.cpp @@ -6,20 +6,18 @@ #include "Witness.h" #include "Serialization.h" -#include "../BinaryCoding.h" -using namespace TW; -using namespace TW::Nervos; +namespace TW::Nervos { void Witness::encode(Data& data) const { - if ((lock.size() == 0) && (inputType.size() == 0) && (outputType.size() == 0)) { + if ((lock.empty()) && (inputType.empty()) && (outputType.empty())) { return; } std::vector dataArray; dataArray.reserve(3); for (auto&& data1 : std::vector({lock, inputType, outputType})) { Data data2; - if (data1.size() > 0) { + if (!data1.empty()) { encode32LE(uint32_t(data1.size()), data2); data2.insert(data2.end(), data1.begin(), data1.end()); } @@ -27,3 +25,5 @@ void Witness::encode(Data& data) const { } Serialization::encodeDataArray(dataArray, data); } + +} // namespace TW::Nervos diff --git a/src/Nimiq/Address.cpp b/src/Nimiq/Address.cpp index a214f586458..46b6cb3ace7 100644 --- a/src/Nimiq/Address.cpp +++ b/src/Nimiq/Address.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,16 +7,10 @@ #include "Address.h" #include "../Base32.h" -#include "../Hash.h" -#include "../HexCoding.h" #include #include -#include -#include - -using namespace TW::Nimiq; namespace TW::Nimiq { diff --git a/src/Nimiq/Address.h b/src/Nimiq/Address.h index 66acb288bad..ff60c756f9e 100644 --- a/src/Nimiq/Address.h +++ b/src/Nimiq/Address.h @@ -22,7 +22,7 @@ class Address { /// Address data consisting of a prefix byte followed by the public key /// hash. - std::array bytes; + std::array bytes{}; /// Determines whether a collection of bytes makes a valid address. static bool isValid(const std::vector& data) { return data.size() == size; } diff --git a/src/Nimiq/Entry.cpp b/src/Nimiq/Entry.cpp index 53bad71eb77..92279053f4f 100644 --- a/src/Nimiq/Entry.cpp +++ b/src/Nimiq/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,19 +9,21 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Nimiq; -using namespace std; +namespace TW::Nimiq { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Nimiq + diff --git a/src/Nimiq/Transaction.cpp b/src/Nimiq/Transaction.cpp index 4498166bad3..c7828ed73a8 100644 --- a/src/Nimiq/Transaction.cpp +++ b/src/Nimiq/Transaction.cpp @@ -8,11 +8,8 @@ #include "Signer.h" #include "../BinaryCoding.h" -#include "../HexCoding.h" -#include "../PublicKey.h" -using namespace TW; -using namespace TW::Nimiq; +namespace TW::Nimiq { const uint8_t NETWORK_ID = 42; const uint8_t EMPTY_FLAGS = 0; @@ -50,3 +47,5 @@ std::vector Transaction::getPreImage() const { return data; } + +} // namespace TW::Nimiq diff --git a/src/Ontology/Entry.cpp b/src/Ontology/Entry.cpp index 648cd7ddf9a..9f4de742362 100644 --- a/src/Ontology/Entry.cpp +++ b/src/Ontology/Entry.cpp @@ -9,19 +9,20 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Ontology; -using namespace std; +namespace TW::Ontology { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Ontology diff --git a/src/Ontology/Ong.cpp b/src/Ontology/Ong.cpp index c26d78c8ae0..e37ff4ae6a7 100644 --- a/src/Ontology/Ong.cpp +++ b/src/Ontology/Ong.cpp @@ -10,8 +10,7 @@ #include -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology { Transaction Ong::decimals(uint32_t nonce) { auto builder = ParamsBuilder(); @@ -22,7 +21,7 @@ Transaction Ong::decimals(uint32_t nonce) { return tx; } -Transaction Ong::balanceOf(const Address &address, uint32_t nonce) { +Transaction Ong::balanceOf(const Address& address, uint32_t nonce) { auto builder = ParamsBuilder(); auto invokeCode = ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "balanceOf", {address._data}); @@ -31,8 +30,8 @@ Transaction Ong::balanceOf(const Address &address, uint32_t nonce) { return tx; } -Transaction Ong::transfer(const Signer &from, const Address &to, uint64_t amount, - const Signer &payer, uint64_t gasPrice, uint64_t gasLimit, +Transaction Ong::transfer(const Signer& from, const Address& to, uint64_t amount, + const Signer& payer, uint64_t gasPrice, uint64_t gasLimit, uint32_t nonce) { NeoVmParamValue::ParamList transferParam{from.getAddress()._data, to._data, amount}; NeoVmParamValue::ParamArray args{transferParam}; @@ -45,8 +44,8 @@ Transaction Ong::transfer(const Signer &from, const Address &to, uint64_t amount return tx; } -Transaction Ong::withdraw(const Signer &claimer, const Address &receiver, uint64_t amount, - const Signer &payer, uint64_t gasPrice, uint64_t gasLimit, +Transaction Ong::withdraw(const Signer& claimer, const Address& receiver, uint64_t amount, + const Signer& payer, uint64_t gasPrice, uint64_t gasLimit, uint32_t nonce) { auto ontContract = Address("AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV"); NeoVmParamValue::ParamList args{claimer.getAddress()._data, ontContract._data, receiver._data, amount}; @@ -58,3 +57,5 @@ Transaction Ong::withdraw(const Signer &claimer, const Address &receiver, uint64 payer.addSign(tx); return tx; } + +} // namespace TW::Ontology diff --git a/src/Ontology/OngTxBuilder.cpp b/src/Ontology/OngTxBuilder.cpp index 4f9865e4304..f44d46a14b9 100644 --- a/src/Ontology/OngTxBuilder.cpp +++ b/src/Ontology/OngTxBuilder.cpp @@ -6,23 +6,22 @@ #include "OngTxBuilder.h" -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology { -Data OngTxBuilder::decimals(const Ontology::Proto::SigningInput &input) { +Data OngTxBuilder::decimals(const Ontology::Proto::SigningInput& input) { auto transaction = Ong().decimals(input.nonce()); auto encoded = transaction.serialize(); return encoded; } -Data OngTxBuilder::balanceOf(const Ontology::Proto::SigningInput &input) { +Data OngTxBuilder::balanceOf(const Ontology::Proto::SigningInput& input) { auto queryAddress = Address(input.query_address()); auto transaction = Ong().balanceOf(queryAddress, input.nonce()); auto encoded = transaction.serialize(); return encoded; } -Data OngTxBuilder::transfer(const Ontology::Proto::SigningInput &input) { +Data OngTxBuilder::transfer(const Ontology::Proto::SigningInput& input) { auto payer = Signer(PrivateKey(input.payer_private_key())); auto owner = Signer(PrivateKey(input.owner_private_key())); auto toAddress = Address(input.to_address()); @@ -32,7 +31,7 @@ Data OngTxBuilder::transfer(const Ontology::Proto::SigningInput &input) { return encoded; } -Data OngTxBuilder::withdraw(const Ontology::Proto::SigningInput &input) { +Data OngTxBuilder::withdraw(const Ontology::Proto::SigningInput& input) { auto payer = Signer(PrivateKey(input.payer_private_key())); auto owner = Signer(PrivateKey(input.owner_private_key())); auto toAddress = Address(input.to_address()); @@ -42,7 +41,7 @@ Data OngTxBuilder::withdraw(const Ontology::Proto::SigningInput &input) { return encoded; } -Data OngTxBuilder::build(const Ontology::Proto::SigningInput &input) { +Data OngTxBuilder::build(const Ontology::Proto::SigningInput& input) { auto method = std::string(input.method().begin(), input.method().end()); if (method == "transfer") { return OngTxBuilder::transfer(input); @@ -55,3 +54,5 @@ Data OngTxBuilder::build(const Ontology::Proto::SigningInput &input) { } return Data(); } + +} // namespace TW::Ontology diff --git a/src/Ontology/Ont.cpp b/src/Ontology/Ont.cpp index 3e2b784a0bb..55a9bf5f2a8 100644 --- a/src/Ontology/Ont.cpp +++ b/src/Ontology/Ont.cpp @@ -10,8 +10,7 @@ #include -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology { Transaction Ont::decimals(uint32_t nonce) { auto builder = ParamsBuilder(); @@ -22,7 +21,7 @@ Transaction Ont::decimals(uint32_t nonce) { return tx; } -Transaction Ont::balanceOf(const Address &address, uint32_t nonce) { +Transaction Ont::balanceOf(const Address& address, uint32_t nonce) { auto builder = ParamsBuilder(); auto invokeCode = ParamsBuilder::buildNativeInvokeCode(contractAddress(), version, "balanceOf", {address._data}); @@ -31,8 +30,8 @@ Transaction Ont::balanceOf(const Address &address, uint32_t nonce) { return tx; } -Transaction Ont::transfer(const Signer &from, const Address &to, uint64_t amount, - const Signer &payer, uint64_t gasPrice, uint64_t gasLimit, +Transaction Ont::transfer(const Signer& from, const Address& to, uint64_t amount, + const Signer& payer, uint64_t gasPrice, uint64_t gasLimit, uint32_t nonce) { NeoVmParamValue::ParamList transferParam{from.getAddress()._data, to._data, amount}; NeoVmParamValue::ParamArray args{transferParam}; @@ -44,3 +43,5 @@ Transaction Ont::transfer(const Signer &from, const Address &to, uint64_t amount payer.addSign(tx); return tx; } + +} // namespace TW::Ontology diff --git a/src/Ontology/OntTxBuilder.cpp b/src/Ontology/OntTxBuilder.cpp index d96a33317d5..735681c14fc 100644 --- a/src/Ontology/OntTxBuilder.cpp +++ b/src/Ontology/OntTxBuilder.cpp @@ -6,23 +6,22 @@ #include "OntTxBuilder.h" -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology { -Data OntTxBuilder::decimals(const Ontology::Proto::SigningInput &input) { +Data OntTxBuilder::decimals(const Ontology::Proto::SigningInput& input) { auto transaction = Ont().decimals(input.nonce()); auto encoded = transaction.serialize(); return encoded; } -Data OntTxBuilder::balanceOf(const Ontology::Proto::SigningInput &input) { +Data OntTxBuilder::balanceOf(const Ontology::Proto::SigningInput& input) { auto queryAddress = Address(input.query_address()); auto transaction = Ont().balanceOf(queryAddress, input.nonce()); auto encoded = transaction.serialize(); return encoded; } -Data OntTxBuilder::transfer(const Ontology::Proto::SigningInput &input) { +Data OntTxBuilder::transfer(const Ontology::Proto::SigningInput& input) { auto payerSigner = Signer(PrivateKey(input.payer_private_key())); auto fromSigner = Signer(PrivateKey(input.owner_private_key())); auto toAddress = Address(input.to_address()); @@ -32,7 +31,7 @@ Data OntTxBuilder::transfer(const Ontology::Proto::SigningInput &input) { return encoded; } -Data OntTxBuilder::build(const Ontology::Proto::SigningInput &input) { +Data OntTxBuilder::build(const Ontology::Proto::SigningInput& input) { auto method = std::string(input.method().begin(), input.method().end()); if (method == "transfer") { return OntTxBuilder::transfer(input); @@ -43,3 +42,5 @@ Data OntTxBuilder::build(const Ontology::Proto::SigningInput &input) { } return Data(); } + +} // namespace TW::Ontology diff --git a/src/Ontology/ParamsBuilder.cpp b/src/Ontology/ParamsBuilder.cpp index 300578a0101..c4db460cfb7 100644 --- a/src/Ontology/ParamsBuilder.cpp +++ b/src/Ontology/ParamsBuilder.cpp @@ -15,8 +15,7 @@ #include #include -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology { void ParamsBuilder::buildNeoVmParam(ParamsBuilder& builder, const NeoVmParamValue& param) { @@ -251,3 +250,5 @@ Data ParamsBuilder::buildOep4InvokeCode(const Address& contractAddress, const st return builder.getBytes(); } + +} // namespace TW::Ontology diff --git a/src/Ontology/SigData.cpp b/src/Ontology/SigData.cpp index 782f6dda84b..857504de0e2 100644 --- a/src/Ontology/SigData.cpp +++ b/src/Ontology/SigData.cpp @@ -9,8 +9,7 @@ #include "ParamsBuilder.h" #include "SigData.h" -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology { Data SigData::serialize() { auto sigInfo = ParamsBuilder::fromSigs(sigs); @@ -28,3 +27,5 @@ Data SigData::serialize() { builder.pushVar(verifyInfo); return builder.getBytes(); } + +} // namespace TW::Ontology diff --git a/src/Ontology/Signer.cpp b/src/Ontology/Signer.cpp index 50bceecd6b9..876b97bf9c7 100644 --- a/src/Ontology/Signer.cpp +++ b/src/Ontology/Signer.cpp @@ -5,14 +5,14 @@ // file LICENSE at the root of the source code distribution tree. #include "Signer.h" + #include "HexCoding.h" #include "SigData.h" #include "../Ontology/Oep4TxBuilder.h" + #include "../Ontology/OngTxBuilder.h" #include "../Ontology/OntTxBuilder.h" -#include "../Hash.h" - #include namespace TW::Ontology { diff --git a/src/Ontology/Transaction.cpp b/src/Ontology/Transaction.cpp index e5c8cc30a15..7bf47d716f4 100644 --- a/src/Ontology/Transaction.cpp +++ b/src/Ontology/Transaction.cpp @@ -8,13 +8,9 @@ #include "Address.h" #include "ParamsBuilder.h" -#include "../Hash.h" -#include "../HexCoding.h" - #include -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology { const std::string Transaction::ZERO_PAYER = "AFmseVrdL9f9oyCzZefL9tG6UbvhPbdYzM"; @@ -58,3 +54,5 @@ std::vector Transaction::serialize(const PublicKey& pk) { builder.pushBack((uint8_t)0xAC); return builder.getBytes(); } + +} // namespace TW::Ontology diff --git a/src/Polkadot/Entry.cpp b/src/Polkadot/Entry.cpp index 6e1185489d5..f97ae843ca9 100644 --- a/src/Polkadot/Entry.cpp +++ b/src/Polkadot/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,17 +9,15 @@ #include "Address.h" #include "Signer.h" -using namespace TW::Polkadot; -using namespace TW; -using namespace std; +namespace TW::Polkadot { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } @@ -31,3 +29,5 @@ Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& a void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Polkadot diff --git a/src/Polkadot/Extrinsic.cpp b/src/Polkadot/Extrinsic.cpp index be841581e93..6ce75c13c8d 100644 --- a/src/Polkadot/Extrinsic.cpp +++ b/src/Polkadot/Extrinsic.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,8 +8,7 @@ #include #include -using namespace TW; -using namespace TW::Polkadot; +namespace TW::Polkadot { static constexpr uint8_t signedBit = 0x80; static constexpr uint8_t sigTypeEd25519 = 0x00; @@ -260,3 +259,5 @@ Data Extrinsic::encodeSignature(const PublicKey& signer, const Data& signature) encodeLengthPrefix(data); return data; } + +} // namespace TW::Polkadot diff --git a/src/Ripple/Address.cpp b/src/Ripple/Address.cpp index bd139a932cb..2ff0026deba 100644 --- a/src/Ripple/Address.cpp +++ b/src/Ripple/Address.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,8 +8,6 @@ #include "../Base58.h" #include -using namespace TW::Ripple; - namespace TW::Ripple { bool Address::isValid(const std::string& string) { diff --git a/src/Ripple/Entry.cpp b/src/Ripple/Entry.cpp index 668154d70d8..b28a843c670 100644 --- a/src/Ripple/Entry.cpp +++ b/src/Ripple/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,19 +10,20 @@ #include "XAddress.h" #include "Signer.h" -using namespace TW::Ripple; -using namespace std; +namespace TW::Ripple { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { return Address::isValid(address) || XAddress::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { return Address(publicKey).string(); } void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } + +} // namespace TW::Ripple diff --git a/src/Ripple/Signer.cpp b/src/Ripple/Signer.cpp index e19a385e098..52237c2fdba 100644 --- a/src/Ripple/Signer.cpp +++ b/src/Ripple/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,11 +6,9 @@ #include "Signer.h" #include "../BinaryCoding.h" -#include "../Hash.h" #include -using namespace TW; -using namespace TW::Ripple; +namespace TW::Ripple { static const int64_t fullyCanonical = 0x80000000; @@ -25,15 +23,14 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); auto transaction = Transaction( - /* amount */input.amount(), - /* fee */input.fee(), - /* flags */input.flags(), - /* sequence */input.sequence(), - /* last_ledger_sequence */input.last_ledger_sequence(), - /* account */Address(input.account()), - /* destination */input.destination(), - /* destination_tag*/tag - ); + /* amount */ input.amount(), + /* fee */ input.fee(), + /* flags */ input.flags(), + /* sequence */ input.sequence(), + /* last_ledger_sequence */ input.last_ledger_sequence(), + /* account */ Address(input.account()), + /* destination */ input.destination(), + /* destination_tag*/ tag); auto signer = Signer(); signer.sign(key, transaction); @@ -54,3 +51,5 @@ void Signer::sign(const PrivateKey& privateKey, Transaction& transaction) const transaction.signature = privateKey.signAsDER(half); } + +} // namespace TW::Ripple diff --git a/src/Ripple/Transaction.cpp b/src/Ripple/Transaction.cpp index 112e3721358..00846a905c7 100644 --- a/src/Ripple/Transaction.cpp +++ b/src/Ripple/Transaction.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,12 +7,10 @@ #include "BinaryCoding.h" #include "Transaction.h" #include "../BinaryCoding.h" -#include "../HexCoding.h" #include -using namespace TW; -using namespace TW::Ripple; +namespace TW::Ripple { const int NETWORK_PREFIX = 0x53545800; @@ -85,8 +83,8 @@ Data Transaction::serializeAmount(int64_t amount) { Data Transaction::serializeAddress(Address address) { auto data = Data(20); - if (!address.bytes.empty()) { - std::copy(&address.bytes[0] + 1, &address.bytes[0] + std::min(address.bytes.size(), size_t(21)), &data[0]); - } + std::copy(&address.bytes[0] + 1, &address.bytes[0] + std::min(address.bytes.size(), size_t(21)), &data[0]); return data; } + +} // namespace TW::Ripple diff --git a/src/Ripple/XAddress.cpp b/src/Ripple/XAddress.cpp index b6f522d7319..0eb5e6978f8 100644 --- a/src/Ripple/XAddress.cpp +++ b/src/Ripple/XAddress.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,12 +7,10 @@ #include "XAddress.h" #include "../Base58.h" -#include "../BinaryCoding.h" -#include "../Data.h" +#include "../BinaryCoding.h" #include -using namespace TW; -using namespace TW::Ripple; +namespace TW::Ripple { const Data prefixMainnet = {0x05, 0x44}; @@ -21,7 +19,7 @@ bool XAddress::isValid(const std::string& string) { if (decoded.size() != XAddress::size) { return false; } - if(!std::equal(decoded.begin(), decoded.begin() + 2, prefixMainnet.begin())) { + if (!std::equal(decoded.begin(), decoded.begin() + 2, prefixMainnet.begin())) { return false; } if (!(decoded[22] == byte(TagFlag::none) || decoded[22] == byte(TagFlag::classic))) { @@ -45,12 +43,13 @@ XAddress::XAddress(const std::string& string) { } } -XAddress::XAddress(const PublicKey& publicKey, const uint32_t destination): tag(destination) { +XAddress::XAddress(const PublicKey& publicKey, const uint32_t destination) + : tag(destination) { ecdsa_get_pubkeyhash(publicKey.bytes.data(), HASHER_SHA2_RIPEMD, bytes.data()); } std::string XAddress::string() const { - /// see https://github.com/ripple/ripple-address-codec/blob/master/src/index.ts + /// \see https://github.com/ripple/ripple-address-codec/blob/master/src/index.ts /// base58check(2 bytes prefix + 20 bytes keyhash + 1 byte flag + 4 bytes + 32bit tag + 4 bytes reserved) Data result; append(result, prefixMainnet); @@ -60,3 +59,5 @@ std::string XAddress::string() const { append(result, Data{0x00, 0x00, 0x00, 0x00}); return Base58::ripple.encodeCheck(result); } + +} // namespace TW::Ripple diff --git a/src/Solana/Program.cpp b/src/Solana/Program.cpp index 0c54f1839d1..bac0340caa8 100644 --- a/src/Solana/Program.cpp +++ b/src/Solana/Program.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,19 +7,13 @@ #include "Program.h" #include "Address.h" #include "Transaction.h" -#include "../Base58.h" -#include "../Hash.h" - -#include #include -#include -using namespace TW; -using namespace TW::Solana; +namespace TW::Solana { Address StakeProgram::addressFromValidatorSeed(const Address& fromAddress, const Address& validatorAddress, - const Address& programId) { + const Address& programId) { Data extended = fromAddress.vector(); std::string seed = validatorAddress.string(); Data vecSeed(seed.begin(), seed.end()); @@ -53,8 +47,7 @@ Address TokenProgram::defaultTokenAddress(const Address& mainAddress, const Addr std::vector seeds = { TW::data(mainAddress.bytes.data(), mainAddress.bytes.size()), TW::data(programId.bytes.data(), programId.bytes.size()), - TW::data(tokenMintAddress.bytes.data(), tokenMintAddress.bytes.size()) - }; + TW::data(tokenMintAddress.bytes.data(), tokenMintAddress.bytes.size())}; return findProgramAddress(seeds, Address(ASSOCIATED_TOKEN_PROGRAM_ID_ADDRESS)); } @@ -87,7 +80,7 @@ Address TokenProgram::findProgramAddress(const std::vector& seeds, [[m Address TokenProgram::createProgramAddress(const std::vector& seeds, const Address& programId) { // concatenate seeds Data hashInput; - for (auto& seed: seeds) { + for (auto& seed : seeds) { append(hashInput, seed); } // append programId @@ -97,3 +90,6 @@ Address TokenProgram::createProgramAddress(const std::vector& seeds, c Data hash = TW::Hash::sha256(hashInput.data(), hashInput.size()); return Address(hash); } + +} // namespace TW::Solana + diff --git a/src/Solana/Signer.cpp b/src/Solana/Signer.cpp index c5a4166fb6d..f5839bc0e8f 100644 --- a/src/Solana/Signer.cpp +++ b/src/Solana/Signer.cpp @@ -7,16 +7,12 @@ #include "Signer.h" #include "Address.h" #include "Program.h" -#include "../Base58.h" -#include #include -#include #include -using namespace TW; -using namespace TW::Solana; +namespace TW::Solana { void Signer::sign(const std::vector& privateKeys, Transaction& transaction) { for (auto privateKey : privateKeys) { @@ -46,147 +42,128 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { std::vector signerKeys; switch (input.transaction_type_case()) { - case Proto::SigningInput::TransactionTypeCase::kTransferTransaction: - { - auto protoMessage = input.transfer_transaction(); - message = Message::createTransfer( - /* from */ Address(key.getPublicKey(TWPublicKeyTypeED25519)), - /* to */ Address(protoMessage.recipient()), - /* value */ protoMessage.value(), - /* recent_blockhash */ blockhash, - /* memo */ protoMessage.memo(), - convertReferences(protoMessage.references())); - signerKeys.push_back(key); - } - break; - - case Proto::SigningInput::TransactionTypeCase::kDelegateStakeTransaction: - { - auto protoMessage = input.delegate_stake_transaction(); - auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); - auto validatorAddress = Address(protoMessage.validator_pubkey()); - auto stakeProgramId = Address(STAKE_PROGRAM_ID_ADDRESS); - std::optional
stakeAddress; - if (protoMessage.stake_account().size() == 0) { - // no stake address specified, generate a new unique - stakeAddress = StakeProgram::addressFromRecentBlockhash(userAddress, blockhash, stakeProgramId); - } else { - // stake address specified, use it - stakeAddress = Address(protoMessage.stake_account()); - } - message = Message::createStake( - /* signer */ userAddress, - /* stakeAddress */ stakeAddress.value(), - /* voteAddress */ validatorAddress, - /* value */ protoMessage.value(), - /* recent_blockhash */ blockhash); - signerKeys.push_back(key); - } - break; - - case Proto::SigningInput::TransactionTypeCase::kDeactivateStakeTransaction: - { - auto protoMessage = input.deactivate_stake_transaction(); - auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); - auto stakeAddress = Address(protoMessage.stake_account()); - message = Message::createStakeDeactivate( - /* signer */ userAddress, - /* stakeAddress */ stakeAddress, - /* recent_blockhash */ blockhash); - signerKeys.push_back(key); - } - break; - - case Proto::SigningInput::TransactionTypeCase::kDeactivateAllStakeTransaction: - { - auto protoMessage = input.deactivate_all_stake_transaction(); - auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); - std::vector
addresses; - for (auto i = 0; i < protoMessage.stake_accounts_size(); ++i) { - addresses.emplace_back(Address(protoMessage.stake_accounts(i))); - } - message = Message::createStakeDeactivateAll(userAddress, addresses, blockhash); - signerKeys.push_back(key); - } - break; - - case Proto::SigningInput::TransactionTypeCase::kWithdrawTransaction: - { - auto protoMessage = input.withdraw_transaction(); - auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); - auto stakeAddress = Address(protoMessage.stake_account()); - message = Message::createStakeWithdraw( - /* signer */ userAddress, - /* stakeAddress */ stakeAddress, - /* value */ protoMessage.value(), - /* recent_blockhash */ blockhash); - signerKeys.push_back(key); - } - break; - - case Proto::SigningInput::TransactionTypeCase::kWithdrawAllTransaction: - { - auto protoMessage = input.withdraw_all_transaction(); - auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); - std::vector> stakes; - for (auto i = 0; i < protoMessage.stake_accounts_size(); ++i) { - stakes.push_back(std::make_pair( - Address(protoMessage.stake_accounts(i).stake_account()), - protoMessage.stake_accounts(i).value() - )); - } - message = Message::createStakeWithdrawAll(userAddress, stakes, blockhash); - signerKeys.push_back(key); - } - break; - - case Proto::SigningInput::TransactionTypeCase::kCreateTokenAccountTransaction: - { - auto protoMessage = input.create_token_account_transaction(); - auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); - auto mainAddress = Address(protoMessage.main_address()); - auto tokenMintAddress = Address(protoMessage.token_mint_address()); - auto tokenAddress = Address(protoMessage.token_address()); - message = Message::createTokenCreateAccount(userAddress, mainAddress, tokenMintAddress, tokenAddress, blockhash); - signerKeys.push_back(key); - } - break; - - case Proto::SigningInput::TransactionTypeCase::kTokenTransferTransaction: - { - auto protoMessage = input.token_transfer_transaction(); - auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); - auto tokenMintAddress = Address(protoMessage.token_mint_address()); - auto senderTokenAddress = Address(protoMessage.sender_token_address()); - auto recipientTokenAddress = Address(protoMessage.recipient_token_address()); - auto amount = protoMessage.amount(); - auto decimals = static_cast(protoMessage.decimals()); - const auto memo = protoMessage.memo(); - message = Message::createTokenTransfer(userAddress, tokenMintAddress, senderTokenAddress, recipientTokenAddress, amount, decimals, blockhash, - memo, convertReferences(protoMessage.references())); - signerKeys.push_back(key); - } - break; - - case Proto::SigningInput::TransactionTypeCase::kCreateAndTransferTokenTransaction: - { - auto protoMessage = input.create_and_transfer_token_transaction(); - auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); - auto recipientMainAddress = Address(protoMessage.recipient_main_address()); - auto tokenMintAddress = Address(protoMessage.token_mint_address()); - auto recipientTokenAddress = Address(protoMessage.recipient_token_address()); - auto senderTokenAddress = Address(protoMessage.sender_token_address()); - auto amount = protoMessage.amount(); - auto decimals = static_cast(protoMessage.decimals()); - const auto memo = protoMessage.memo(); - message = Message::createTokenCreateAndTransfer(userAddress, recipientMainAddress, tokenMintAddress, recipientTokenAddress, senderTokenAddress, amount, decimals, blockhash, - memo, convertReferences(protoMessage.references())); - signerKeys.push_back(key); - } - break; - - default: - assert(input.transaction_type_case() != Proto::SigningInput::TransactionTypeCase::TRANSACTION_TYPE_NOT_SET); + case Proto::SigningInput::TransactionTypeCase::kTransferTransaction: { + auto protoMessage = input.transfer_transaction(); + message = Message::createTransfer( + /* from */ Address(key.getPublicKey(TWPublicKeyTypeED25519)), + /* to */ Address(protoMessage.recipient()), + /* value */ protoMessage.value(), + /* recent_blockhash */ blockhash, + /* memo */ protoMessage.memo(), + convertReferences(protoMessage.references())); + signerKeys.push_back(key); + } break; + + case Proto::SigningInput::TransactionTypeCase::kDelegateStakeTransaction: { + auto protoMessage = input.delegate_stake_transaction(); + auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); + auto validatorAddress = Address(protoMessage.validator_pubkey()); + auto stakeProgramId = Address(STAKE_PROGRAM_ID_ADDRESS); + std::optional
stakeAddress; + if (protoMessage.stake_account().size() == 0) { + // no stake address specified, generate a new unique + stakeAddress = StakeProgram::addressFromRecentBlockhash(userAddress, blockhash, stakeProgramId); + } else { + // stake address specified, use it + stakeAddress = Address(protoMessage.stake_account()); + } + message = Message::createStake( + /* signer */ userAddress, + /* stakeAddress */ stakeAddress.value(), + /* voteAddress */ validatorAddress, + /* value */ protoMessage.value(), + /* recent_blockhash */ blockhash); + signerKeys.push_back(key); + } break; + + case Proto::SigningInput::TransactionTypeCase::kDeactivateStakeTransaction: { + auto protoMessage = input.deactivate_stake_transaction(); + auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); + auto stakeAddress = Address(protoMessage.stake_account()); + message = Message::createStakeDeactivate( + /* signer */ userAddress, + /* stakeAddress */ stakeAddress, + /* recent_blockhash */ blockhash); + signerKeys.push_back(key); + } break; + + case Proto::SigningInput::TransactionTypeCase::kDeactivateAllStakeTransaction: { + auto protoMessage = input.deactivate_all_stake_transaction(); + auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); + std::vector
addresses; + for (auto i = 0; i < protoMessage.stake_accounts_size(); ++i) { + addresses.emplace_back(Address(protoMessage.stake_accounts(i))); + } + message = Message::createStakeDeactivateAll(userAddress, addresses, blockhash); + signerKeys.push_back(key); + } break; + + case Proto::SigningInput::TransactionTypeCase::kWithdrawTransaction: { + auto protoMessage = input.withdraw_transaction(); + auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); + auto stakeAddress = Address(protoMessage.stake_account()); + message = Message::createStakeWithdraw( + /* signer */ userAddress, + /* stakeAddress */ stakeAddress, + /* value */ protoMessage.value(), + /* recent_blockhash */ blockhash); + signerKeys.push_back(key); + } break; + + case Proto::SigningInput::TransactionTypeCase::kWithdrawAllTransaction: { + auto protoMessage = input.withdraw_all_transaction(); + auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); + std::vector> stakes; + for (auto i = 0; i < protoMessage.stake_accounts_size(); ++i) { + stakes.push_back(std::make_pair( + Address(protoMessage.stake_accounts(i).stake_account()), + protoMessage.stake_accounts(i).value())); + } + message = Message::createStakeWithdrawAll(userAddress, stakes, blockhash); + signerKeys.push_back(key); + } break; + + case Proto::SigningInput::TransactionTypeCase::kCreateTokenAccountTransaction: { + auto protoMessage = input.create_token_account_transaction(); + auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); + auto mainAddress = Address(protoMessage.main_address()); + auto tokenMintAddress = Address(protoMessage.token_mint_address()); + auto tokenAddress = Address(protoMessage.token_address()); + message = Message::createTokenCreateAccount(userAddress, mainAddress, tokenMintAddress, tokenAddress, blockhash); + signerKeys.push_back(key); + } break; + + case Proto::SigningInput::TransactionTypeCase::kTokenTransferTransaction: { + auto protoMessage = input.token_transfer_transaction(); + auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); + auto tokenMintAddress = Address(protoMessage.token_mint_address()); + auto senderTokenAddress = Address(protoMessage.sender_token_address()); + auto recipientTokenAddress = Address(protoMessage.recipient_token_address()); + auto amount = protoMessage.amount(); + auto decimals = static_cast(protoMessage.decimals()); + const auto memo = protoMessage.memo(); + message = Message::createTokenTransfer(userAddress, tokenMintAddress, senderTokenAddress, recipientTokenAddress, amount, decimals, blockhash, + memo, convertReferences(protoMessage.references())); + signerKeys.push_back(key); + } break; + + case Proto::SigningInput::TransactionTypeCase::kCreateAndTransferTokenTransaction: { + auto protoMessage = input.create_and_transfer_token_transaction(); + auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); + auto recipientMainAddress = Address(protoMessage.recipient_main_address()); + auto tokenMintAddress = Address(protoMessage.token_mint_address()); + auto recipientTokenAddress = Address(protoMessage.recipient_token_address()); + auto senderTokenAddress = Address(protoMessage.sender_token_address()); + auto amount = protoMessage.amount(); + auto decimals = static_cast(protoMessage.decimals()); + const auto memo = protoMessage.memo(); + message = Message::createTokenCreateAndTransfer(userAddress, recipientMainAddress, tokenMintAddress, recipientTokenAddress, senderTokenAddress, amount, decimals, blockhash, + memo, convertReferences(protoMessage.references())); + signerKeys.push_back(key); + } break; + + default: + assert(input.transaction_type_case() != Proto::SigningInput::TransactionTypeCase::TRANSACTION_TYPE_NOT_SET); } auto transaction = Transaction(message); @@ -230,3 +207,5 @@ std::string Signer::signJSON(const std::string& json, const Data& key) { input.set_private_key(key.data(), key.size()); return Signer::sign(input).encoded(); } + +} // namespace TW::Solana diff --git a/src/Solana/Transaction.cpp b/src/Solana/Transaction.cpp index dd5dc5c0c05..ac345134dc6 100644 --- a/src/Solana/Transaction.cpp +++ b/src/Solana/Transaction.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,14 +8,10 @@ #include "Hash.h" #include "Signer.h" -#include "../BinaryCoding.h" -#include "../PublicKey.h" #include -using namespace TW; -using namespace TW::Solana; -using namespace std; +namespace TW::Solana { uint8_t CompiledInstruction::findAccount(const Address& address) { auto it = std::find(addresses.begin(), addresses.end(), address); @@ -54,31 +50,30 @@ void Message::addAccountKeys(const Address& account) { } void Message::compileAccounts() { - for (auto& instr: instructions) { - for (auto& address: instr.accounts) { + for (auto& instr : instructions) { + for (auto& address : instr.accounts) { addAccount(address); } } // add programIds (read-only, at end) - for (auto& instr: instructions) { + for (auto& instr : instructions) { addAccount(AccountMeta{instr.programId, false, true}); } header = MessageHeader{ (uint8_t)signedAccounts.size(), 0, - (uint8_t)readOnlyAccounts.size() - }; + (uint8_t)readOnlyAccounts.size()}; // merge the three buckets accountKeys.clear(); - for(auto& a: signedAccounts) { + for (auto& a : signedAccounts) { addAccountKeys(a); } - for(auto& a: unsignedAccounts) { + for (auto& a : unsignedAccounts) { addAccountKeys(a); } - for(auto& a: readOnlyAccounts) { + for (auto& a : readOnlyAccounts) { addAccountKeys(a); } @@ -87,7 +82,7 @@ void Message::compileAccounts() { void Message::compileInstructions() { compiledInstructions.clear(); - for (auto instruction: instructions) { + for (auto instruction : instructions) { compiledInstructions.emplace_back(CompiledInstruction(instruction, accountKeys)); } } @@ -145,3 +140,5 @@ uint8_t Transaction::getAccountIndex(Address publicKey) { bool Signature::operator==(const Signature& v) const { return bytes == v.bytes; } + +} // namespace TW::Solana diff --git a/src/THORChain/TWSwap.cpp b/src/THORChain/TWSwap.cpp index a13b7823d92..9f1341c50fe 100644 --- a/src/THORChain/TWSwap.cpp +++ b/src/THORChain/TWSwap.cpp @@ -1,33 +1,32 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include +#include "Data.h" #include "Swap.h" #include "proto/THORChainSwap.pb.h" -#include "Data.h" +#include -using namespace TW::THORChainSwap; using namespace TW; -TWData *_Nonnull TWTHORChainSwapBuildSwap(TWData *_Nonnull input) { - Proto::SwapInput inputProto; - Proto::SwapOutput outputProto; +TWData* _Nonnull TWTHORChainSwapBuildSwap(TWData* _Nonnull input) { + THORChainSwap::Proto::SwapInput inputProto; + THORChainSwap::Proto::SwapOutput outputProto; if (!inputProto.ParseFromArray(TWDataBytes(input), static_cast(TWDataSize(input)))) { // error - outputProto.mutable_error()->set_code(Proto::ErrorCode::Error_Input_proto_deserialization); + outputProto.mutable_error()->set_code(THORChainSwap::Proto::ErrorCode::Error_Input_proto_deserialization); outputProto.mutable_error()->set_message("Could not deserialize input proto"); - auto outputData = data(outputProto.SerializeAsString()); + auto outputData = TW::data(outputProto.SerializeAsString()); return TWDataCreateWithBytes(outputData.data(), outputData.size()); } const auto fromChain = inputProto.from_chain(); const auto toChain = inputProto.to_asset().chain(); - auto res = Swap::build( - static_cast(static_cast(fromChain)), - static_cast(static_cast(toChain)), + auto res = THORChainSwap::Swap::build( + static_cast(static_cast(fromChain)), + static_cast(static_cast(toChain)), inputProto.from_address(), inputProto.to_asset().symbol(), inputProto.to_asset().token_id(), @@ -35,66 +34,59 @@ TWData *_Nonnull TWTHORChainSwapBuildSwap(TWData *_Nonnull input) { inputProto.vault_address(), inputProto.router_address(), inputProto.from_amount(), - inputProto.to_amount_limit() - ); + inputProto.to_amount_limit()); outputProto.set_from_chain(fromChain); outputProto.set_to_chain(toChain); if (std::get<1>(res) != 0) { // error - outputProto.mutable_error()->set_code(static_cast(std::get<1>(res))); + outputProto.mutable_error()->set_code(static_cast(std::get<1>(res))); outputProto.mutable_error()->set_message(std::get<2>(res)); } else { // no error - outputProto.mutable_error()->set_code(Proto::ErrorCode::OK); + outputProto.mutable_error()->set_code(THORChainSwap::Proto::ErrorCode::OK); outputProto.mutable_error()->set_message(""); const Data& txInput = std::get<0>(res); switch (fromChain) { - case Proto::BTC: - { - Bitcoin::Proto::SigningInput btcInput; - if (!btcInput.ParseFromArray(txInput.data(), static_cast(txInput.size()))) { - outputProto.mutable_error()->set_code(Proto::ErrorCode::Error_Input_proto_deserialization); - outputProto.mutable_error()->set_message("Could not deserialize BTC input"); - } else { - *outputProto.mutable_bitcoin() = btcInput; - } - } - break; + case THORChainSwap::Proto::BTC: { + Bitcoin::Proto::SigningInput btcInput; + if (!btcInput.ParseFromArray(txInput.data(), static_cast(txInput.size()))) { + outputProto.mutable_error()->set_code(THORChainSwap::Proto::ErrorCode::Error_Input_proto_deserialization); + outputProto.mutable_error()->set_message("Could not deserialize BTC input"); + } else { + *outputProto.mutable_bitcoin() = btcInput; + } + } break; - case Proto::ETH: - { - Ethereum::Proto::SigningInput ethInput; - if (!ethInput.ParseFromArray(txInput.data(), static_cast(txInput.size()))) { - outputProto.mutable_error()->set_code(Proto::ErrorCode::Error_Input_proto_deserialization); - outputProto.mutable_error()->set_message("Could not deserialize ETH input"); - } else { - *outputProto.mutable_ethereum() = ethInput; - } - } - break; + case THORChainSwap::Proto::ETH: { + Ethereum::Proto::SigningInput ethInput; + if (!ethInput.ParseFromArray(txInput.data(), static_cast(txInput.size()))) { + outputProto.mutable_error()->set_code(THORChainSwap::Proto::ErrorCode::Error_Input_proto_deserialization); + outputProto.mutable_error()->set_message("Could not deserialize ETH input"); + } else { + *outputProto.mutable_ethereum() = ethInput; + } + } break; - case Proto::BNB: - { - Binance::Proto::SigningInput bnbInput; - if (!bnbInput.ParseFromArray(txInput.data(), static_cast(txInput.size()))) { - outputProto.mutable_error()->set_code(Proto::ErrorCode::Error_Input_proto_deserialization); - outputProto.mutable_error()->set_message("Could not deserialize BNB input"); - } else { - *outputProto.mutable_binance() = bnbInput; - } - } - break; + case THORChainSwap::Proto::BNB: { + Binance::Proto::SigningInput bnbInput; + if (!bnbInput.ParseFromArray(txInput.data(), static_cast(txInput.size()))) { + outputProto.mutable_error()->set_code(THORChainSwap::Proto::ErrorCode::Error_Input_proto_deserialization); + outputProto.mutable_error()->set_message("Could not deserialize BNB input"); + } else { + *outputProto.mutable_binance() = bnbInput; + } + } break; - default: - outputProto.mutable_error()->set_code(Proto::ErrorCode::Error_Unsupported_from_chain); - outputProto.mutable_error()->set_message(std::string("Unsupported from chain ") + std::to_string(fromChain)); - break; + default: + outputProto.mutable_error()->set_code(THORChainSwap::Proto::ErrorCode::Error_Unsupported_from_chain); + outputProto.mutable_error()->set_message(std::string("Unsupported from chain ") + std::to_string(fromChain)); + break; } } // serialize output - auto outputData = data(outputProto.SerializeAsString()); + auto outputData = TW::data(outputProto.SerializeAsString()); return TWDataCreateWithBytes(outputData.data(), outputData.size()); } diff --git a/src/Tezos/Forging.cpp b/src/Tezos/Forging.cpp index 7d2cc57f7ce..83088b3f3c0 100644 --- a/src/Tezos/Forging.cpp +++ b/src/Tezos/Forging.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,14 +7,11 @@ #include "Forging.h" #include "Address.h" #include "BinaryCoding.h" -#include "../Base58.h" -#include "../Data.h" #include "../HexCoding.h" #include "../proto/Tezos.pb.h" - #include -using namespace TW; +namespace TW::Tezos { namespace { @@ -28,8 +25,6 @@ void encodePrefix(const std::string& address, Data& forged) { } // namespace -namespace TW::Tezos { - // Forge the given boolean into a hex encoded string. Data forgeBool(bool input) { unsigned char result = input ? 0xff : 0x00; diff --git a/src/Tezos/Forging.h b/src/Tezos/Forging.h index 818ffce744a..721546db1e9 100644 --- a/src/Tezos/Forging.h +++ b/src/Tezos/Forging.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Tezos/OperationList.cpp b/src/Tezos/OperationList.cpp index 72fbb82ca57..fc2e7ed3897 100644 --- a/src/Tezos/OperationList.cpp +++ b/src/Tezos/OperationList.cpp @@ -5,15 +5,10 @@ // file LICENSE at the root of the source code distribution tree. #include "OperationList.h" -#include "BinaryCoding.h" #include "Forging.h" -#include "HexCoding.h" #include "../Base58.h" -#include "../proto/Tezos.pb.h" -using namespace TW; -using namespace TW::Tezos; -using namespace TW::Tezos::Proto; +namespace TW::Tezos { Tezos::OperationList::OperationList(const std::string& str) { branch = str; @@ -53,3 +48,5 @@ Data Tezos::OperationList::forge(const PrivateKey& privateKey) const { return forged; } + +} // namespace TW::Tezos \ No newline at end of file diff --git a/src/Tezos/OperationList.h b/src/Tezos/OperationList.h index c3d0040f606..8ed3152b684 100644 --- a/src/Tezos/OperationList.h +++ b/src/Tezos/OperationList.h @@ -11,11 +11,10 @@ #include "../PrivateKey.h" #include -using namespace TW::Tezos; -using namespace TW::Tezos::Proto; - namespace TW::Tezos { +using TW::Tezos::Proto::Operation; + class OperationList { public: std::string branch; diff --git a/src/Tezos/Signer.cpp b/src/Tezos/Signer.cpp index 3ff02ed8e85..248df7fd115 100644 --- a/src/Tezos/Signer.cpp +++ b/src/Tezos/Signer.cpp @@ -6,7 +6,6 @@ #include "Signer.h" #include "OperationList.h" -#include "../Hash.h" #include "../HexCoding.h" #include diff --git a/src/Theta/Transaction.cpp b/src/Theta/Transaction.cpp index f430d422238..380f30084ea 100644 --- a/src/Theta/Transaction.cpp +++ b/src/Theta/Transaction.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,8 +8,8 @@ #include "../Ethereum/RLP.h" -using namespace TW; -using namespace TW::Theta; +namespace TW::Theta { + using RLP = Ethereum::RLP; Data encode(const Coins& coins) noexcept { @@ -52,13 +52,13 @@ Data encode(const std::vector& outputs) noexcept { } Transaction::Transaction(Ethereum::Address from, Ethereum::Address to, - uint256_t thetaAmount, uint256_t tfuelAmount, - uint64_t sequence, uint256_t feeAmount /* = 1000000000000*/) { + const uint256_t& thetaAmount, const uint256_t& tfuelAmount, + uint64_t sequence, const uint256_t& feeAmount /* = 1000000000000*/) { auto fee = Coins(0, feeAmount); auto coinsInput = Coins(thetaAmount, tfuelAmount + feeAmount); auto coinsOutput = Coins(thetaAmount, tfuelAmount); - auto input = TxInput(std::move(from), coinsInput, sequence); - auto output = TxOutput(std::move(to), coinsOutput); + auto input = TxInput(from, coinsInput, sequence); + auto output = TxOutput(to, coinsOutput); this->_fee = fee; this->inputs.push_back(input); @@ -70,9 +70,9 @@ Data Transaction::encode() const noexcept { uint16_t txType = 2; // TxSend append(encoded, RLP::encode(txType)); auto encodedData = Data(); - append(encodedData, ::encode(_fee)); - append(encodedData, ::encode(inputs)); - append(encodedData, ::encode(outputs)); + append(encodedData, Theta::encode(_fee)); + append(encodedData, Theta::encode(inputs)); + append(encodedData, Theta::encode(outputs)); append(encoded, RLP::encodeList(encodedData)); return encoded; } @@ -86,3 +86,5 @@ bool Transaction::setSignature(const Ethereum::Address& address, const Data& sig } return false; } + +} // namespace TW::Theta diff --git a/src/Theta/Transaction.h b/src/Theta/Transaction.h index cdc9d079d4d..58a3531a0a5 100644 --- a/src/Theta/Transaction.h +++ b/src/Theta/Transaction.h @@ -48,8 +48,8 @@ class Transaction { : _fee(std::move(fee)), inputs(std::move(inputs)), outputs(std::move(outputs)) {} Transaction(Ethereum::Address from, Ethereum::Address to, - uint256_t thetaAmount, uint256_t tfuelAmount, uint64_t sequence, - uint256_t feeAmount = 1000000000000); + const uint256_t& thetaAmount, const uint256_t& tfuelAmount, uint64_t sequence, + const uint256_t& feeAmount = 1000000000000); /// Encodes the transaction Data encode() const noexcept; diff --git a/src/Tron/Serialization.cpp b/src/Tron/Serialization.cpp index a753e52e5d9..36bfe251f69 100644 --- a/src/Tron/Serialization.cpp +++ b/src/Tron/Serialization.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,17 +10,15 @@ #include #include -using namespace TW; -using namespace TW::Tron; -using namespace std; +namespace TW::Tron { using json = nlohmann::json; -string typeName(const protocol::Transaction::Contract::ContractType type) { +std::string typeName(const protocol::Transaction::Contract::ContractType type) { return protocol::Transaction::Contract::ContractType_Name(type); } -string typeUrl(const protocol::Transaction::Contract::ContractType type) { +std::string typeUrl(const protocol::Transaction::Contract::ContractType type) { std::ostringstream stringStream; stringStream << "type.googleapis.com/protocol." << typeName(type); return stringStream.str(); @@ -47,9 +45,9 @@ json valueJSON(const protocol::TransferAssetContract& contract) { json valueJSON(const protocol::VoteAssetContract& contract) { json valueJSON; - - vector vote_address; - for (const string& addr : contract.vote_address()) { + + std::vector vote_address; + for (const std::string& addr : contract.vote_address()) { vote_address.push_back(hex(addr)); } @@ -57,7 +55,7 @@ json valueJSON(const protocol::VoteAssetContract& contract) { valueJSON["vote_address"] = vote_address; valueJSON["support"] = contract.support(); valueJSON["count"] = contract.count(); - + return valueJSON; } @@ -72,7 +70,7 @@ json voteJSON(const protocol::VoteWitnessContract::Vote& vote) { json valueJSON(const protocol::VoteWitnessContract& contract) { json valueJSON; - vector votes; + std::vector votes; for (const protocol::VoteWitnessContract::Vote& vote : contract.votes()) { votes.push_back(voteJSON(vote)); } @@ -136,81 +134,81 @@ json valueJSON(const protocol::TriggerSmartContract& contract) { return valueJSON; } -json parameterJSON(const google::protobuf::Any ¶meter, const protocol::Transaction::Contract::ContractType type) { +json parameterJSON(const google::protobuf::Any& parameter, const protocol::Transaction::Contract::ContractType type) { json paramJSON; paramJSON["type_url"] = typeUrl(type); switch (type) { - case protocol::Transaction::Contract::TransferContract: { - protocol::TransferContract contract; - parameter.UnpackTo(&contract); - paramJSON["value"] = valueJSON(contract); - break; - } - case protocol::Transaction::Contract::TransferAssetContract: { - protocol::TransferAssetContract contract; - parameter.UnpackTo(&contract); - paramJSON["value"] = valueJSON(contract); - break; - } - case protocol::Transaction::Contract::VoteAssetContract: { - protocol::VoteAssetContract contract; - parameter.UnpackTo(&contract); - paramJSON["value"] = valueJSON(contract); - break; - } - case protocol::Transaction::Contract::VoteWitnessContract: { - protocol::VoteWitnessContract contract; - parameter.UnpackTo(&contract); - paramJSON["value"] = valueJSON(contract); - break; - } - case protocol::Transaction::Contract::FreezeBalanceContract: { - protocol::FreezeBalanceContract contract; - parameter.UnpackTo(&contract); - paramJSON["value"] = valueJSON(contract); - break; - } - case protocol::Transaction::Contract::UnfreezeBalanceContract: { - protocol::UnfreezeBalanceContract contract; - parameter.UnpackTo(&contract); - paramJSON["value"] = valueJSON(contract); - break; - } - case protocol::Transaction::Contract::WithdrawBalanceContract: { - protocol::WithdrawBalanceContract contract; - parameter.UnpackTo(&contract); - paramJSON["value"] = valueJSON(contract); - break; - } - case protocol::Transaction::Contract::UnfreezeAssetContract: { - protocol::UnfreezeAssetContract contract; - parameter.UnpackTo(&contract); - paramJSON["value"] = valueJSON(contract); - break; - } - case protocol::Transaction::Contract::TriggerSmartContract: { - protocol::TriggerSmartContract contract; - parameter.UnpackTo(&contract); - paramJSON["value"] = valueJSON(contract); - break; - } - case protocol::Transaction::Contract::AccountCreateContract: - default: - break; + case protocol::Transaction::Contract::TransferContract: { + protocol::TransferContract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } + case protocol::Transaction::Contract::TransferAssetContract: { + protocol::TransferAssetContract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } + case protocol::Transaction::Contract::VoteAssetContract: { + protocol::VoteAssetContract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } + case protocol::Transaction::Contract::VoteWitnessContract: { + protocol::VoteWitnessContract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } + case protocol::Transaction::Contract::FreezeBalanceContract: { + protocol::FreezeBalanceContract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } + case protocol::Transaction::Contract::UnfreezeBalanceContract: { + protocol::UnfreezeBalanceContract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } + case protocol::Transaction::Contract::WithdrawBalanceContract: { + protocol::WithdrawBalanceContract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } + case protocol::Transaction::Contract::UnfreezeAssetContract: { + protocol::UnfreezeAssetContract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } + case protocol::Transaction::Contract::TriggerSmartContract: { + protocol::TriggerSmartContract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } + case protocol::Transaction::Contract::AccountCreateContract: + default: + break; } return paramJSON; } -json contractJSON(const protocol::Transaction::Contract &contract) { +json contractJSON(const protocol::Transaction::Contract& contract) { json contractJSON; contractJSON["type"] = typeName(contract.type()); contractJSON["parameter"] = parameterJSON(contract.parameter(), contract.type()); return contractJSON; } -json raw_dataJSON(const protocol::Transaction::raw &raw) { +json raw_dataJSON(const protocol::Transaction::raw& raw) { json raw_dataJSON; raw_dataJSON["ref_block_bytes"] = hex(raw.ref_block_bytes()); @@ -223,16 +221,18 @@ json raw_dataJSON(const protocol::Transaction::raw &raw) { } raw_dataJSON["timestamp"] = raw.timestamp(); raw_dataJSON["expiration"] = raw.expiration(); - raw_dataJSON["contract"] = json::array({ contractJSON(raw.contract(0)) }); + raw_dataJSON["contract"] = json::array({contractJSON(raw.contract(0))}); return raw_dataJSON; } -json TW::Tron::transactionJSON(const protocol::Transaction& transaction, const TW::Data& txID, const TW::Data& signature) { +json transactionJSON(const protocol::Transaction& transaction, const TW::Data& txID, const TW::Data& signature) { json transactionJSON; transactionJSON["raw_data"] = raw_dataJSON(transaction.raw_data()); transactionJSON["txID"] = hex(txID); - transactionJSON["signature"] = json::array({ hex(signature) }); + transactionJSON["signature"] = json::array({hex(signature)}); return transactionJSON; } + +} // namespace TW::Tron diff --git a/src/Tron/Signer.cpp b/src/Tron/Signer.cpp index 2680046135f..87ed70b30f5 100644 --- a/src/Tron/Signer.cpp +++ b/src/Tron/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,21 +10,16 @@ #include "../Base58.h" #include "../BinaryCoding.h" -#include "../Hash.h" #include "../HexCoding.h" #include "Serialization.h" #include #include -using namespace TW; -using namespace TW::Tron; -using namespace std::chrono; +namespace TW::Tron { const std::string TRANSFER_TOKEN_FUNCTION = "0xa9059cbb"; -size_t base58Capacity = 128; - /// Converts an external TransferContract to an internal one used for signing. protocol::TransferContract to_internal(const Proto::TransferContract& transfer) { auto internal = protocol::TransferContract(); @@ -106,7 +101,7 @@ protocol::VoteAssetContract to_internal(const Proto::VoteAssetContract& voteCont internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); internal.set_support(voteContract.support()); internal.set_count(voteContract.count()); - for(int i = 0; i < voteContract.vote_address_size(); i++) { + for (int i = 0; i < voteContract.vote_address_size(); i++) { auto voteAddress = Base58::bitcoin.decodeCheck(voteContract.vote_address(i)); internal.add_vote_address(voteAddress.data(), voteAddress.size()); } @@ -120,7 +115,7 @@ protocol::VoteWitnessContract to_internal(const Proto::VoteWitnessContract& vote internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); internal.set_support(voteContract.support()); - for(int i = 0; i < voteContract.votes_size(); i++) { + for (int i = 0; i < voteContract.votes_size(); i++) { auto voteAddress = Base58::bitcoin.decodeCheck(voteContract.votes(i).vote_address()); auto* vote = internal.add_votes(); @@ -293,15 +288,15 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { } // Get default timestamp and expiration - const uint64_t now = duration_cast< milliseconds >( - system_clock::now().time_since_epoch() - ).count(); + const uint64_t now = duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); const uint64_t timestamp = input.transaction().timestamp() == 0 - ? now - : input.transaction().timestamp(); + ? now + : input.transaction().timestamp(); const uint64_t expiration = input.transaction().expiration() == 0 - ? timestamp + 10 * 60 * 60 * 1000 // 10 hours - : input.transaction().expiration(); + ? timestamp + 10 * 60 * 60 * 1000 // 10 hours + : input.transaction().expiration(); internal.mutable_raw_data()->set_timestamp(timestamp); internal.mutable_raw_data()->set_expiration(expiration); @@ -325,3 +320,5 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { return output; } + +} // namespace TW::Tron diff --git a/src/VeChain/Transaction.cpp b/src/VeChain/Transaction.cpp index 383531bf8a5..aeca93d352f 100644 --- a/src/VeChain/Transaction.cpp +++ b/src/VeChain/Transaction.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,8 +8,8 @@ #include "../Ethereum/RLP.h" -using namespace TW; -using namespace TW::VeChain; +namespace TW::VeChain { + using RLP = Ethereum::RLP; Data encode(const Clause& clause) noexcept { @@ -45,3 +45,5 @@ Data Transaction::encode() const noexcept { } return RLP::encodeList(encoded); } + +} // namespace TW::VeChain diff --git a/src/Zcash/TAddress.cpp b/src/Zcash/TAddress.cpp deleted file mode 100644 index 9ebb2471ef5..00000000000 --- a/src/Zcash/TAddress.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © 2017-2020 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -#include "TAddress.h" - -using namespace TW::Zcash; diff --git a/src/Zcash/TAddress.h b/src/Zcash/TAddress.h index 91bb67cde6b..3452746b13f 100644 --- a/src/Zcash/TAddress.h +++ b/src/Zcash/TAddress.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Zcash/Transaction.cpp b/src/Zcash/Transaction.cpp index 20ac5669afb..291c3384370 100644 --- a/src/Zcash/Transaction.cpp +++ b/src/Zcash/Transaction.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,26 +8,23 @@ #include "../Bitcoin/SigHashType.h" #include "../BinaryCoding.h" -#include "../Hash.h" -#include "../HexCoding.h" #include -using namespace TW; -using namespace TW::Zcash; +namespace TW::Zcash { -const auto sigHashPersonalization = Data({'Z','c','a','s','h','S','i','g','H','a','s','h'}); -const auto prevoutsHashPersonalization = Data({'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'}); -const auto sequenceHashPersonalization = Data({'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'}); -const auto outputsHashPersonalization = Data({'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'}); -const auto joinsplitsHashPersonalization = Data({'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'}); -const auto shieldedSpendHashPersonalization = Data({'Z','c','a','s','h','S','S','p','e','n','d','s','H','a','s','h'}); -const auto shieldedOutputsHashPersonalization = Data({'Z','c','a','s','h','S','O','u','t','p','u','t','H','a','s','h'}); +const auto sigHashPersonalization = Data({'Z', 'c', 'a', 's', 'h', 'S', 'i', 'g', 'H', 'a', 's', 'h'}); +const auto prevoutsHashPersonalization = Data({'Z', 'c', 'a', 's', 'h', 'P', 'r', 'e', 'v', 'o', 'u', 't', 'H', 'a', 's', 'h'}); +const auto sequenceHashPersonalization = Data({'Z', 'c', 'a', 's', 'h', 'S', 'e', 'q', 'u', 'e', 'n', 'c', 'H', 'a', 's', 'h'}); +const auto outputsHashPersonalization = Data({'Z', 'c', 'a', 's', 'h', 'O', 'u', 't', 'p', 'u', 't', 's', 'H', 'a', 's', 'h'}); +const auto joinsplitsHashPersonalization = Data({'Z', 'c', 'a', 's', 'h', 'J', 'S', 'p', 'l', 'i', 't', 's', 'H', 'a', 's', 'h'}); +const auto shieldedSpendHashPersonalization = Data({'Z', 'c', 'a', 's', 'h', 'S', 'S', 'p', 'e', 'n', 'd', 's', 'H', 'a', 's', 'h'}); +const auto shieldedOutputsHashPersonalization = Data({'Z', 'c', 'a', 's', 'h', 'S', 'O', 'u', 't', 'p', 'u', 't', 'H', 'a', 's', 'h'}); /// See https://github.com/zcash/zips/blob/master/zip-0205.rst#sapling-deployment BRANCH_ID section -const std::array Zcash::SaplingBranchID = {0xbb, 0x09, 0xb8, 0x76}; +const std::array SaplingBranchID = {0xbb, 0x09, 0xb8, 0x76}; /// See https://github.com/zcash/zips/blob/master/zip-0206.rst#blossom-deployment BRANCH_ID section -const std::array Zcash::BlossomBranchID = {0x60, 0x0e, 0xb4, 0x2b}; +const std::array BlossomBranchID = {0x60, 0x0e, 0xb4, 0x2b}; Data Transaction::getPreImage(const Bitcoin::Script& scriptCode, size_t index, enum TWBitcoinSigHashType hashType, uint64_t amount) const { @@ -214,3 +211,5 @@ Bitcoin::Proto::Transaction Transaction::proto() const { return protoTx; } + +} // namespace TW::Zcash diff --git a/src/Zilliqa/Address.cpp b/src/Zilliqa/Address.cpp index bf010554bd0..af0d14ac1bd 100644 --- a/src/Zilliqa/Address.cpp +++ b/src/Zilliqa/Address.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,6 +8,8 @@ #include -using namespace TW::Zilliqa; +namespace TW::Zilliqa { const std::string Address::hrp = HRP_ZILLIQA; + +} // namespace TW::Zilliqa diff --git a/src/Zilliqa/AddressChecksum.cpp b/src/Zilliqa/AddressChecksum.cpp index 3d741a5c4ae..bbd072f6268 100644 --- a/src/Zilliqa/AddressChecksum.cpp +++ b/src/Zilliqa/AddressChecksum.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,11 +11,10 @@ #include "../uint256.h" #include -using namespace TW; -using namespace TW::Zilliqa; +namespace TW::Zilliqa { -/// see https://github.com/Zilliqa/Zilliqa/blob/1c53b792c7ae44f7b77366536a7e2f73a3eade6a/src/libServer/AddressChecksum.h -std::string Zilliqa::checksum(const Data& bytes) { +/// \see https://github.com/Zilliqa/Zilliqa/blob/1c53b792c7ae44f7b77366536a7e2f73a3eade6a/src/libServer/AddressChecksum.h +std::string checksum(const Data& bytes) { const auto addressString = hex(bytes); const auto hash = hex(Hash::sha256(bytes)); @@ -38,3 +37,5 @@ std::string Zilliqa::checksum(const Data& bytes) { return string; } + +} // namespace TW::Zilliqa diff --git a/src/Zilliqa/Entry.cpp b/src/Zilliqa/Entry.cpp index ca66e3637bd..9ab22662f0d 100644 --- a/src/Zilliqa/Entry.cpp +++ b/src/Zilliqa/Entry.cpp @@ -9,35 +9,32 @@ #include "Address.h" #include "Signer.h" -using namespace TW; -using namespace std; - namespace TW::Zilliqa { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, byte, byte, const char*) const { return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, byte, const char*) const { return Address(publicKey).string(); } Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { Address addr; if (!Address::decode(address, addr)) { - return Data(); + return {}; } // data in Zilliqa is a checksummed string without 0x - return TW::data(checksum(addr.getKeyHash())); + return data(checksum(addr.getKeyHash())); } -void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { +void Entry::sign([[maybe_unused]] TWCoinType coin, const Data& dataIn, Data& dataOut) const { signTemplate(dataIn, dataOut); } -string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { +std::string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json, const Data& key) const { return Signer::signJSON(json, key); } diff --git a/src/Zilliqa/Signer.cpp b/src/Zilliqa/Signer.cpp index 1683d59c77f..521ffd5c556 100644 --- a/src/Zilliqa/Signer.cpp +++ b/src/Zilliqa/Signer.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -18,8 +18,8 @@ #include #include -using namespace TW; -using namespace TW::Zilliqa; +namespace TW::Zilliqa { + using ByteArray = ZilliqaMessage::ByteArray; static inline Data prependZero(Data& data) { @@ -137,3 +137,5 @@ std::string Signer::signJSON(const std::string& json, const Data& key) { input.set_private_key(key.data(), key.size()); return hex(Signer::sign(input).json()); } + +} // namespace TW::Zilliqa diff --git a/tests/Aeternity/AddressTests.cpp b/tests/Aeternity/AddressTests.cpp index 40c99814889..c08866c05e7 100644 --- a/tests/Aeternity/AddressTests.cpp +++ b/tests/Aeternity/AddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,13 +7,11 @@ #include #include #include -#include -using namespace TW; -using namespace TW::Aeternity; +namespace TW::Aeternity::tests { TEST(AeternityAddress, FromPublicKey) { - auto publicKey = PublicKey(parse_hex("ee93a4f66f8d16b819bb9beb9ffccdfcdc1412e87fee6a324c2a99a1e0e67148"),TWPublicKeyTypeED25519); + auto publicKey = PublicKey(parse_hex("ee93a4f66f8d16b819bb9beb9ffccdfcdc1412e87fee6a324c2a99a1e0e67148"), TWPublicKeyTypeED25519); auto address = Address(publicKey); ASSERT_EQ(address.string(), "ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw"); } @@ -21,4 +19,6 @@ TEST(AeternityAddress, FromPublicKey) { TEST(AeternityAddress, FromString) { auto address = Address("ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw"); ASSERT_EQ(address.string(), "ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw"); -} \ No newline at end of file +} + +} // namespace TW::Aeternity::tests diff --git a/tests/Aeternity/SignerTests.cpp b/tests/Aeternity/SignerTests.cpp index aab6d85abfb..55f9246fd3b 100644 --- a/tests/Aeternity/SignerTests.cpp +++ b/tests/Aeternity/SignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,8 +12,7 @@ #include #include "uint256.h" -using namespace TW; -using namespace TW::Aeternity; +namespace TW::Aeternity::tests { TEST(AeternitySigner, Sign) { std::string sender_id = "ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw"; @@ -82,3 +81,5 @@ TEST(AeternitySigner, SignTxWithZeroNonce) { EXPECT_EQ(result.signature(), "sg_MaJc4ptSUhq5kH6mArszDAvu4f7PejyuhmgM6U8GEr8bRUTaSFbdFPx4C6FEYA5v5Lgwu9EToaWnHgR2xkqZ9JjHnaBpA"); EXPECT_EQ(result.encoded(), "tx_+LULAfhCuECdQsgcE8bp+9CANdasxkt5gxfjBSI1ztyPl1aNJbm+MwUvE7Lu/qvAkHijfe+Eui2zrqhZRYc5mblRa+oLOIIEuG34awwBoQHuk6T2b40WuBm7m+uf/M383BQS6H/uajJMKpmh4OZxSKEBHxOjsIvwAUAGYqaLadh194A87EwIZH9u1dhMeJe9UKOILsSS9IArwACGEjCc5UAAgwG7qwCPWmVybyBub25jZSB0ZXN0piWfFA=="); } + +} // namespace TW::Aeternity::tests diff --git a/tests/Aeternity/TWAnySignerTests.cpp b/tests/Aeternity/TWAnySignerTests.cpp index 01b4fcf80be..f966db42fbe 100644 --- a/tests/Aeternity/TWAnySignerTests.cpp +++ b/tests/Aeternity/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,12 +12,11 @@ #include "../interface/TWTestUtilities.h" #include -using namespace TW; -using namespace TW::Aeternity; +namespace TW::Aeternity::tests { TEST(TWAnySignerAeternity, Sign) { auto privateKey = parse_hex("4646464646464646464646464646464646464646464646464646464646464646"); - + Proto::SigningInput input; input.set_from_address("ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw"); input.set_to_address("ak_Egp9yVdpxmvAfQ7vsXGvpnyfNq71msbdUpkMNYGTeTe8kPL3v"); @@ -35,3 +34,5 @@ TEST(TWAnySignerAeternity, Sign) { ASSERT_EQ(output.encoded(), "tx_+KkLAfhCuEDZ2XDV5OuHv1iuLn66sFLBUwnzp1K8JW1Zz+fEgmuEh6HEvNu0R112M3IYkVzvTSnT0pJ3TWhVOumgJ+IWwW8HuGH4XwwBoQHuk6T2b40WuBm7m+uf/M383BQS6H/uajJMKpmh4OZxSKEBHxOjsIvwAUAGYqaLadh194A87EwIZH9u1dhMeJe9UKMKhhIwnOVAAIMBQ0Uxi0hlbGxvIFdvcmxkDZqNSg=="); } + +} // namespace TW::Aeternity::tests diff --git a/tests/Aeternity/TransactionTests.cpp b/tests/Aeternity/TransactionTests.cpp index 384216ba3e4..ea0ac8aedd3 100644 --- a/tests/Aeternity/TransactionTests.cpp +++ b/tests/Aeternity/TransactionTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,12 +7,10 @@ #include "HexCoding.h" #include "PrivateKey.h" #include "../interface/TWTestUtilities.h" - -#include "HexCoding.h" #include #include -using namespace TW::Aeternity; +namespace TW::Aeternity::tests { TEST(AeternityTransaction, EncodeRlp) { std::string sender_id = "ak_2a1j2Mk9YSmC1gioUq4PWRm3bsv887MbuRVwyv4KaUGoR1eiKi"; @@ -62,3 +60,4 @@ TEST(AeternityTransaction, EncodeRlpWithZeroTtl) { ASSERT_EQ(encodedTxHex, "f85c0c01a101cea7ade470c9f99d9d4e400880a86f1d49bb444b62f11a9ebb64bbcfeb73fef3a1011f13a3b08bf001400662a68b69d875f7803cec4c08647f6ed5d84c7897bd50a30a8612309ce5400000318b48656c6c6f20576f726c64"); } +} // namespace TW::Aeternity::tests diff --git a/tests/Aion/RLPTests.cpp b/tests/Aion/RLPTests.cpp index 977fbdbda65..86df3146ace 100644 --- a/tests/Aion/RLPTests.cpp +++ b/tests/Aion/RLPTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,11 +6,10 @@ #include "Aion/RLP.h" #include "HexCoding.h" - #include -using namespace TW; -using namespace TW::Aion; +namespace TW::Aion::tests { + using boost::multiprecision::uint128_t; TEST(AionRLP, EncodeLong) { @@ -24,3 +23,5 @@ TEST(AionRLP, EncodeLong) { EXPECT_EQ(hex(RLP::encodeLong(uint128_t(4295000060L))), "880000000100007ffc"); EXPECT_EQ(hex(RLP::encodeLong(uint128_t(72057594037927935L))), "8800ffffffffffffff"); } + +} // namespace TW::Aion::tests diff --git a/tests/Aion/SignerTests.cpp b/tests/Aion/SignerTests.cpp index b8a7970f248..34d44504db7 100644 --- a/tests/Aion/SignerTests.cpp +++ b/tests/Aion/SignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,8 +10,7 @@ #include -using namespace TW; -using namespace TW::Aion; +namespace TW::Aion::tests { TEST(AionSigner, Sign) { auto address = Aion::Address("0xa082c3de528b7807dc27ad66debb16d4cfe4054209398cee619dd95955063d1e"); @@ -38,3 +37,5 @@ TEST(AionSigner, SignWithData) { // Raw transaction EXPECT_EQ(hex(transaction.encode()), "f8a109a0a082c3de528b7807dc27ad66debb16d4cfe4054209398cee619dd95955063d1e8227108641494f4e000085242019b04d8252088800000004a817c80001b860a775daa30b33fda3091768f0561c8042ee23cb48a6a3e5d7e8248b13d04a48a736fc2642c2d62900204779aa274dba3b8712eff7a8464aa78ea52b09ece20679fe3f5edf94c84a7e0c5f93213be891bc279af927086f455167f5bc73d3046c0d"); } + +} // namespace TW::Aion::tests diff --git a/tests/Aion/TWAnySignerTests.cpp b/tests/Aion/TWAnySignerTests.cpp index 1f30f761d03..2f7ab4630c0 100644 --- a/tests/Aion/TWAnySignerTests.cpp +++ b/tests/Aion/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,12 +12,11 @@ #include "../interface/TWTestUtilities.h" #include -using namespace TW; -using namespace TW::Aion; +namespace TW::Aion::tests { TEST(TWAnySignerAion, Sign) { auto privateKey = parse_hex("db33ffdf82c7ba903daf68d961d3c23c20471a8ce6b408e52d579fd8add80cc9"); - + Proto::SigningInput input; input.set_to_address("0xa082c3de528b7807dc27ad66debb16d4cfe4054209398cee619dd95955063d1e"); auto amount = store(uint256_t(10000)); @@ -36,3 +35,5 @@ TEST(TWAnySignerAion, Sign) { ASSERT_EQ(hex(output.encoded()), "f89b09a0a082c3de528b7807dc27ad66debb16d4cfe4054209398cee619dd95955063d1e8227108085242019b04d8252088800000004a817c80001b860a775daa30b33fda3091768f0561c8042ee23cb48a6a3e5d7e8248b13d04a48a7d3d3386742c2716031b79950cef5fcb49c079a5cab095c8b08915e126b9741389924ba2d5c00036a3b39c2a8562fa0800f1a13a566ce6e027274ce63a41dec07"); } + +} // namespace TW::Aion::tests diff --git a/tests/Aion/TransactionTests.cpp b/tests/Aion/TransactionTests.cpp index ad6b8546c2b..9b9ff818758 100644 --- a/tests/Aion/TransactionTests.cpp +++ b/tests/Aion/TransactionTests.cpp @@ -1,17 +1,14 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. #include "Aion/Transaction.h" - #include "HexCoding.h" - #include -using namespace TW; -using namespace TW::Aion; +namespace TW::Aion::tests { TEST(AionTransaction, Encode) { auto address = Aion::Address("0xa082c3de528b7807dc27ad66debb16d4cfe4054209398cee619dd95955063d1e"); @@ -25,3 +22,5 @@ TEST(AionTransaction, EncodeWithSignature) { transaction.signature = parse_hex("a775daa30b33fda3091768f0561c8042ee23cb48a6a3e5d7e8248b13d04a48a7d3d3386742c2716031b79950cef5fcb49c079a5cab095c8b08915e126b9741389924ba2d5c00036a3b39c2a8562fa0800f1a13a566ce6e027274ce63a41dec07"); ASSERT_EQ(hex(transaction.encode()), "f89b09a0a082c3de528b7807dc27ad66debb16d4cfe4054209398cee619dd95955063d1e8227108085242019b04d8252088800000004a817c80001b860a775daa30b33fda3091768f0561c8042ee23cb48a6a3e5d7e8248b13d04a48a7d3d3386742c2716031b79950cef5fcb49c079a5cab095c8b08915e126b9741389924ba2d5c00036a3b39c2a8562fa0800f1a13a566ce6e027274ce63a41dec07"); } + +} // namespace TW::Aion::tests diff --git a/tests/Base64Tests.cpp b/tests/Base64Tests.cpp index 9a918d7fd46..64787ffaaf8 100644 --- a/tests/Base64Tests.cpp +++ b/tests/Base64Tests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,8 +10,7 @@ #include -using namespace TW; -using namespace TW::Base64; +namespace TW::Base64::tests { TEST(Base64, encode) { auto encoded = encode(data("Hello, world!")); @@ -49,7 +48,7 @@ TEST(Base64, decode) { TEST(Base64, UrlFormat) { const std::string const1 = "11003faa8556289975ec991ac9994dfb613abec4ea000d5094e6379080f594e559b330b8"; - + // Encoded string has both special characters auto encoded = encode(parse_hex(const1)); EXPECT_EQ("EQA/qoVWKJl17JkayZlN+2E6vsTqAA1QlOY3kID1lOVZszC4", encoded); @@ -61,3 +60,5 @@ TEST(Base64, UrlFormat) { decoded = decodeBase64Url("EQA_qoVWKJl17JkayZlN-2E6vsTqAA1QlOY3kID1lOVZszC4"); EXPECT_EQ(const1, hex(decoded)); } + +} // namespace TW::Base64::tests diff --git a/tests/BaseEncoding.cpp b/tests/BaseEncoding.cpp index 65763eb404f..48003ec5fad 100644 --- a/tests/BaseEncoding.cpp +++ b/tests/BaseEncoding.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,18 +9,15 @@ #include -using namespace TW; -using namespace TW::Base32; +namespace TW::Base32::tests { -void TestBase32Encode(const char* decoded_hex, const char* expected_encoded_in, const char* alphabet_in = nullptr) -{ +void TestBase32Encode(const char* decoded_hex, const char* expected_encoded_in, const char* alphabet_in = nullptr) { auto decoded = parse_hex(std::string(decoded_hex)); auto encoded = encode(decoded, alphabet_in); ASSERT_EQ(std::string(expected_encoded_in), encoded); } -void TestBase32Decode(const char* encoded_in, const char* expected_decoded_hex, const char* alphabet_in = nullptr) -{ +void TestBase32Decode(const char* encoded_in, const char* expected_decoded_hex, const char* alphabet_in = nullptr) { Data decoded; bool res = decode(std::string(encoded_in), decoded, alphabet_in); ASSERT_TRUE(res); @@ -33,7 +30,7 @@ TEST(Base32, Encode) { TestBase32Encode("010203", "AEBAG"); TestBase32Encode("", ""); TestBase32Encode( - "48450c2745890def7da06fc2551f912a14f9fc581c12db6e4d6f73f2fd0b2ad50df3d396", + "48450c2745890def7da06fc2551f912a14f9fc581c12db6e4d6f73f2fd0b2ad50df3d396", "JBCQYJ2FREG667NAN7BFKH4RFIKPT7CYDQJNW3SNN5Z7F7ILFLKQ346TSY"); TestBase32Encode( "3dd160d60673bd9b13adc25dad5d988d0d9f4ccdbe95a2122f9ef28b3ce4e89693074620", @@ -49,7 +46,7 @@ TEST(Base32, Decode) { TestBase32Decode("", ""); TestBase32Decode( "JBCQYJ2FREG667NAN7BFKH4RFIKPT7CYDQJNW3SNN5Z7F7ILFLKQ346TSY", - "48450c2745890def7da06fc2551f912a14f9fc581c12db6e4d6f73f2fd0b2ad50df3d396"); + "48450c2745890def7da06fc2551f912a14f9fc581c12db6e4d6f73f2fd0b2ad50df3d396"); TestBase32Decode( "HXIWBVQGOO6ZWE5NYJO22XMYRUGZ6TGNX2K2EERPT3ZIWPHE5CLJGB2GEA", "3dd160d60673bd9b13adc25dad5d988d0d9f4ccdbe95a2122f9ef28b3ce4e89693074620"); @@ -66,7 +63,9 @@ TEST(Base32, EncodeNimiq) { TEST(Base32, DecodeInvalid) { Data decoded; - ASSERT_FALSE(decode("+-", decoded)); // invalid characters - ASSERT_FALSE(decode("A", decoded)); // invalid odd length + ASSERT_FALSE(decode("+-", decoded)); // invalid characters + ASSERT_FALSE(decode("A", decoded)); // invalid odd length ASSERT_FALSE(decode("ABC", decoded)); // invalid odd length } + +} // namespace TW::Base32::tests diff --git a/tests/Binance/TWAnySignerTests.cpp b/tests/Binance/TWAnySignerTests.cpp index 22ab4b17de7..aa06a82e55e 100644 --- a/tests/Binance/TWAnySignerTests.cpp +++ b/tests/Binance/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -14,8 +14,7 @@ #include #include -using namespace TW; -using namespace TW::Binance; +namespace TW::Binance { Proto::SigningOutput SignTest() { auto input = Proto::SigningInput(); @@ -90,3 +89,5 @@ TEST(TWAnySignerBinance, MultithreadedSigning) { th2.join(); th3.join(); } + +} // namespace TW::Binance diff --git a/tests/BinanceSmartChain/SignerTests.cpp b/tests/BinanceSmartChain/SignerTests.cpp index 579cbb4ef18..3ec01b4f1e6 100644 --- a/tests/BinanceSmartChain/SignerTests.cpp +++ b/tests/BinanceSmartChain/SignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,7 +8,6 @@ #include "Ethereum/Signer.h" #include "Ethereum/Transaction.h" #include "Ethereum/Address.h" -#include "Ethereum/RLP.h" #include "Ethereum/ABI.h" #include "proto/Ethereum.pb.h" #include "HexCoding.h" @@ -19,15 +18,11 @@ namespace TW::Binance { -using namespace TW::Ethereum; -using namespace TW::Ethereum::ABI; - - TEST(BinanceSmartChain, SignNativeTransfer) { // https://explorer.binance.org/smart-testnet/tx/0x6da28164f7b3bc255d749c3ae562e2a742be54c12bf1858b014cc2fe5700684e auto toAddress = parse_hex("0x31BE00EB1fc8e14A696DBC72f746ec3e95f49683"); - auto transaction = TransactionNonTyped::buildNativeTransfer( + auto transaction = Ethereum::TransactionNonTyped::buildNativeTransfer( /* nonce: */ 0, /* gasPrice: */ 20000000000, /* gasLimit: */ 21000, @@ -46,9 +41,9 @@ TEST(BinanceSmartChain, SignNativeTransfer) { TEST(BinanceSmartChain, SignTokenTransfer) { auto toAddress = parse_hex("0x31BE00EB1fc8e14A696DBC72f746ec3e95f49683"); - auto func = Function("transfer", std::vector>{ - std::make_shared(toAddress), - std::make_shared(uint256_t(10000000000000000)) + auto func = Ethereum::ABI::Function("transfer", std::vector>{ + std::make_shared(toAddress), + std::make_shared(uint256_t(10000000000000000)) }); Data payloadFunction; func.encode(payloadFunction); @@ -75,7 +70,7 @@ TEST(BinanceSmartChain, SignTokenTransfer) { const std::string expected = "f8ab1e8504a817c800830f424094ed24fc36d5ee211ea25a80239fb8c4cfd80f12ee80b844a9059cbb00000000000000000000000031be00eb1fc8e14a696dbc72f746ec3e95f49683000000000000000000000000000000000000000000000000002386f26fc1000081e6a0aa9d5e9a947e96f728fe5d3e6467000cd31a693c00270c33ec64b4abddc29516a00bf1d5646139b2bcca1ad64e6e79f45b7d1255de603b5a3765cbd9544ae148d0"; - Proto::SigningOutput output; + Ethereum::Proto::SigningOutput output; ANY_SIGN(input, TWCoinTypeSmartChain); EXPECT_EQ(hex(output.encoded()), expected); diff --git a/tests/Bitcoin/FeeCalculatorTests.cpp b/tests/Bitcoin/FeeCalculatorTests.cpp index fd0585d0482..93ea4013e77 100644 --- a/tests/Bitcoin/FeeCalculatorTests.cpp +++ b/tests/Bitcoin/FeeCalculatorTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,9 +8,7 @@ #include -using namespace TW; -using namespace TW::Bitcoin; - +namespace TW::Bitcoin { TEST(BitcoinFeeCalculator, ConstantFeeCalculator) { const auto feeCalculator = ConstantFeeCalculator(33); @@ -75,3 +73,5 @@ TEST(BitcoinFeeCalculator, DecredCalculate) { EXPECT_EQ(feeCalculator.calculate(1, 2, 10), 2540); EXPECT_EQ(feeCalculator.calculateSingleInput(1), 166); } + +} // namespace TW::Bitcoin diff --git a/tests/Bitcoin/InputSelectorTests.cpp b/tests/Bitcoin/InputSelectorTests.cpp index ce8b32e5674..1f66fedeec5 100644 --- a/tests/Bitcoin/InputSelectorTests.cpp +++ b/tests/Bitcoin/InputSelectorTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,17 +7,11 @@ #include #include "TxComparisonHelper.h" -#include "Bitcoin/OutPoint.h" -#include "Bitcoin/Script.h" #include "Bitcoin/InputSelector.h" -#include "proto/Bitcoin.pb.h" #include -#include - -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { TEST(BitcoinInputSelector, SelectUnspents1) { auto utxos = buildTestUTXOs({4000, 2000, 6000, 1000, 11000, 12000}); @@ -193,7 +187,7 @@ TEST(BitcoinInputSelector, SelectThreeNoDust) { // 100'000 would fit with dust; instead two UTXOs are selected not to leave dust EXPECT_TRUE(verifySelectedUTXOs(selected, {75'000, 100'000})); - + EXPECT_EQ(feeCalculator.calculate(1, 2, 1), 174); const auto dustLimit = 102; @@ -471,7 +465,7 @@ TEST(BitcoinInputSelector, ManyUtxos_5000_simple) { // expected result: 1205 utxos, with the smaller amounts (except the very small dust ones) std::vector subset; uint64_t subsetSum = 0; - for (int i = 10; i < 1205+10; ++i) { + for (int i = 10; i < 1205 + 10; ++i) { const uint64_t val = (i + 1) * 100; subset.push_back(val); subsetSum += val; @@ -497,7 +491,7 @@ TEST(BitcoinInputSelector, ManyUtxos_MaxAmount_5000) { // expected result: 4990 utxos (none of which is dust) std::vector subset; uint64_t subsetSum = 0; - for (int i = 10; i < 4990+10; ++i) { + for (int i = 10; i < 4990 + 10; ++i) { const uint64_t val = (i + 1) * 100; subset.push_back(val); subsetSum += val; @@ -506,3 +500,5 @@ TEST(BitcoinInputSelector, ManyUtxos_MaxAmount_5000) { EXPECT_EQ(subsetSum, 1'250'244'500ul); EXPECT_TRUE(verifySelectedUTXOs(selected, subset)); } + +} // namespace TW::Bitcoin diff --git a/tests/Bitcoin/TWBitcoinSigningTests.cpp b/tests/Bitcoin/TWBitcoinSigningTests.cpp index 3942c7c9baa..f2c26b2691c 100644 --- a/tests/Bitcoin/TWBitcoinSigningTests.cpp +++ b/tests/Bitcoin/TWBitcoinSigningTests.cpp @@ -1,39 +1,34 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include "Base58.h" #include "Bitcoin/Address.h" -#include "Bitcoin/SegwitAddress.h" #include "Bitcoin/OutPoint.h" #include "Bitcoin/Script.h" +#include "Bitcoin/SegwitAddress.h" +#include "Bitcoin/SigHashType.h" #include "Bitcoin/Transaction.h" #include "Bitcoin/TransactionBuilder.h" #include "Bitcoin/TransactionSigner.h" -#include "Bitcoin/SigHashType.h" -#include "Bitcoin/SegwitAddress.h" -#include "Base58.h" #include "Hash.h" #include "HexCoding.h" #include "PrivateKey.h" -#include "proto/Bitcoin.pb.h" #include "TxComparisonHelper.h" -#include "../interface/TWTestUtilities.h" +#include "proto/Bitcoin.pb.h" -#include #include #include -#include -#include #include -#include #include +#include -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { +// clang-format off SigningInput buildInputP2PKH(bool omitKey = false) { auto hash0 = parse_hex("fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f"); auto hash1 = parse_hex("ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a"); @@ -75,7 +70,8 @@ SigningInput buildInputP2PKH(bool omitKey = false) { input.utxos.push_back(utxo0); UTXO utxo1; - utxo1.script = Script(parse_hex("0014" "1d0f172a0ecb48aee1be1f2687d2963ae33f71a1")); + utxo1.script = Script(parse_hex("0014" + "1d0f172a0ecb48aee1be1f2687d2963ae33f71a1")); utxo1.amount = 600'000'000; utxo1.outPoint = OutPoint(hash1, 1, UINT32_MAX); input.utxos.push_back(utxo1); @@ -207,13 +203,13 @@ TEST(BitcoinSigning, SignP2WPKH_Bip143) { utxo1.script = utxo1Script; utxo1.amount = 600000000; // 0x23C34600 0046c323 utxo1.outPoint = OutPoint(hash1, 1, UINT32_MAX); - input.utxos.push_back(utxo1); + input.utxos.push_back(utxo1); // Set plan to force both UTXOs and exact output amounts TransactionPlan plan; plan.amount = amount; plan.availableAmount = 600000000 + 1000000; - plan.fee = 265210000; // very large, the amounts specified (in1, out0, out1) are not consistent/realistic + plan.fee = 265210000; // very large, the amounts specified (in1, out0, out1) are not consistent/realistic plan.change = 223450000; // 0x0d519390 plan.branchId = {0}; plan.utxos.push_back(utxo0); @@ -276,7 +272,8 @@ SigningInput buildInputP2WPKH(int64_t amount, TWBitcoinSigHashType hashType, int assert(hex(utxoPubkeyHash1) == "1d0f172a0ecb48aee1be1f2687d2963ae33f71a1"); input.privateKeys.push_back(utxoKey1); - auto scriptPub1 = Script(parse_hex("0014" "1d0f172a0ecb48aee1be1f2687d2963ae33f71a1")); + auto scriptPub1 = Script(parse_hex("0014" + "1d0f172a0ecb48aee1be1f2687d2963ae33f71a1")); Data scriptHash; scriptPub1.matchPayToWitnessPublicKeyHash(scriptHash); auto scriptHashHex = hex(scriptHash); @@ -292,7 +289,8 @@ SigningInput buildInputP2WPKH(int64_t amount, TWBitcoinSigHashType hashType, int input.utxos.push_back(utxo0); UTXO utxo1; - utxo1.script = Script(parse_hex("0014" "1d0f172a0ecb48aee1be1f2687d2963ae33f71a1")); + utxo1.script = Script(parse_hex("0014" + "1d0f172a0ecb48aee1be1f2687d2963ae33f71a1")); utxo1.amount = utxo1Amount; utxo1.outPoint = OutPoint(hash1, 1, UINT32_MAX); input.utxos.push_back(utxo1); @@ -502,7 +500,7 @@ SigningInput buildInputP2WSH(enum TWBitcoinSigHashType hashType, bool omitScript auto hash0 = parse_hex("0001000000000000000000000000000000000000000000000000000000000000"); utxo0.outPoint = OutPoint(hash0, 0, UINT32_MAX); input.utxos.push_back(utxo0); - + return input; } @@ -978,7 +976,7 @@ TEST(BitcoinSigning, SignP2SH_P2WSH) { "47" "3044022044e3b59b06931d46f857c82fa1d53d89b116a40a581527eac35c5eb5b7f0785302207d0f8b5d063ffc6749fb4e133db7916162b540c70dee40ec0b21e142d8843b3a00" "cf" "56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae" "00000000" // nLockTime - ; + ; Data serialized; signedTx.encode(serialized); @@ -1108,7 +1106,7 @@ TEST(BitcoinSigning, Plan_10input_MaxAmount) { input.toAddress = "bc1qauwlpmzamwlf9tah6z4w0t8sunh6pnyyjgk0ne"; input.changeAddress = ownAddress; - // Plan. + // Plan. // Estimated size: witness size: 10 * (1 + 1 + 72 + 1 + 33) + 2 = 1082; base 451; raw 451 + 1082 = 1533; vsize 451 + 1082/4 --> 722 // Actual size: witness size: 1078; base 451; raw 451 + 1078 = 1529; vsize 451 + 1078/4 --> 721 auto plan = TransactionBuilder::plan(input); @@ -1466,12 +1464,12 @@ TEST(BitcoinSigning, EncodeThreeOutput) { auto hashType = TWBitcoinSigHashType::TWBitcoinSigHashTypeAll; Data sighash = unsignedTx.getSignatureHash(redeemScript0, unsignedTx.inputs[0].previousOutput.index, - hashType, utxo0Amount, static_cast(unsignedTx._version)); + hashType, utxo0Amount, static_cast(unsignedTx._version)); auto sig = privkey.signAsDER(sighash); ASSERT_FALSE(sig.empty()); sig.push_back(hashType); EXPECT_EQ(hex(sig), "30450221008d88197a37ffcb51ecacc7e826aa588cb1068a107a82373c4b54ec42318a395c02204abbf5408504614d8f943d67e7873506c575e85a5e1bd92a02cd345e5192a82701"); - + // add witness stack unsignedTx.inputs[0].scriptWitness.push_back(sig); unsignedTx.inputs[0].scriptWitness.push_back(pubkey.bytes); @@ -1556,7 +1554,7 @@ TEST(BitcoinSigning, SignP2TR_5df51e) { const auto privateKey = "13fcaabaf9e71ffaf915e242ec58a743d55f102cf836968e5bd4881135e0c52c"; const auto ownAddress = "bc1qpjult34k9spjfym8hss2jrwjgf0xjf40ze0pp8"; const auto toAddress = "bc1ptmsk7c2yut2xah4pgflpygh2s7fh0cpfkrza9cjj29awapv53mrslgd5cf"; // Taproot - const auto coin = TWCoinTypeBitcoin; + const auto coin = TWCoinTypeBitcoin; // Setup input SigningInput input; @@ -1758,3 +1756,5 @@ TEST(BitcoinSigning, Sign_OpReturn_THORChainSwap) { "00000000" // nLockTime ); } +// clang-format on +} // namespace TW::Bitcoin diff --git a/tests/Bitcoin/TWBitcoinTransactionTests.cpp b/tests/Bitcoin/TWBitcoinTransactionTests.cpp index c0654b789da..8df4be05c54 100644 --- a/tests/Bitcoin/TWBitcoinTransactionTests.cpp +++ b/tests/Bitcoin/TWBitcoinTransactionTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,14 +6,10 @@ #include "Bitcoin/Transaction.h" #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" - -#include #include -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { TEST(BitcoinTransaction, Encode) { auto transaction = Transaction(2, 0); @@ -37,5 +33,7 @@ TEST(BitcoinTransaction, Encode) { transaction.encode(unsignedData, Transaction::SegwitFormatMode::NonSegwit); ASSERT_EQ(unsignedData.size(), 201ul); ASSERT_EQ(hex(unsignedData), - "02000000035897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f0000000000ffffffffbf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c1200000000ffffffff22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc0100000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d717000000001976a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac00000000"); + "02000000035897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f0000000000ffffffffbf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c1200000000ffffffff22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc0100000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d717000000001976a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac00000000"); } + +} // namespace TW::Bitcoin diff --git a/tests/Bitcoin/TransactionPlanTests.cpp b/tests/Bitcoin/TransactionPlanTests.cpp index 955486e22f8..d906c863056 100644 --- a/tests/Bitcoin/TransactionPlanTests.cpp +++ b/tests/Bitcoin/TransactionPlanTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -16,9 +16,7 @@ #include -using namespace TW; -using namespace TW::Bitcoin; - +namespace TW::Bitcoin { TEST(TransactionPlan, OneTypical) { auto utxos = buildTestUTXOs({100'000}); @@ -196,7 +194,7 @@ TEST(TransactionPlan, ThreeNoDust) { } TEST(TransactionPlan, TenThree) { - auto utxos = buildTestUTXOs({1'000, 2'000, 100'000, 3'000, 4'000, 5,000, 125'000, 6'000, 150'000, 7'000}); + auto utxos = buildTestUTXOs({1'000, 2'000, 100'000, 3'000, 4'000, 5, 000, 125'000, 6'000, 150'000, 7'000}); auto sigingInput = buildSigningInput(300'000, 1, utxos); auto txPlan = TransactionBuilder::plan(sigingInput); @@ -263,7 +261,7 @@ TEST(TransactionPlan, Inputs5_33Req19NoDustFee2) { // UTXOs smaller than singleInputFee are not included auto txPlan = TransactionBuilder::plan(sigingInput); - auto expectedFee = 283*byteFee; + auto expectedFee = 283 * byteFee; EXPECT_TRUE(verifyPlan(txPlan, {6'000, 8'000, 10'000}, 19'000, expectedFee)); auto& feeCalculator = getFeeCalculator(TWCoinTypeBitcoin); @@ -278,7 +276,7 @@ TEST(TransactionPlan, Inputs5_33Req19Dust1Fee5) { // UTXOs smaller than singleInputFee are not included auto txPlan = TransactionBuilder::plan(sigingInput); - auto expectedFee = 283*byteFee; + auto expectedFee = 283 * byteFee; EXPECT_TRUE(verifyPlan(txPlan, {6'000, 8'000, 10'000}, 19'000, expectedFee)); auto& feeCalculator = getFeeCalculator(TWCoinTypeBitcoin); @@ -293,7 +291,7 @@ TEST(TransactionPlan, Inputs5_33Req19Dust1Fee9) { // UTXOs smaller than singleInputFee are not included auto txPlan = TransactionBuilder::plan(sigingInput); - auto expectedFee = 283*byteFee; + auto expectedFee = 283 * byteFee; EXPECT_TRUE(verifyPlan(txPlan, {6'000, 8'000, 10'000}, 19'000, expectedFee)); auto& feeCalculator = getFeeCalculator(TWCoinTypeBitcoin); @@ -319,7 +317,7 @@ TEST(TransactionPlan, Inputs5_33Req13Fee20) { // UTXOs smaller than singleInputFee are not included auto txPlan = TransactionBuilder::plan(sigingInput); - auto expectedFee = 283*byteFee; + auto expectedFee = 283 * byteFee; EXPECT_TRUE(verifyPlan(txPlan, {6'000, 8'000, 10'000}, 13'000, expectedFee)); auto& feeCalculator = getFeeCalculator(TWCoinTypeBitcoin); @@ -688,3 +686,5 @@ TEST(TransactionPlan, OpReturn) { EXPECT_EQ(feeCalculator.calculate(1, 2, byteFee), 174 * byteFee); EXPECT_EQ(feeCalculator.calculate(1, 3, byteFee), 205 * byteFee); } + +} // namespace TW::Bitcoin diff --git a/tests/Bitcoin/TxComparisonHelper.cpp b/tests/Bitcoin/TxComparisonHelper.cpp index cc2fb43ecec..f99fae78c82 100644 --- a/tests/Bitcoin/TxComparisonHelper.cpp +++ b/tests/Bitcoin/TxComparisonHelper.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -16,12 +16,10 @@ #include "HexCoding.h" #include "BinaryCoding.h" -#include #include #include -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { auto emptyTxOutPoint = OutPoint(parse_hex("1d0f172a0ecb48aee1be1f2687d2963ae33f71a1"), 0); @@ -30,14 +28,15 @@ UTXO buildTestUTXO(int64_t amount) { utxo.amount = amount; utxo.outPoint = emptyTxOutPoint; utxo.outPoint.sequence = UINT32_MAX; - utxo.script = Script(parse_hex("0014" "1d0f172a0ecb48aee1be1f2687d2963ae33f71a1")); + utxo.script = Script(parse_hex("0014" + "1d0f172a0ecb48aee1be1f2687d2963ae33f71a1")); return utxo; } UTXOs buildTestUTXOs(const std::vector& amounts) { UTXOs utxos; - for (auto it = amounts.begin(); it != amounts.end(); it++) { - utxos.push_back(buildTestUTXO(*it)); + for (long long amount : amounts) { + utxos.push_back(buildTestUTXO(amount)); } return utxos; } @@ -48,7 +47,7 @@ SigningInput buildSigningInput(Amount amount, int byteFee, const UTXOs& utxos, b input.byteFee = byteFee; input.useMaxAmount = useMaxAmount; input.coinType = coin; - + if (!omitPrivateKey) { auto utxoKey = PrivateKey(parse_hex("619c335025c7f4012e556c2a58b2506e30b8511b53ade95ea316fd8c3286feb9")); auto pubKey = utxoKey.getPublicKey(TWPublicKeyTypeSECP256k1); @@ -65,7 +64,7 @@ SigningInput buildSigningInput(Amount amount, int byteFee, const UTXOs& utxos, b int64_t sumUTXOs(const UTXOs& utxos) { int64_t s = 0u; - for (auto& utxo: utxos) { + for (auto& utxo : utxos) { s += utxo.amount; } return s; @@ -104,8 +103,8 @@ bool verifyPlan(const TransactionPlan& plan, const std::vector& utxoAmo std::cerr << "Mismatch in fee, act " << plan.fee << ", exp " << fee << std::endl; } int64_t sumExpectedUTXOs = 0; - for (auto i = 0ul; i < utxoAmounts.size(); ++i) { - sumExpectedUTXOs += utxoAmounts[i]; + for (long long utxoAmount : utxoAmounts) { + sumExpectedUTXOs += utxoAmount; } if (plan.availableAmount != sumExpectedUTXOs) { ret = false; @@ -140,7 +139,7 @@ bool operator==(const EncodedTxSize& s1, const EncodedTxSize& s2) { } EncodedTxSize getEncodedTxSize(const Transaction& tx) { - EncodedTxSize size; + EncodedTxSize size{}; { // full segwit size Data data; tx.encode(data, Transaction::SegwitFormatMode::Segwit); @@ -159,10 +158,10 @@ EncodedTxSize getEncodedTxSize(const Transaction& tx) { assert(size.segwit - size.nonSegwit == 2ul + witnessSize); } // compute virtual size: 3/4 of (smaller) non-segwit + 1/4 of segwit size - uint64_t sum = size.nonSegwit * 3 + size.segwit; + uint64_t sum = size.nonSegwit * 3 + size.segwit; size.virtualBytes = sum / 4 + (sum % 4 != 0); // alternative computation: (smaller) non-segwit + 1/4 of the diff (witness-only) - uint64_t vSize2 = size.nonSegwit + (witnessSize + 2)/ 4 + ((witnessSize + 2) % 4 != 0); + uint64_t vSize2 = size.nonSegwit + (witnessSize + 2) / 4 + ((witnessSize + 2) % 4 != 0); assert(size.virtualBytes == vSize2); return size; } @@ -207,7 +206,7 @@ void prettyPrintTransaction(const Transaction& tx, bool useWitnessFormat) { data.clear(); encodeVarInt(tx.inputs.size(), data); std::cout << " \"" << hex(data) << "\" // inputs\n"; - for (auto& input: tx.inputs) { + for (auto& input : tx.inputs) { auto& outpoint = reinterpret_cast(input.previousOutput); std::cout << " \"" << hex(outpoint.hash) << "\""; data.clear(); @@ -223,7 +222,7 @@ void prettyPrintTransaction(const Transaction& tx, bool useWitnessFormat) { data.clear(); encodeVarInt(tx.outputs.size(), data); std::cout << " \"" << hex(data) << "\" // outputs\n"; - for (auto& output: tx.outputs) { + for (auto& output : tx.outputs) { data.clear(); encode64LE(output.value, data); std::cout << " \"" << hex(data) << "\""; @@ -233,11 +232,11 @@ void prettyPrintTransaction(const Transaction& tx, bool useWitnessFormat) { if (useWitnessFormat) { std::cout << " // witness\n"; - for (auto& input: tx.inputs) { + for (auto& input : tx.inputs) { data.clear(); encodeVarInt(input.scriptWitness.size(), data); std::cout << " \"" << hex(data) << "\"\n"; - for (auto& item: input.scriptWitness) { + for (auto& item : input.scriptWitness) { data.clear(); encodeVarInt(item.size(), data); std::cout << " \"" << hex(data) << "\""; @@ -251,3 +250,5 @@ void prettyPrintTransaction(const Transaction& tx, bool useWitnessFormat) { std::cout << " \"" << hex(data) << "\" // nLockTime\n"; std::cout << "\n"; } + +} // namespace TW::Bitcoin diff --git a/tests/Bitcoin/TxComparisonHelper.h b/tests/Bitcoin/TxComparisonHelper.h index 05fea3251f1..4cb2f92a1d2 100644 --- a/tests/Bitcoin/TxComparisonHelper.h +++ b/tests/Bitcoin/TxComparisonHelper.h @@ -16,9 +16,7 @@ #include #include -using namespace TW; -using namespace TW::Bitcoin; - +namespace TW::Bitcoin { /// Build a dummy UTXO with the given amount UTXO buildTestUTXO(int64_t amount); @@ -26,8 +24,8 @@ UTXO buildTestUTXO(int64_t amount); /// Build a set of dummy UTXO with the given amounts UTXOs buildTestUTXOs(const std::vector& amounts); -SigningInput buildSigningInput(Amount amount, int byteFee, const UTXOs& utxos, - bool useMaxAmount = false, enum TWCoinType coin = TWCoinTypeBitcoin, bool omitPrivateKey = false); +SigningInput buildSigningInput(Amount amount, int byteFee, const UTXOs& utxos, + bool useMaxAmount = false, enum TWCoinType coin = TWCoinTypeBitcoin, bool omitPrivateKey = false); /// Compare a set of selected UTXOs to the expected set of amounts. /// Returns false on mismatch, and error is printed (stderr). @@ -56,3 +54,5 @@ bool validateEstimatedSize(const Transaction& tx, int smallerTolerance = -1, int /// Print out a transaction in a nice format, as structured hex strings. void prettyPrintTransaction(const Transaction& tx, bool useWitnessFormat = true); + +} // namespace TW::Bitcoin diff --git a/tests/BitcoinGold/TWSignerTests.cpp b/tests/BitcoinGold/TWSignerTests.cpp index 31f9a6f8fc5..f75bc5219a5 100644 --- a/tests/BitcoinGold/TWSignerTests.cpp +++ b/tests/BitcoinGold/TWSignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,20 +9,18 @@ #include #include -#include "Bitcoin/SegwitAddress.h" -#include "proto/Bitcoin.pb.h" #include "Bitcoin/OutPoint.h" #include "Bitcoin/Script.h" +#include "Bitcoin/SigHashType.h" #include "Bitcoin/Transaction.h" #include "Bitcoin/TransactionBuilder.h" #include "Bitcoin/TransactionSigner.h" -#include "Bitcoin/SigHashType.h" #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "proto/Bitcoin.pb.h" #include "../Bitcoin/TxComparisonHelper.h" +#include "../interface/TWTestUtilities.h" -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { TEST(TWBitcoinGoldSigner, SignTransaction) { const int64_t amount = 10000; @@ -39,7 +37,6 @@ TEST(TWBitcoinGoldSigner, SignTransaction) { auto utxoKey0 = parse_hex("cbe13a79b82ec7f8871b336a64fd8d531f598e7c9022e29c67e824cfd54af57f"); input.add_private_key(utxoKey0.data(), utxoKey0.size()); - auto scriptPub1 = Script(parse_hex("0014db746a75d9aae8995d135b1e19a04d7765242a8f")); auto scriptHash = std::vector(); scriptPub1.matchPayToWitnessPublicKeyHash(scriptHash); @@ -53,14 +50,13 @@ TEST(TWBitcoinGoldSigner, SignTransaction) { auto utxo0Script = parse_hex("0014d53cae7c6fb6c8efe4fd8bfecea36534105b1674"); utxo0->set_script(utxo0Script.data(), utxo0Script.size()); utxo0->set_amount(99000); - + auto hash0 = parse_hex("1d4653041a1915b3a52d47aeaa119c8f79ed7634a93692a6e811173067464f03"); utxo0->mutable_out_point()->set_hash(hash0.data(), hash0.size()); utxo0->mutable_out_point()->set_index(1); utxo0->mutable_out_point()->set_sequence(0xfffffffd); input.set_lock_time(0x00098971); - Proto::TransactionPlan plan; { // try plan first @@ -84,6 +80,7 @@ TEST(TWBitcoinGoldSigner, SignTransaction) { signedTx.encode(serialized); // BitcoinGold Mainnet: https://btg2.trezor.io/tx/db26faec66d070045df0da56140349beb5a12bd14bca12b162fded8f84d18afa EXPECT_EQ(serialized.size(), 222ul); + // clang-format off ASSERT_EQ(hex(serialized), "01000000" "0001" @@ -96,6 +93,8 @@ TEST(TWBitcoinGoldSigner, SignTransaction) { "4730440220325c56363b17e1b1329efeb400c0933a3d9adfb304f29889b3ef01084aef19e302202a69d9be9ef668b5a5517fbfa42e1fc26b3f8b582c721bd1eabd721322bc2b6c41" "2103e00b5dec8078d526fba090247bd92db6b67a4dd1953b788cea9b52de9471b8cf" "71890900" - ); + ); + // clang-format on } - + +} // namespace TW::Bitcoin diff --git a/tests/Cardano/TransactionTests.cpp b/tests/Cardano/TransactionTests.cpp index eaedb19f822..702a32ce77a 100644 --- a/tests/Cardano/TransactionTests.cpp +++ b/tests/Cardano/TransactionTests.cpp @@ -14,10 +14,7 @@ #include -using namespace TW::Cardano; -using namespace TW; -using namespace std; - +namespace TW::Cardano { Transaction createTx() { Transaction tx; @@ -25,12 +22,10 @@ Transaction createTx() { tx.inputs.emplace_back(parse_hex("554f2fd942a23d06835d26bbd78f0106fa94c8a551114a0bef81927f66467af0"), 0); tx.outputs.emplace_back( AddressV3("addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23").data(), - 2000000 - ); + 2000000); tx.outputs.emplace_back( AddressV3("addr1q92cmkgzv9h4e5q7mnrzsuxtgayvg4qr7y3gyx97ukmz3dfx7r9fu73vqn25377ke6r0xk97zw07dqr9y5myxlgadl2s0dgke5").data(), - 16749189 - ); + 16749189); tx.fee = 165555; tx.ttl = 53333345; return tx; @@ -60,40 +55,40 @@ TEST(CardanoTransaction, GetId) { TEST(CardanoTransaction, minAdaAmount) { const auto policyId = "9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77"; - { // ADA only + { // ADA only const auto tb = TokenBundle(); EXPECT_EQ(tb.minAdaAmount(), 1000000ul); } - { // 1 policyId, 1 6-char asset name + { // 1 policyId, 1 6-char asset name const auto tb = TokenBundle({TokenAmount(policyId, "TOKEN1", 0)}); EXPECT_EQ(tb.minAdaAmount(), 1444443ul); } - { // 2 policyId, 2 4-char asset names + { // 2 policyId, 2 4-char asset names auto tb = TokenBundle(); tb.add(TokenAmount("012345678901234567890POLICY1", "TOK1", 20)); tb.add(TokenAmount("012345678901234567890POLICY2", "TOK2", 20)); EXPECT_EQ(tb.minAdaAmount(), 1629628ul); } - { // 10 policyId, 10 6-char asset names + { // 10 policyId, 10 6-char asset names auto tb = TokenBundle(); for (auto i = 0; i < 10; ++i) { - string policyId1 = + "012345678901234567890123456" + std::to_string(i); - string name = "ASSET" + std::to_string(i); + std::string policyId1 = +"012345678901234567890123456" + std::to_string(i); + std::string name = "ASSET" + std::to_string(i); tb.add(TokenAmount(policyId1, name, 0)); } EXPECT_EQ(tb.minAdaAmount(), 3370367ul); } - EXPECT_EQ(TokenBundle::minAdaAmountHelper(0, 0, 0), 1000000ul); // ADA only - EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 0, 0), 1370369ul); // 1 policyId, no asset name - EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 1, 1), 1444443ul); // 1 policyId, 1 1-char asset name - EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 1, 6), 1444443ul); // 1 policyId, 1 6-char asset name - EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 1, 32), 1555554ul); // 1 policyId, 1 32-char asset name - EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 110, 110*32), 23777754ul); // 1 policyId, 110 32-char asset name - EXPECT_EQ(TokenBundle::minAdaAmountHelper(2, 2, 8), 1629628ul); // 2 policyId, 2 4-char asset names - EXPECT_EQ(TokenBundle::minAdaAmountHelper(3, 5, 20), 1999998ul); // 3 policyId, 5 4-char asset names - EXPECT_EQ(TokenBundle::minAdaAmountHelper(10, 10, 10*6), 3370367ul); // 10 policyId, 10 6-char asset names - EXPECT_EQ(TokenBundle::minAdaAmountHelper(60, 60, 60*32), 21222201ul); // 60 policyId, 60 32-char asset names + EXPECT_EQ(TokenBundle::minAdaAmountHelper(0, 0, 0), 1000000ul); // ADA only + EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 0, 0), 1370369ul); // 1 policyId, no asset name + EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 1, 1), 1444443ul); // 1 policyId, 1 1-char asset name + EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 1, 6), 1444443ul); // 1 policyId, 1 6-char asset name + EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 1, 32), 1555554ul); // 1 policyId, 1 32-char asset name + EXPECT_EQ(TokenBundle::minAdaAmountHelper(1, 110, 110 * 32), 23777754ul); // 1 policyId, 110 32-char asset name + EXPECT_EQ(TokenBundle::minAdaAmountHelper(2, 2, 8), 1629628ul); // 2 policyId, 2 4-char asset names + EXPECT_EQ(TokenBundle::minAdaAmountHelper(3, 5, 20), 1999998ul); // 3 policyId, 5 4-char asset names + EXPECT_EQ(TokenBundle::minAdaAmountHelper(10, 10, 10 * 6), 3370367ul); // 10 policyId, 10 6-char asset names + EXPECT_EQ(TokenBundle::minAdaAmountHelper(60, 60, 60 * 32), 21222201ul); // 60 policyId, 60 32-char asset names } TEST(CardanoTransaction, getPolicyIDs) { @@ -113,12 +108,12 @@ TEST(CardanoTransaction, getPolicyIDs) { } TEST(TWCardanoTransaction, minAdaAmount) { - { // ADA-only + { // ADA-only const auto bundleProto = TokenBundle().toProto(); const auto bundleProtoData = data(bundleProto.SerializeAsString()); EXPECT_EQ(TWCardanoMinAdaAmount(&bundleProtoData), 1000000ul); } - { // 2 policyId, 2 4-char asset names + { // 2 policyId, 2 4-char asset names auto bundle = TokenBundle(); bundle.add(TokenAmount("012345678901234567890POLICY1", "TOK1", 20)); bundle.add(TokenAmount("012345678901234567890POLICY2", "TOK2", 20)); @@ -127,3 +122,5 @@ TEST(TWCardanoTransaction, minAdaAmount) { EXPECT_EQ(TWCardanoMinAdaAmount(&bundleProtoData), 1629628ul); } } + +} // namespace TW::Cardano diff --git a/tests/CborTests.cpp b/tests/CborTests.cpp index 6016793dc4c..592b0ec9322 100644 --- a/tests/CborTests.cpp +++ b/tests/CborTests.cpp @@ -10,21 +10,23 @@ #include -using namespace TW; -using namespace TW::Cbor; +namespace TW::Cbor::tests { + using namespace std; +// clang-format off TEST(Cbor, EncSample1) { EXPECT_EQ( - "8205a26178186461793831", + "8205a26178186461793831", hex(Encode::array({ - Encode::uint(5), - Encode::map({ - make_pair(Encode::string("x"), Encode::uint(100)), - make_pair(Encode::string("y"), Encode::negInt(50)), - }), - }).encoded()) + Encode::uint(5), + Encode::map({ + make_pair(Encode::string("x"), Encode::uint(100)), + make_pair(Encode::string("y"), Encode::negInt(50)), + }), + }) + .encoded()) ); } @@ -84,16 +86,14 @@ TEST(Cbor, EncNegInt) { EXPECT_EQ("-9", Decode(Encode::negInt(9).encoded()).dumpToString()); } - TEST(Cbor, EncString) { EXPECT_EQ("60", hex(Encode::string("").encoded())); EXPECT_EQ("6141", hex(Encode::string("A").encoded())); EXPECT_EQ("656162636465", hex(Encode::string("abcde").encoded())); Data long258(258); EXPECT_EQ( - "590102000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - hex(Encode::bytes(long258).encoded()) - ); + "590102000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + hex(Encode::bytes(long258).encoded())); EXPECT_EQ("\"abcde\"", Decode(Encode::string("abcde").encoded()).dumpToString()); EXPECT_EQ("h\"6162636465\"", Decode(Encode::bytes(parse_hex("6162636465")).encoded()).dumpToString()); @@ -215,7 +215,7 @@ TEST(Cbor, DecMemoryref) { } TEST(Cbor, GetValue) { - EXPECT_EQ(5ul, Decode(parse_hex("05")).getValue()); + EXPECT_EQ(5ul, Decode(parse_hex("05")).getValue()); } TEST(Cbor, GetValueInvalid) { @@ -257,7 +257,7 @@ TEST(Cbor, GetStringInvalidTooShort) { TEST(Cbor, ArrayEmpty) { Data cbor = Encode::array({}).encoded(); - + EXPECT_EQ("80", hex(cbor)); EXPECT_TRUE(Decode(cbor).isValid()); EXPECT_EQ("[]", Decode(cbor).dumpToString()); @@ -272,7 +272,7 @@ TEST(Cbor, Array3) { Encode::uint(2), Encode::uint(3), }).encoded(); - + EXPECT_EQ("83010203", hex(cbor)); EXPECT_TRUE(Decode(cbor).isValid()); EXPECT_EQ("[1, 2, 3]", Decode(cbor).dumpToString()); @@ -296,11 +296,10 @@ TEST(Cbor, ArrayNested) { Encode::uint(5), }), }).encoded(); - + EXPECT_EQ("8301820203820405", hex(cbor)); EXPECT_TRUE(Decode(cbor).isValid()); - EXPECT_EQ("[1, [2, 3], [4, 5]]", - Decode(cbor).dumpToString()); + EXPECT_EQ("[1, [2, 3], [4, 5]]", Decode(cbor).dumpToString()); Decode decode(cbor); EXPECT_EQ(3ul, decode.getArrayElements().size()); @@ -319,11 +318,11 @@ TEST(Cbor, Array25) { elem.push_back(Encode::uint(i)); } Data cbor = Encode::array(elem).encoded(); - + EXPECT_EQ("98190102030405060708090a0b0c0d0e0f101112131415161718181819", hex(cbor)); EXPECT_TRUE(Decode(cbor).isValid()); EXPECT_EQ("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]", - Decode(cbor).dumpToString()); + Decode(cbor).dumpToString()); Decode decode(cbor); EXPECT_EQ(25ul, decode.getArrayElements().size()); @@ -334,7 +333,7 @@ TEST(Cbor, Array25) { TEST(Cbor, MapEmpty) { Data cbor = Encode::map({}).encoded(); - + EXPECT_EQ("a0", hex(cbor)); EXPECT_TRUE(Decode(cbor).isValid()); EXPECT_EQ("{}", Decode(cbor).dumpToString()); @@ -348,7 +347,7 @@ TEST(Cbor, Map2Num) { make_pair(Encode::uint(1), Encode::uint(2)), make_pair(Encode::uint(3), Encode::uint(4)), }).encoded(); - + EXPECT_EQ("a201020304", hex(cbor)); EXPECT_TRUE(Decode(cbor).isValid()); EXPECT_EQ("{1: 2, 3: 4}", Decode(cbor).dumpToString()); @@ -363,15 +362,15 @@ TEST(Cbor, Map2WithArr) { Data cbor = Encode::map({ make_pair(Encode::string("a"), Encode::uint(1)), make_pair(Encode::string("b"), Encode::array({ - Encode::uint(2), + Encode::uint(2), Encode::uint(3), })), }).encoded(); - + EXPECT_EQ("a26161016162820203", hex(cbor)); EXPECT_TRUE(Decode(cbor).isValid()); - EXPECT_EQ("{\"a\": 1, \"b\": [2, 3]}", - Decode(cbor).dumpToString()); + EXPECT_EQ("{\"a\": 1, \"b\": [2, 3]}", + Decode(cbor).dumpToString()); Decode decode(cbor); EXPECT_EQ(2ul, decode.getMapElements().size()); @@ -389,11 +388,11 @@ TEST(Cbor, MapNested) { make_pair(Encode::string("b"), Encode::string("c")), })), }).encoded(); - + EXPECT_EQ("a16161a161626163", hex(cbor)); EXPECT_TRUE(Decode(cbor).isValid()); - EXPECT_EQ("{\"a\": {\"b\": \"c\"}}", - Decode(cbor).dumpToString()); + EXPECT_EQ("{\"a\": {\"b\": \"c\"}}", + Decode(cbor).dumpToString()); Decode decode(cbor); EXPECT_EQ(1ul, decode.getMapElements().size()); @@ -444,15 +443,15 @@ TEST(Cbor, MapGetInvalidTooShort2) { TEST(Cbor, ArrayIndef) { Data cbor = Encode::indefArray() - .addIndefArrayElem(Encode::uint(1)) - .addIndefArrayElem(Encode::uint(2)) - .closeIndefArray() - .encoded(); - + .addIndefArrayElem(Encode::uint(1)) + .addIndefArrayElem(Encode::uint(2)) + .closeIndefArray() + .encoded(); + EXPECT_EQ("9f0102ff", hex(cbor)); EXPECT_TRUE(Decode(cbor).isValid()); EXPECT_EQ("[_ 1, 2]", - Decode(cbor).dumpToString()); + Decode(cbor).dumpToString()); Decode decode(cbor); EXPECT_EQ(2ul, decode.getArrayElements().size()); @@ -485,10 +484,10 @@ TEST(Cbor, ArrayInfefErrorCloseNostart) { TEST(Cbor, ArrayInfefErrorResultNoclose) { try { Data cbor = Encode::indefArray() - .addIndefArrayElem(Encode::uint(1)) - .addIndefArrayElem(Encode::uint(2)) - // close is missing, break command not written - .encoded(); + .addIndefArrayElem(Encode::uint(1)) + .addIndefArrayElem(Encode::uint(2)) + // close is missing, break command not written + .encoded(); } catch (exception& ex) { return; } @@ -520,3 +519,5 @@ TEST(Cbor, GetTagElementNotTag) { } FAIL() << "Expected exception"; } +// clang-format on +} // namespace TW::Cbor::tests diff --git a/tests/Cosmos/ProtobufTests.cpp b/tests/Cosmos/ProtobufTests.cpp index a31b662ac5e..73557fd4303 100644 --- a/tests/Cosmos/ProtobufTests.cpp +++ b/tests/Cosmos/ProtobufTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -20,8 +20,8 @@ #include -using namespace TW::Cosmos; -using namespace TW; +namespace TW::Cosmos::tests { + using json = nlohmann::json; TEST(CosmosProtobuf, SendMsg) { @@ -63,3 +63,5 @@ TEST(CosmosProtobuf, DeterministicSerialization_Article) { const auto serialized = data(article.SerializeAsString()); EXPECT_EQ(hex(serialized), "0a1b54686520776f726c64206e65656473206368616e676520f09f8cb318e8bebec8bc2e280138024a084e696365206f6e654a095468616e6b20796f75"); } + +} // namespace TW::Cosmos::tests diff --git a/tests/Cosmos/SignerTests.cpp b/tests/Cosmos/SignerTests.cpp index e3b87703b6d..36355e3ed4f 100644 --- a/tests/Cosmos/SignerTests.cpp +++ b/tests/Cosmos/SignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,14 +12,11 @@ #include "Cosmos/Signer.h" #include "../interface/TWTestUtilities.h" #include "Cosmos/Protobuf/bank_tx.pb.h" -#include "Cosmos/Protobuf/coin.pb.h" #include #include -using namespace TW; -using namespace TW::Cosmos; - +namespace TW::Cosmos::tests { TEST(CosmosSigner, SignTxProtobuf) { auto input = Proto::SigningInput(); @@ -212,7 +209,7 @@ TEST(CosmosSigner, SignIbcTransferProtobuf_817101) { auto output = Signer::sign(input, TWCoinTypeCosmos); // real-world tx: https://www.mintscan.io/cosmos/txs/817101F3D96314AD028733248B28BAFAD535024D7D2C8875D3FE31DC159F096B - // curl -H 'Content-Type: application/json' --data-binary '{"tx_bytes": "Cr4BCr...1yKOU=", "mode": "BROADCAST_MODE_BLOCK"}' https://api.cosmos.network/cosmos/tx/v1beta1/txs + // curl -H 'Content-Type: application/json' --data-binary '{"tx_bytes": "Cr4BCr...1yKOU=", "mode": "BROADCAST_MODE_BLOCK"}' https://api.cosmos.network/cosmos/tx/v1beta1/txs // also similar TX: BCDAC36B605576C8182C2829C808B30A69CAD4959D5ED1E6FF9984ABF280D603 assertJSONEqual(output.serialized(), "{\"tx_bytes\": \"Cr4BCrsBCikvaWJjLmFwcGxpY2F0aW9ucy50cmFuc2Zlci52MS5Nc2dUcmFuc2ZlchKNAQoIdHJhbnNmZXISC2NoYW5uZWwtMTQxGg8KBXVhdG9tEgYxMDAwMDAiLWNvc21vczFta3k2OWNuOGVrdHd5MDg0NXZlYzl1cHNkcGhrdHh0MDNna3dseCorb3NtbzE4czBoZG5zbGxnY2Nsd2V1OWF5bXc0bmdrdHIyazBya3ZuN2ptbjIHCAEQgI6ZBBJoClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEC7O9c5DejAsZ/lUaN5LMfNukR9GfX5qUrQcHhPh1WNkkSBAoCCAEYAhIUCg4KBXVhdG9tEgUxMjUwMBCgwh4aQK0HIWdFMk+C6Gi1KG/vELe1ffcc1aEWUIqz2t/ZhwqNNHxUUSp27wteiugHEMVTEIOBhs84t2gIcT/nD/1yKOU=\", \"mode\": \"BROADCAST_MODE_BLOCK\"}"); EXPECT_EQ(hex(output.signature()), "ad07216745324f82e868b5286fef10b7b57df71cd5a116508ab3dadfd9870a8d347c54512a76ef0b5e8ae80710c55310838186cf38b76808713fe70ffd7228e5"); @@ -252,7 +249,7 @@ TEST(CosmosSigner, SignDirect1) { TEST(CosmosSigner, SignDirect_0a90010a) { const auto bodyBytes = parse_hex("0a90010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e6412700a2d636f736d6f7331706b707472653766646b6c366766727a6c65736a6a766878686c63337234676d6d6b38727336122d636f736d6f7331717970717870713971637273737a673270767871367273307a716733797963356c7a763778751a100a0575636f736d120731323334353637"); - { // verify contents of body + { // verify contents of body auto msgSend = cosmos::bank::v1beta1::MsgSend(); msgSend.set_from_address("cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6"); msgSend.set_to_address("cosmos1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu"); @@ -294,3 +291,5 @@ TEST(CosmosSigner, SignDirect_0a90010a) { EXPECT_EQ(output.json(), ""); EXPECT_EQ(output.error(), ""); } + +} // namespace TW::Cosmos::tests diff --git a/tests/Cosmos/StakingTests.cpp b/tests/Cosmos/StakingTests.cpp index c7148d6c147..f3fb89a34f5 100644 --- a/tests/Cosmos/StakingTests.cpp +++ b/tests/Cosmos/StakingTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,11 +11,9 @@ #include "HexCoding.h" #include "proto/Cosmos.pb.h" #include "../interface/TWTestUtilities.h" - #include -using namespace TW; -using namespace TW::Cosmos; +namespace TW::Cosmos::tests { TEST(CosmosStaking, CompoundingAuthz) { // Successfully broadcasted https://www.mintscan.io/cosmos/txs/C4629BC7C88690518D8F448E7A8D239C9D63975B11F8E1CE2F95CC2ADA3CCF67 @@ -244,3 +242,5 @@ TEST(CosmosStaking, Withdraw) { EXPECT_EQ(hex(signingOutput.serialized()), ""); } } + +} // namespace TW::Cosmos::tests diff --git a/tests/Cosmos/TWAnySignerTests.cpp b/tests/Cosmos/TWAnySignerTests.cpp index eef12c6e02c..ae6fd1e8bf7 100644 --- a/tests/Cosmos/TWAnySignerTests.cpp +++ b/tests/Cosmos/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,8 +11,7 @@ #include #include -using namespace TW; -using namespace TW::Cosmos; +namespace TW::Cosmos::tests { TEST(TWAnySignerCosmos, SignTx) { auto privateKey = parse_hex("8bbec3772ddb4df68f3186440380c301af116d1422001c1877d6f5e4dba8c8af"); @@ -62,3 +61,5 @@ TEST(TWAnySignerCosmos, SignJSON) { ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeCosmos)); assertStringsEqual(result, R"({"mode":"block","tx":{"fee":{"amount":[{"amount":"5000","denom":"uatom"}],"gas":"200000"},"memo":"Testing","msg":[{"type":"cosmos-sdk/MsgSend","value":{"amount":[{"amount":"995000","denom":"uatom"}],"from_address":"cosmos1ufwv9ymhqaal6xz47n0jhzm2wf4empfqvjy575","to_address":"cosmos135qla4294zxarqhhgxsx0sw56yssa3z0f78pm0"}}],"signatures":[{"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"A6EsukEXB53GhohQVeDpxtkeH8KQIayd/Co/ApYRYkTm"},"signature":"ULEpUqNzoAnYEx2x22F3ANAiPXquAU9+mqLWoAA/ZOUGTMsdb6vryzsW6AKX2Kqj1pGNdrTcQ58Z09JPyjpgEA=="}]}})"); } + +} // namespace TW::Cosmos::tests diff --git a/tests/CryptoOrg/AddressTests.cpp b/tests/CryptoOrg/AddressTests.cpp index 833a79016fa..8bd3bfdd62f 100644 --- a/tests/CryptoOrg/AddressTests.cpp +++ b/tests/CryptoOrg/AddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -13,8 +13,7 @@ #include #include -using namespace TW; -using namespace TW::Cosmos; +namespace TW::Cosmos::tests { TEST(CryptoorgAddress, Valid) { ASSERT_TRUE(Address::isValid(TWCoinTypeCryptoOrg, "cro1ctwtcwpgksky988dhth6jslxveumgu0d45zgf0")); @@ -50,3 +49,5 @@ TEST(CryptoorgAddress, FromString) { EXPECT_EQ(address.string(), "cro1ctwtcwpgksky988dhth6jslxveumgu0d45zgf0"); EXPECT_EQ(hex(address.getKeyHash()), "c2dcbc3828b42c429cedbaefa943e66679b471ed"); } + +} // namespace TW::Cosmos::tests \ No newline at end of file diff --git a/tests/CryptoOrg/SignerTests.cpp b/tests/CryptoOrg/SignerTests.cpp index f74b7af074e..9cb39723edb 100644 --- a/tests/CryptoOrg/SignerTests.cpp +++ b/tests/CryptoOrg/SignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,15 +8,13 @@ #include "Cosmos/Signer.h" #include "Cosmos/Address.h" #include "HexCoding.h" -#include "PrivateKey.h" #include "PublicKey.h" #include "../interface/TWTestUtilities.h" #include #include -using namespace TW; -using namespace TW::Cosmos; +namespace TW::Cosmos::tests { TEST(CryptoorgSigner, SignTx_DDCCE4) { auto input = Cosmos::Proto::SigningInput(); @@ -171,3 +169,5 @@ TEST(CryptoorgSigner, SignJson) { } )"); } + +} // namespace TW::Cosmos::tests diff --git a/tests/Decred/AddressTests.cpp b/tests/Decred/AddressTests.cpp index 49f627dabe9..9629a821d21 100644 --- a/tests/Decred/AddressTests.cpp +++ b/tests/Decred/AddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,8 +12,7 @@ #include -using namespace TW; -using namespace TW::Decred; +namespace TW::Decred::tests { TEST(DecredAddress, FromPublicKey) { const auto publicKey = PublicKey(parse_hex("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"), TWPublicKeyTypeSECP256k1); @@ -45,3 +44,5 @@ TEST(DecredAddress, Derive) { const auto address = TW::deriveAddress(TWCoinTypeDecred, wallet.getKey(TWCoinTypeDecred, path)); ASSERT_EQ(address, "DsVMHD5D86dpRnt2GPZvv4bYUJZg6B9Pzqa"); } + +} // namespace TW::Decred::tests diff --git a/tests/DigiByte/TWDigiByteTests.cpp b/tests/DigiByte/TWDigiByteTests.cpp index c135a7d662a..32ff866d846 100644 --- a/tests/DigiByte/TWDigiByteTests.cpp +++ b/tests/DigiByte/TWDigiByteTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -16,8 +16,7 @@ #include -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { TEST(DigiByteTransaction, SignTransaction) { /* @@ -71,18 +70,19 @@ TEST(DigiByteTransaction, SignTransaction) { hex(serialized), "01000000" "01" - "ea63bdc39035ebe02df7ad999581156f996303a70f9a3358811454a7ca806b96" - "00000000" - "6a" - "473044022003e9756b12ecbe5788fdb6eb4b6d7b58f9f9410df32f3047edb0dd0ebffb0d630220499d00d17e50c48b4bac6c0ce148f13bb3109a8845fa3400a2d6a57dabf2c4010121024e525e582452cece7b869532d9e354cfec58b71cbed76f7238c91274a64b2116" - "ffffffff" - "02" - "4023050600000000""19" - "76a9142d5b215a11029ee51a1dd9404d271c7e4a74f5f288ac" - "18053d0000000000""19" - "76a91447825943ca6a936b177fdc7c9dc05251640169c288ac" + "ea63bdc39035ebe02df7ad999581156f996303a70f9a3358811454a7ca806b96" "00000000" - ); + "6a" + "473044022003e9756b12ecbe5788fdb6eb4b6d7b58f9f9410df32f3047edb0dd0ebffb0d630220499d00d17e50c48b4bac6c0ce148f13bb3109a8845fa3400a2d6a57dabf2c4010121024e525e582452cece7b869532d9e354cfec58b71cbed76f7238c91274a64b2116" + "ffffffff" + "02" + "4023050600000000" + "19" + "76a9142d5b215a11029ee51a1dd9404d271c7e4a74f5f288ac" + "18053d0000000000" + "19" + "76a91447825943ca6a936b177fdc7c9dc05251640169c288ac" + "00000000"); } TEST(DigiByteTransaction, SignP2WPKH) { @@ -127,7 +127,7 @@ TEST(DigiByteTransaction, SignP2WPKH) { TEST(DigiByteTransaction, LockScripts) { // https://dgb2.trezor.io/tx/966b80caa754148158339a0fa70363996f15819599adf72de0eb3590c3bd63ea - + auto script = WRAP(TWBitcoinScript, TWBitcoinScriptLockScriptForAddress(STRING("DBfCffUdSbhqKZhjuvrJ6AgvJofT4E2kp4").get(), TWCoinTypeDigiByte)); auto scriptData = WRAPD(TWBitcoinScriptData(script.get())); assertHexEqual(scriptData, "76a91447825943ca6a936b177fdc7c9dc05251640169c288ac"); @@ -137,8 +137,10 @@ TEST(DigiByteTransaction, LockScripts) { assertHexEqual(scriptData2, "0014885534ab5dc680b68d95c0af49ec2acc2e9915c4"); // https://dgb2.trezor.io/tx/965eb4afcd0aa6e3f4f8fc3513ca042f09e6e2235367fa006cbd1f546c293a2a - + auto script3 = WRAP(TWBitcoinScript, TWBitcoinScriptLockScriptForAddress(STRING("SUngTA1vaC2E62mbnc81Mdos3TcvZHwsVo").get(), TWCoinTypeDigiByte)); auto scriptData3 = WRAPD(TWBitcoinScriptData(script3.get())); assertHexEqual(scriptData3, "a91452356ed3d2d31eb8b263ace5d164e3cf3b37096687"); } + +} // namespace TW::Bitcoin diff --git a/tests/ECash/TWECashTests.cpp b/tests/ECash/TWECashTests.cpp index 9a8a24b4f09..974f9bcff81 100644 --- a/tests/ECash/TWECashTests.cpp +++ b/tests/ECash/TWECashTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2021 Trust Wallet. +// Copyright © 2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -22,8 +22,7 @@ #include -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { TEST(ECash, Address) { EXPECT_TRUE(TWAnyAddressIsValid(STRING("pqx578nanz2h2estzmkr53zqdg6qt8xyqvh683mrz0").get(), TWCoinTypeECash)); @@ -93,9 +92,8 @@ TEST(ECash, LockScript) { TEST(ECash, ExtendedKeys) { // Same test as BCH, but with the 899 derivation path auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic( - STRING("ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal").get(), - STRING("TREZOR").get() - )); + STRING("ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal").get(), + STRING("TREZOR").get())); auto xprv = WRAPS(TWHDWalletGetExtendedPrivateKey(wallet.get(), TWPurposeBIP44, TWCoinTypeECash, TWHDVersionXPRV)); auto xpub = WRAPS(TWHDWalletGetExtendedPublicKey(wallet.get(), TWPurposeBIP44, TWCoinTypeECash, TWHDVersionXPUB)); @@ -153,11 +151,18 @@ TEST(ECash, SignTransaction) { EXPECT_EQ(output.transaction().outputs(1).value(), 4325); EXPECT_EQ(output.encoded().length(), 226ul); ASSERT_EQ(hex(output.encoded()), - "01000000" - "01" - "e28c2b955293159898e34c6840d99bf4d390e2ee1c6f606939f18ee1e2000d05" "02000000" "6b483045022100b70d158b43cbcded60e6977e93f9a84966bc0cec6f2dfd1463d1223a90563f0d02207548d081069de570a494d0967ba388ff02641d91cadb060587ead95a98d4e3534121038eab72ec78e639d02758e7860cdec018b49498c307791f785aa3019622f4ea5b" "ffffffff" - "02" - "5802000000000000" "1976a914769bdff96a02f9135a1d19b749db6a78fe07dc9088ac" - "e510000000000000" "1976a9149e089b6889e032d46e3b915a3392edfd616fb1c488ac" - "00000000"); + "01000000" + "01" + "e28c2b955293159898e34c6840d99bf4d390e2ee1c6f606939f18ee1e2000d05" + "02000000" + "6b483045022100b70d158b43cbcded60e6977e93f9a84966bc0cec6f2dfd1463d1223a90563f0d02207548d081069de570a494d0967ba388ff02641d91cadb060587ead95a98d4e3534121038eab72ec78e639d02758e7860cdec018b49498c307791f785aa3019622f4ea5b" + "ffffffff" + "02" + "5802000000000000" + "1976a914769bdff96a02f9135a1d19b749db6a78fe07dc9088ac" + "e510000000000000" + "1976a9149e089b6889e032d46e3b915a3392edfd616fb1c488ac" + "00000000"); } + +} // namespace TW::Bitcoin diff --git a/tests/EOS/AssetTests.cpp b/tests/EOS/AssetTests.cpp index 979d54e2550..b697bea654b 100644 --- a/tests/EOS/AssetTests.cpp +++ b/tests/EOS/AssetTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,8 +9,7 @@ #include -using namespace TW; -using namespace TW::EOS; +namespace TW::EOS::tests { TEST(EOSAsset, Serialization) { Data buf; @@ -30,3 +29,5 @@ TEST(EOSAsset, Serialization) { // add tests for negative amounts, fractional amounts } + +} // namespace TW::EOS diff --git a/tests/EOS/NameTests.cpp b/tests/EOS/NameTests.cpp index 76cd5cb5e52..e9b64201926 100644 --- a/tests/EOS/NameTests.cpp +++ b/tests/EOS/NameTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,18 +6,16 @@ #include "EOS/Name.h" #include "HexCoding.h" -#include "PrivateKey.h" #include -using namespace TW; -using namespace TW::EOS; +namespace TW::EOS::tests { TEST(EOSName, Invalid) { ASSERT_THROW(Name(std::string(14, 'a')), std::invalid_argument); - std::string invalidNames[] = {"Alice", "alice16", "12345satoshis"}; - for(auto name: invalidNames) { + std::string invalidNames[] = {"Alice", "alice16", "12345satoshis"}; + for (auto name : invalidNames) { ASSERT_FALSE(Name(name).string() == name); } } @@ -30,4 +28,6 @@ TEST(EOSName, Valid) { Data buf; Name(validName).serialize(buf); ASSERT_EQ(hex(buf), "458608d8354cb3c1"); -} \ No newline at end of file +} + +} // namespace TW::EOS::tests \ No newline at end of file diff --git a/tests/EOS/SignatureTests.cpp b/tests/EOS/SignatureTests.cpp index 28bb3ee51a2..72f3fb85a2c 100644 --- a/tests/EOS/SignatureTests.cpp +++ b/tests/EOS/SignatureTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,23 +9,20 @@ #include -using namespace TW; -using namespace TW::EOS; +namespace TW::EOS::tests { TEST(EOSSignature, Serialization) { Data buf; - Signature *sig = new Signature(parse_hex("1f14262320d5b145220fb94d8fe204117edd25e52bbe9557b6e0909dd00307af266f5be1deef001446979523ac9de32c7eae5e5be4180b5a60c0e6bf14b2dd3e05"), Type::ModernK1); + Signature* sig = new Signature(parse_hex("1f14262320d5b145220fb94d8fe204117edd25e52bbe9557b6e0909dd00307af266f5be1deef001446979523ac9de32c7eae5e5be4180b5a60c0e6bf14b2dd3e05"), Type::ModernK1); sig->serialize(buf); ASSERT_EQ( hex(buf), - "001f14262320d5b145220fb94d8fe204117edd25e52bbe9557b6e0909dd00307af266f5be1deef001446979523ac9de32c7eae5e5be4180b5a60c0e6bf14b2dd3e05" - ); + "001f14262320d5b145220fb94d8fe204117edd25e52bbe9557b6e0909dd00307af266f5be1deef001446979523ac9de32c7eae5e5be4180b5a60c0e6bf14b2dd3e05"); ASSERT_EQ( sig->string(), - "SIG_K1_JwtfgsdSx5RuF5aejedQ7FJTexaKMrQyYosPUWUrU1mzdLx6JUgLTZJd7zWA8q8VdnXht3YmVt7jafmD2eEK7hTRpT9rY5" - ); + "SIG_K1_JwtfgsdSx5RuF5aejedQ7FJTexaKMrQyYosPUWUrU1mzdLx6JUgLTZJd7zWA8q8VdnXht3YmVt7jafmD2eEK7hTRpT9rY5"); delete sig; sig = new Signature(parse_hex("1f5c419d16f573ddbf07d2eb959621f690f9cb856ea2d113e3af02b3b40005488410e82ffa37a079e119844d213f4eb066a640507db68851752bea6e61eb864d84"), Type::ModernR1); @@ -34,15 +31,15 @@ TEST(EOSSignature, Serialization) { ASSERT_EQ( hex(buf), - "011f5c419d16f573ddbf07d2eb959621f690f9cb856ea2d113e3af02b3b40005488410e82ffa37a079e119844d213f4eb066a640507db68851752bea6e61eb864d84" - ); + "011f5c419d16f573ddbf07d2eb959621f690f9cb856ea2d113e3af02b3b40005488410e82ffa37a079e119844d213f4eb066a640507db68851752bea6e61eb864d84"); ASSERT_EQ( sig->string(), - "SIG_R1_K7KpdLYqa6ebCP22TuiYAY9YoJh1dTWTZEVkdPzdoadFL6f8PkMYk5N8wtsF11cneEJ91XnEZP6wDJHhRyqr1fr68ouYcz" - ); + "SIG_R1_K7KpdLYqa6ebCP22TuiYAY9YoJh1dTWTZEVkdPzdoadFL6f8PkMYk5N8wtsF11cneEJ91XnEZP6wDJHhRyqr1fr68ouYcz"); delete sig; ASSERT_THROW(sig = new Signature(parse_hex("1f5c419d16f573ddbf07d2eb959621f690f9cb856ea2d113e3af02b3b40005488410e82ffa37a079e119844d213f4eb066a640507db68851752bea6e61eb864d84"), Type::Legacy), std::invalid_argument); ASSERT_THROW(sig = new Signature(parse_hex("011f5c419d16f573ddbf07d2eb959621f690f9cb856ea2d113e3af02b3b40005488410e82ffa37a079e119844d213f4eb066a640507db68851752bea6e61eb864d84"), Type::ModernR1), std::invalid_argument); } + +} // namespace TW::EOS::tests \ No newline at end of file diff --git a/tests/EOS/TWAnySignerTests.cpp b/tests/EOS/TWAnySignerTests.cpp index 537ae52b042..ea9e2b2b237 100644 --- a/tests/EOS/TWAnySignerTests.cpp +++ b/tests/EOS/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,8 +11,7 @@ #include -using namespace TW; -using namespace TW::EOS; +namespace TW::EOS::tests { TEST(TWAnySignerEOS, Sign) { Proto::SigningInput input; @@ -51,3 +50,5 @@ TEST(TWAnySignerEOS, Sign) { EXPECT_TRUE(output.json_encoded().empty()); } } + +} // namespace TW::EOS::tests diff --git a/tests/Elrond/TransactionFactoryTests.cpp b/tests/Elrond/TransactionFactoryTests.cpp index c86777cb46d..8837d2cab6b 100644 --- a/tests/Elrond/TransactionFactoryTests.cpp +++ b/tests/Elrond/TransactionFactoryTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,13 +6,11 @@ #include #include -#include "boost/format.hpp" #include "Elrond/TransactionFactory.h" #include "TestAccounts.h" -using namespace TW; -using namespace TW::Elrond; +namespace TW::Elrond::tests { TEST(ElrondTransactionFactory, fromEGLDTransfer) { auto input = Proto::SigningInput(); @@ -109,7 +107,7 @@ TEST(ElrondTransactionFactory, createTransfersWithProvidedNetworkConfig) { Transaction tx1 = factory.fromEGLDTransfer(signingInputWithEGLDTransfer); Transaction tx2 = factory.fromESDTTransfer(signingInputWithESDTTransfer); Transaction tx3 = factory.fromESDTNFTTransfer(signingInputWithESDTNFTTransfer); - + ASSERT_EQ(60000ul, tx1.gasLimit); ASSERT_EQ(1500000000ul, tx1.gasPrice); ASSERT_EQ("T", tx1.chainID); @@ -143,7 +141,7 @@ TEST(ElrondTransactionFactory, createTransfersWithOverriddenNetworkParameters) { Transaction tx1 = factory.fromEGLDTransfer(signingInputWithEGLDTransfer); Transaction tx2 = factory.fromESDTTransfer(signingInputWithESDTTransfer); Transaction tx3 = factory.fromESDTNFTTransfer(signingInputWithESDTNFTTransfer); - + ASSERT_EQ(50500ul, tx1.gasLimit); ASSERT_EQ(1000000001ul, tx1.gasPrice); ASSERT_EQ("A", tx1.chainID); @@ -184,9 +182,11 @@ TEST(ElrondTransactionFactory, create) { Transaction tx2 = factory.create(signingInputWithEGLDTransfer); Transaction tx3 = factory.create(signingInputWithESDTTransfer); Transaction tx4 = factory.create(signingInputWithESDTNFTTransfer); - + ASSERT_EQ("hello", tx1.data); ASSERT_EQ("1", tx2.value); ASSERT_EQ("ESDTTransfer@4d59544f4b454e2d31323334@09184e72a000", tx3.data); ASSERT_EQ("ESDTNFTTransfer@4c4b4d45582d616162393130@04@028ec3dfa01ac000@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8", tx4.data); } + +} // namespace TW::Elrond::tests diff --git a/tests/Ethereum/AbiTests.cpp b/tests/Ethereum/AbiTests.cpp index 712364de657..598fc454f86 100644 --- a/tests/Ethereum/AbiTests.cpp +++ b/tests/Ethereum/AbiTests.cpp @@ -10,8 +10,7 @@ #include -using namespace TW; -using namespace TW::Ethereum::ABI; +namespace TW::Ethereum::ABI::tests { ///// Parameter types @@ -1643,3 +1642,5 @@ TEST(EthereumAbi, ParametersMethods) { EXPECT_FALSE(p.setValueJson("value")); EXPECT_EQ(hex(p.hashStruct()), "755311b9e2cee471a91b161ccc5deed933d844b5af2b885543cc3c04eb640983"); } + +} // namespace TW::Ethereum::ABI::tests diff --git a/tests/Ethereum/ContractCallTests.cpp b/tests/Ethereum/ContractCallTests.cpp index 22461161e54..f338581c242 100644 --- a/tests/Ethereum/ContractCallTests.cpp +++ b/tests/Ethereum/ContractCallTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,11 +10,10 @@ #include #include -using namespace TW; -using namespace TW::Ethereum::ABI; - extern std::string TESTS_ROOT; +namespace TW::Ethereum::ABI::tests { + static nlohmann::json load_json(std::string path) { std::ifstream stream(path); nlohmann::json json; @@ -174,8 +173,7 @@ TEST(ContractCall, GetAmountsOut) { "0000000000000000000000000000000000000000000000000000000000000064" "0000000000000000000000000000000000000000000000000000000000000040" "0000000000000000000000000000000000000000000000000000000000000001" - "000000000000000000000000f784682c82526e245f50975190ef0fff4e4fc077" - ); + "000000000000000000000000f784682c82526e245f50975190ef0fff4e4fc077"); auto path = TESTS_ROOT + "/Ethereum/Data/getAmountsOut.json"; auto abi = load_json(path); @@ -192,8 +190,7 @@ TEST(ContractCall, 1inch) { // https://etherscan.io/tx/0xc2d113151124579c21332d4cc6ab2b7f61e81d62392ed8596174513cb47e35ba auto call = parse_hex( - "7c02520000000000000000000000000027239549dd40e1d60f5b80b0c4196923745b1fd2000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001800000000000000000000000002b591e99afe9f32eaa6214f7b7629768c40eeb39000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000027239549dd40e1d60f5b80b0c4196923745b1fd20000000000000000000000001611c227725c5e420ef058275ae772b41775e261000000000000000000000000000000000000000000000000000005d0fadb1c0000000000000000000000000000000000000000000000000000000005c31df1da000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002080000000000000000000000069d91b94f0aaf8e8a2586909fa77a5c2c89818d50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000104128acb080000000000000000000000001611c227725c5e420ef058275ae772b41775e2610000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000005d0fadb1c0000000000000000000000000000000000000000000000000000000001000276a400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000002b591e99afe9f32eaa6214f7b7629768c40eeb39000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000" - ); + "7c02520000000000000000000000000027239549dd40e1d60f5b80b0c4196923745b1fd2000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001800000000000000000000000002b591e99afe9f32eaa6214f7b7629768c40eeb39000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000027239549dd40e1d60f5b80b0c4196923745b1fd20000000000000000000000001611c227725c5e420ef058275ae772b41775e261000000000000000000000000000000000000000000000000000005d0fadb1c0000000000000000000000000000000000000000000000000000000005c31df1da000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002080000000000000000000000069d91b94f0aaf8e8a2586909fa77a5c2c89818d50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000104128acb080000000000000000000000001611c227725c5e420ef058275ae772b41775e2610000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000005d0fadb1c0000000000000000000000000000000000000000000000000000000001000276a400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000002b591e99afe9f32eaa6214f7b7629768c40eeb39000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000"); auto decoded = decodeCall(call, abi); ASSERT_TRUE(decoded.has_value()); auto expected = @@ -212,11 +209,12 @@ TEST(ContractCall, TupleNested) { "0000000000000000000000000000000000000000000000000000000000000003" "0000000000000000000000000000000000000000000000000000000000000004" "0000000000000000000000000000000000000000000000000000000000000005" - "0000000000000000000000000000000000000000000000000000000000000001" - ); + "0000000000000000000000000000000000000000000000000000000000000001"); auto decoded = decodeCall(call, abi); ASSERT_TRUE(decoded.has_value()); auto expected = R"|({"function":"nested_tuple(uint16,(uint16,(uint16,uint64),uint32),bool)","inputs":[{"name":"param1","type":"uint16","value":"1"},{"components":[{"name":"param21","type":"uint16","value":"2"},{"components":[{"name":"param221","type":"uint16","value":"3"},{"name":"param222","type":"uint64","value":"4"}],"name":"param22","type":"tuple"},{"name":"param23","type":"uint32","value":"5"}],"name":"param2","type":"tuple"},{"name":"param3","type":"bool","value":true}]})|"; EXPECT_EQ(decoded.value(), expected); } + +} // namespace TW::Ethereum::ABI::tests diff --git a/tests/Ethereum/RLPTests.cpp b/tests/Ethereum/RLPTests.cpp index 34e76bf6cc8..52b01b75de4 100644 --- a/tests/Ethereum/RLPTests.cpp +++ b/tests/Ethereum/RLPTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,23 +9,25 @@ #include -using namespace TW; -using namespace TW::Ethereum; +namespace TW::Ethereum::tests { + using boost::multiprecision::uint256_t; std::string stringifyItems(const RLP::DecodedItem& di); std::string stringifyData(const Data& data) { - if (data.size() == 0) return "0"; + if (data.size() == 0) + return "0"; // try if only letters bool isLettersOnly = true; - for(auto i: data) { + for (auto i : data) { if (!((i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z') || i == ' ' || i == ',')) { isLettersOnly = false; break; } } - if (isLettersOnly) return std::string("'") + std::string(data.begin(), data.end()) + "'"; + if (isLettersOnly) + return std::string("'") + std::string(data.begin(), data.end()) + "'"; // try if it can be parsed (recursive) if (data.size() >= 2) { try { @@ -33,7 +35,8 @@ std::string stringifyData(const Data& data) { if (di.decoded.size() > 0 && di.remainder.size() == 0) { return stringifyItems(di); } - } catch (...) {} + } catch (...) { + } } // any other: as hex string return hex(data); @@ -49,8 +52,9 @@ std::string stringifyItems(const RLP::DecodedItem& di) { } std::string res = "(" + std::to_string(n) + ": "; int count = 0; - for(auto i: di.decoded) { - if (count++) res += " "; + for (auto i : di.decoded) { + if (count++) + res += " "; res += stringifyData(i); } res += ")"; @@ -95,16 +99,13 @@ TEST(RLP, EncodeUInt256) { EXPECT_EQ(hex(RLP::encode(uint256_t(0xffffffffffffffULL))), "87ffffffffffffff"); EXPECT_EQ( hex(RLP::encode(uint256_t("0x102030405060708090a0b0c0d0e0f2"))), - "8f102030405060708090a0b0c0d0e0f2" - ); + "8f102030405060708090a0b0c0d0e0f2"); EXPECT_EQ( hex(RLP::encode(uint256_t("0x0100020003000400050006000700080009000a000b000c000d000e01"))), - "9c0100020003000400050006000700080009000a000b000c000d000e01" - ); + "9c0100020003000400050006000700080009000a000b000c000d000e01"); EXPECT_EQ( hex(RLP::encode(uint256_t("0x0100000000000000000000000000000000000000000000000000000000000000"))), - "a00100000000000000000000000000000000000000000000000000000000000000" - ); + "a00100000000000000000000000000000000000000000000000000000000000000"); } TEST(RLP, EncodeList) { @@ -161,7 +162,7 @@ TEST(RLP, DecodeString) { EXPECT_EQ(decodeHelper("a00100000000000000000000000000000000000000000000000000000000000000"), "0100000000000000000000000000000000000000000000000000000000000000"); // long string EXPECT_EQ(decodeHelper("b87674686973206973206120612076657279206c6f6e6720737472696e672c2074686973206973206120612076657279206c6f6e6720737472696e672c2074686973206973206120612076657279206c6f6e6720737472696e672c2074686973206973206120612076657279206c6f6e6720737472696e67"), - "'this is a a very long string, this is a a very long string, this is a a very long string, this is a a very long string'"); + "'this is a a very long string, this is a a very long string, this is a a very long string, this is a a very long string'"); } TEST(RLP, DecodeList) { @@ -174,40 +175,39 @@ TEST(RLP, DecodeList) { // long list, raw ether transfer tx EXPECT_EQ(decodeHelper("f86b81a985051f4d5ce982520894515778891c99e3d2e7ae489980cb7c77b37b5e76861b48eb57e0008025a0ad01c32a7c974df9d0bd48c8d7e0ecab62e90811917aa7dc0c966751a0c3f475a00dc77d9ec68484481bdf87faac14378f4f18d477f84c0810d29480372c1bbc65"), - "(9: " - "a9 " // nonce - "051f4d5ce9 " // gas price - "5208 " // gas limit - "515778891c99e3d2e7ae489980cb7c77b37b5e76 " // to - "1b48eb57e000 " // amount - "0 " // data - "25 " // v - "ad01c32a7c974df9d0bd48c8d7e0ecab62e90811917aa7dc0c966751a0c3f475 " // r - "0dc77d9ec68484481bdf87faac14378f4f18d477f84c0810d29480372c1bbc65" // s - ")" - ); + "(9: " + "a9 " // nonce + "051f4d5ce9 " // gas price + "5208 " // gas limit + "515778891c99e3d2e7ae489980cb7c77b37b5e76 " // to + "1b48eb57e000 " // amount + "0 " // data + "25 " // v + "ad01c32a7c974df9d0bd48c8d7e0ecab62e90811917aa7dc0c966751a0c3f475 " // r + "0dc77d9ec68484481bdf87faac14378f4f18d477f84c0810d29480372c1bbc65" // s + ")"); // long list, raw token transfer tx EXPECT_EQ(decodeHelper("f8aa81d485077359400082db9194dac17f958d2ee523a2206206994597c13d831ec780b844a9059cbb000000000000000000000000c6b6b55c8c4971145a842cc4e5db92d879d0b3e00000000000000000000000000000000000000000000000000000000002faf0801ca02843d8ed66b9623392dc336dd36d5dd5a630b2019962869b6e50fdb4ecb5b6aca05d9ea377bc65e2921f7fc257de8135530cc74e3188b6ba57a4b9cb284393050a"), - "(9: " - "d4 " - "0773594000 " - "db91 " - "dac17f958d2ee523a2206206994597c13d831ec7 " - "0 " - "a9059cbb000000000000000000000000c6b6b55c8c4971145a842cc4e5db92d879d0b3e00000000000000000000000000000000000000000000000000000000002faf080 " - "1c " - "2843d8ed66b9623392dc336dd36d5dd5a630b2019962869b6e50fdb4ecb5b6ac " - "5d9ea377bc65e2921f7fc257de8135530cc74e3188b6ba57a4b9cb284393050a" - ")" - ); + "(9: " + "d4 " + "0773594000 " + "db91 " + "dac17f958d2ee523a2206206994597c13d831ec7 " + "0 " + "a9059cbb000000000000000000000000c6b6b55c8c4971145a842cc4e5db92d879d0b3e00000000000000000000000000000000000000000000000000000000002faf080 " + "1c " + "2843d8ed66b9623392dc336dd36d5dd5a630b2019962869b6e50fdb4ecb5b6ac " + "5d9ea377bc65e2921f7fc257de8135530cc74e3188b6ba57a4b9cb284393050a" + ")"); { // long list, with 2-byte size const std::string elem = "0123"; const std::size_t n = 500; std::vector longarr; - for (auto i = 0ul; i < n; ++i) longarr.push_back(elem); + for (auto i = 0ul; i < n; ++i) + longarr.push_back(elem); const Data encoded = RLP::encodeList(longarr); ASSERT_EQ(hex(subData(encoded, 0, 20)), "f909c48430313233843031323384303132338430"); @@ -223,7 +223,8 @@ TEST(RLP, DecodeList) { const std::string elem = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; const std::size_t n = 650; std::vector longarr; - for (auto i = 0ul; i < n; ++i) longarr.push_back(elem); + for (auto i = 0ul; i < n; ++i) + longarr.push_back(elem); const Data encoded = RLP::encodeList(longarr); ASSERT_EQ(encoded.size(), 66304ul); @@ -235,7 +236,7 @@ TEST(RLP, DecodeList) { // nested list EXPECT_EQ(decodeHelper("f8479cdb84c301020395d4856170706c658662616e616e6186636865727279a9e890cf83abcdef8a0001020304050607080996d587626974636f696e88626565656e62656583657468"), - "(2: (2: (3: 01 02 03) (3: 'apple' 'banana' 'cherry')) (2: (2: abcdef 00010203040506070809) (3: 'bitcoin' 'beeenbee' 'eth')))"); + "(2: (2: (3: 01 02 03) (3: 'apple' 'banana' 'cherry')) (2: (2: abcdef 00010203040506070809) (3: 'bitcoin' 'beeenbee' 'eth')))"); } TEST(RLP, DecodeInvalid) { @@ -295,9 +296,11 @@ TEST(RLP, parseVarInt) { EXPECT_EQ(hex(store(RLP::parseVarInt(7, parse_hex("01020304050607"), 0))), "01020304050607"); EXPECT_EQ(hex(store(RLP::parseVarInt(8, parse_hex("0102030405060708"), 0))), "0102030405060708"); EXPECT_EQ(hex(store(RLP::parseVarInt(8, parse_hex("abcd0102030405060708"), 2))), "0102030405060708"); - EXPECT_THROW(RLP::parseVarInt(0, parse_hex("01"), 0), std::invalid_argument); // wrong size + EXPECT_THROW(RLP::parseVarInt(0, parse_hex("01"), 0), std::invalid_argument); // wrong size EXPECT_THROW(RLP::parseVarInt(9, parse_hex("010203040506070809"), 0), std::invalid_argument); // wrong size - EXPECT_THROW(RLP::parseVarInt(4, parse_hex("0102"), 0), std::invalid_argument); // too short - EXPECT_THROW(RLP::parseVarInt(4, parse_hex("01020304"), 2), std::invalid_argument); // too short - EXPECT_THROW(RLP::parseVarInt(2, parse_hex("0002"), 0), std::invalid_argument); // starts with 0 + EXPECT_THROW(RLP::parseVarInt(4, parse_hex("0102"), 0), std::invalid_argument); // too short + EXPECT_THROW(RLP::parseVarInt(4, parse_hex("01020304"), 2), std::invalid_argument); // too short + EXPECT_THROW(RLP::parseVarInt(2, parse_hex("0002"), 0), std::invalid_argument); // starts with 0 } + +} // namespace TW::Ethereum::tests diff --git a/tests/Ethereum/TWAnySignerTests.cpp b/tests/Ethereum/TWAnySignerTests.cpp index f822ae9e888..727966fa8d8 100644 --- a/tests/Ethereum/TWAnySignerTests.cpp +++ b/tests/Ethereum/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -15,9 +15,7 @@ #include -using namespace TW; -using namespace TW::Ethereum; -using namespace TW::Ethereum::ABI; +namespace TW::Ethereum { TEST(TWEthereumSigner, EmptyValue) { auto str = std::string(""); @@ -80,7 +78,7 @@ TEST(TWAnySignerEthereum, SignERC20TransferAsERC20) { auto chainId = store(uint256_t(1)); auto nonce = store(uint256_t(0)); auto gasPrice = store(uint256_t(42000000000)); // 0x09c7652400 - auto gasLimit = store(uint256_t(78009)); // 130B9 + auto gasLimit = store(uint256_t(78009)); // 130B9 auto toAddress = "0x5322b34c88ed0691971bf52a7047448f0f4efc84"; auto token = "0x6b175474e89094c44da98b954eedeac495271d0f"; // DAI auto amount = uint256_t(2000000000000000000); @@ -111,10 +109,9 @@ TEST(TWAnySignerEthereum, SignERC20TransferAsERC20) { // expected payload Data payload; { - auto func = Function("transfer", std::vector>{ - std::make_shared(parse_hex(toAddress)), - std::make_shared(amount) - }); + auto func = ABI::Function("transfer", std::vector>{ + std::make_shared(parse_hex(toAddress)), + std::make_shared(amount)}); func.encode(payload); } ASSERT_EQ(hex(output.data()), hex(payload)); @@ -124,8 +121,8 @@ TEST(TWAnySignerEthereum, SignERC20TransferAsERC20) { TEST(TWAnySignerEthereum, SignERC20TransferAsGenericContract) { auto chainId = store(uint256_t(1)); auto nonce = store(uint256_t(0)); - auto gasPrice = store(uint256_t(42000000000)); // 0x09c7652400 - auto gasLimit = store(uint256_t(78009)); // 130B9 + auto gasPrice = store(uint256_t(42000000000)); // 0x09c7652400 + auto gasLimit = store(uint256_t(78009)); // 130B9 auto toAddress = "0x6b175474e89094c44da98b954eedeac495271d0f"; // DAI // payload: transfer(0x5322b34c88ed0691971bf52a7047448f0f4efc84, 2000000000000000000) auto data = parse_hex("0xa9059cbb0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000001bc16d674ec80000"); @@ -157,7 +154,7 @@ TEST(TWAnySignerEthereum, SignERC20TransferInvalidAddress) { auto chainId = store(uint256_t(1)); auto nonce = store(uint256_t(0)); auto gasPrice = store(uint256_t(42000000000)); // 0x09c7652400 - auto gasLimit = store(uint256_t(78009)); // 130B9 + auto gasLimit = store(uint256_t(78009)); // 130B9 auto invalidAddress = "0xdeadbeef"; auto amount = store(uint256_t(2000000000000000000)); auto key = parse_hex("0x608dcb1742bb3fb7aec002074e3420e4fab7d00cced79ccdac53ed5b27138151"); @@ -185,7 +182,7 @@ TEST(TWAnySignerEthereum, SignERC20Approve) { auto chainId = store(uint256_t(1)); auto nonce = store(uint256_t(0)); auto gasPrice = store(uint256_t(42000000000)); // 0x09c7652400 - auto gasLimit = store(uint256_t(78009)); // 130B9 + auto gasLimit = store(uint256_t(78009)); // 130B9 auto spenderAddress = "0x5322b34c88ed0691971bf52a7047448f0f4efc84"; auto token = "0x6b175474e89094c44da98b954eedeac495271d0f"; // DAI auto amount = store(uint256_t(2000000000000000000)); @@ -286,13 +283,12 @@ TEST(TWAnySignerEthereum, SignERC1155Transfer) { // expected payload Data payload; { - auto func = Function("safeTransferFrom", std::vector>{ - std::make_shared(parse_hex(fromAddress)), - std::make_shared(parse_hex(toAddress)), - std::make_shared(uint256_t(0x23c47ee5)), - std::make_shared(value), - std::make_shared(data) - }); + auto func = ABI::Function("safeTransferFrom", std::vector>{ + std::make_shared(parse_hex(fromAddress)), + std::make_shared(parse_hex(toAddress)), + std::make_shared(uint256_t(0x23c47ee5)), + std::make_shared(value), + std::make_shared(data)}); func.encode(payload); } ASSERT_EQ(hex(output.data()), hex(payload)); @@ -312,7 +308,7 @@ TEST(TWAnySignerEthereum, PlanNotSupported) { // Ethereum does not use plan(), call it nonetheless Proto::SigningInput input; auto inputData = input.SerializeAsString(); - auto inputTWData = WRAPD(TWDataCreateWithBytes((const uint8_t *)inputData.data(), inputData.size())); + auto inputTWData = WRAPD(TWDataCreateWithBytes((const uint8_t*)inputData.data(), inputData.size())); auto outputTWData = WRAPD(TWAnySignerPlan(inputTWData.get(), TWCoinTypeEthereum)); EXPECT_EQ(TWDataSize(outputTWData.get()), 0ul); } @@ -358,9 +354,9 @@ TEST(TWAnySignerEthereum, SignERC1559Transfer_1442) { TEST(TWAnySignerEthereum, SignERC20Transfer_1559) { auto chainId = store(uint256_t(1)); auto nonce = store(uint256_t(0)); - auto gasLimit = store(uint256_t(78009)); // 130B9 + auto gasLimit = store(uint256_t(78009)); // 130B9 auto maxInclusionFeePerGas = store(uint256_t(2000000000)); // 77359400 - auto maxFeePerGas = store(uint256_t(3000000000)); // B2D05E00 + auto maxFeePerGas = store(uint256_t(3000000000)); // B2D05E00 auto toAddress = "0x5322b34c88ed0691971bf52a7047448f0f4efc84"; auto token = "0x6b175474e89094c44da98b954eedeac495271d0f"; // DAI auto amount = uint256_t(2000000000000000000); @@ -488,3 +484,5 @@ TEST(TWAnySignerEthereum, SignERC1155Transfer_1559) { ASSERT_EQ(hex(output.encoded()), "02f901500180847735940084b2d05e00830130b9944e45e92ed38f885d39a733c14f1817217a89d42580b8e4f242432a000000000000000000000000718046867b5b1782379a14ea4fc0c9b724da94fc0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000000000000023c47ee50000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000c080a0533df41dda5540c57257b7fe89c29cefff0155c333e063220df2bf9680fcc15aa036a844fd20de5a51de96ceaaf078558e87d86426a4a5d4b215ee1fd0fa397f8a"); } + +} // namespace TW::Ethereum diff --git a/tests/Ethereum/ValueDecoderTests.cpp b/tests/Ethereum/ValueDecoderTests.cpp index fa459be1dcc..c576971e9d4 100644 --- a/tests/Ethereum/ValueDecoderTests.cpp +++ b/tests/Ethereum/ValueDecoderTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,8 +9,7 @@ #include -using namespace TW; -using namespace TW::Ethereum; +namespace TW::Ethereum::tests { uint256_t decodeFromHex(std::string s) { auto data = parse_hex(s); @@ -31,12 +30,12 @@ TEST(EthereumAbiValueDecoder, decodeValue) { EXPECT_EQ("24", ABI::ValueDecoder::decodeValue(parse_hex("0000000000000000000000000000000000000000000000000000000000000018"), "uint8")); EXPECT_EQ("123456", ABI::ValueDecoder::decodeValue(parse_hex("000000000000000000000000000000000000000000000000000000000001e240"), "uint256")); EXPECT_EQ("0xf784682c82526e245f50975190ef0fff4e4fc077", ABI::ValueDecoder::decodeValue(parse_hex("000000000000000000000000f784682c82526e245f50975190ef0fff4e4fc077"), "address")); - EXPECT_EQ("Hello World! Hello World! Hello World!", - ABI::ValueDecoder::decodeValue(parse_hex( - "000000000000000000000000000000000000000000000000000000000000002c" - "48656c6c6f20576f726c64212020202048656c6c6f20576f726c642120202020" - "48656c6c6f20576f726c64210000000000000000000000000000000000000000" - ), "string")); + EXPECT_EQ("Hello World! Hello World! Hello World!", + ABI::ValueDecoder::decodeValue(parse_hex( + "000000000000000000000000000000000000000000000000000000000000002c" + "48656c6c6f20576f726c64212020202048656c6c6f20576f726c642120202020" + "48656c6c6f20576f726c64210000000000000000000000000000000000000000"), + "string")); EXPECT_EQ("0x31323334353637383930", ABI::ValueDecoder::decodeValue(parse_hex("3132333435363738393000000000000000000000000000000000000000000000"), "bytes10")); } @@ -47,8 +46,7 @@ TEST(EthereumAbiValueDecoder, decodeArray) { "0000000000000000000000000000000000000000000000000000000000000003" "0000000000000000000000000000000000000000000000000000000000000031" "0000000000000000000000000000000000000000000000000000000000000032" - "0000000000000000000000000000000000000000000000000000000000000033" - ); + "0000000000000000000000000000000000000000000000000000000000000033"); auto res = ABI::ValueDecoder::decodeArray(input, "uint8[]"); EXPECT_EQ(3ul, res.size()); EXPECT_EQ("49", res[0]); @@ -60,8 +58,7 @@ TEST(EthereumAbiValueDecoder, decodeArray) { Data input = parse_hex( "0000000000000000000000000000000000000000000000000000000000000002" "000000000000000000000000f784682c82526e245f50975190ef0fff4e4fc077" - "0000000000000000000000002e00cd222cb42b616d86d037cc494e8ab7f5c9a3" - ); + "0000000000000000000000002e00cd222cb42b616d86d037cc494e8ab7f5c9a3"); auto res = ABI::ValueDecoder::decodeArray(input, "address[]"); EXPECT_EQ(2ul, res.size()); EXPECT_EQ("0xf784682c82526e245f50975190ef0fff4e4fc077", res[0]); @@ -76,11 +73,12 @@ TEST(EthereumAbiValueDecoder, decodeArray) { "0000000000000000000000000000000000000000000000000000000000000002" "1011000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000000003" - "1022220000000000000000000000000000000000000000000000000000000000" - ); + "1022220000000000000000000000000000000000000000000000000000000000"); auto res = ABI::ValueDecoder::decodeArray(input, "bytes[]"); EXPECT_EQ(2ul, res.size()); EXPECT_EQ("0x1011", res[0]); EXPECT_EQ("0x102222", res[1]); } } + +} // namespace TW::Ethereum::tests diff --git a/tests/Ethereum/ValueEncoderTests.cpp b/tests/Ethereum/ValueEncoderTests.cpp index 28a663aef58..29a621d2a05 100644 --- a/tests/Ethereum/ValueEncoderTests.cpp +++ b/tests/Ethereum/ValueEncoderTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,14 +9,12 @@ #include -using namespace TW; -using namespace TW::Ethereum; - -Data data; +namespace TW::Ethereum::tests { void checkLast32BytesEqual(const Data& data, const char* expected) { EXPECT_EQ(hex(subData(data, data.size() - 32, 32)), expected); } + TEST(EthereumAbiValueEncoder, encodeBool) { Data data; ABI::ValueEncoder::encodeBool(false, data); @@ -134,3 +132,5 @@ TEST(EthereumAbiValueEncoder, pad32) { EXPECT_EQ(0ul, ABI::ValueEncoder::padNeeded32(64)); EXPECT_EQ(31ul, ABI::ValueEncoder::padNeeded32(65)); } + +} // namespace TW::Ethereum::tests diff --git a/tests/FIO/AddressTests.cpp b/tests/FIO/AddressTests.cpp index df478710d40..aea76097f2e 100644 --- a/tests/FIO/AddressTests.cpp +++ b/tests/FIO/AddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,8 +11,7 @@ #include -using namespace TW; -using namespace TW::FIO; +namespace TW::FIO::tests { TEST(FIOAddress, ValidateString) { ASSERT_FALSE(Address::isValid("abc")); @@ -64,3 +63,5 @@ TEST(FIOAddress, GetPublicKey) { auto address = Address(publicKey); EXPECT_EQ(hex(address.publicKey().bytes), publicKeyHex); } + +} // namespace TW::FIO::tests diff --git a/tests/FIO/EncryptionTests.cpp b/tests/FIO/EncryptionTests.cpp index 75f7f009401..3fc2171ce40 100644 --- a/tests/FIO/EncryptionTests.cpp +++ b/tests/FIO/EncryptionTests.cpp @@ -15,8 +15,8 @@ #include -using namespace TW; -using namespace TW::FIO; +namespace TW::FIO::tests { + using namespace std; TEST(FIOEncryption, checkEncrypt) { @@ -24,7 +24,7 @@ TEST(FIOEncryption, checkEncrypt) { const Data secret = parse_hex("02332627b9325cb70510a70f0f6be4bcb008fbbc7893ca51dedf5bf46aa740c0fc9d3fbd737d09a3c4046d221f4f1a323f515332c3fef46e7f075db561b1a2c9"); const Data plaintext = TW::data("secret message"); Data iv = parse_hex("f300888ca4f512cebdc0020ff0f7224c"); - + Data result = Encryption::checkEncrypt(secret, plaintext, iv); EXPECT_EQ(hex(result), "f300888ca4f512cebdc0020ff0f7224c7f896315e90e172bed65d005138f224da7301d5563614e3955750e4480aabf7753f44b4975308aeb8e23c31e114962ab"); } @@ -34,7 +34,7 @@ TEST(FIOEncryption, checkDecrypt) { const Data secret = parse_hex("02332627b9325cb70510a70f0f6be4bcb008fbbc7893ca51dedf5bf46aa740c0fc9d3fbd737d09a3c4046d221f4f1a323f515332c3fef46e7f075db561b1a2c9"); const Data encrypted = parse_hex("f300888ca4f512cebdc0020ff0f7224c7f896315e90e172bed65d005138f224da7301d5563614e3955750e4480aabf7753f44b4975308aeb8e23c31e114962ab"); const Data expectedPlaintext = TW::data("secret message"); - + Data result = Encryption::checkDecrypt(secret, encrypted); EXPECT_EQ(hex(result), hex(expectedPlaintext)); } @@ -53,7 +53,7 @@ TEST(FIOEncryption, checkEncryptInvalidIvLength) { TEST(FIOEncryption, checkDecryptInvalidMessageHMAC) { const Data secret = parse_hex("02332627b9325cb70510a70f0f6be4bcb008fbbc7893ca51dedf5bf46aa740c0fc9d3fbd737d09a3c4046d221f4f1a323f515332c3fef46e7f075db561b1a2c9"); const Data encrypted = parse_hex("f300888ca4f512cebdc0020ff0f7224c7f896315e90e172bed65d005138f224da7301d5563614e3955750e4480aabf7753f44b4975308aeb8e23c31e114962ab00"); - try { + try { Encryption::checkDecrypt(secret, encrypted); } catch (std::invalid_argument&) { // expected exception, OK @@ -64,7 +64,7 @@ TEST(FIOEncryption, checkDecryptInvalidMessageHMAC) { TEST(FIOEncryption, checkDecryptMessageTooShort) { const Data secret = parse_hex("02332627b9325cb70510a70f0f6be4bcb008fbbc7893ca51dedf5bf46aa740c0fc9d3fbd737d09a3c4046d221f4f1a323f515332c3fef46e7f075db561b1a2c9"); - try { + try { Encryption::checkDecrypt(secret, Data(60)); } catch (std::invalid_argument&) { // expected exception, OK @@ -170,7 +170,7 @@ TEST(FIOEncryption, encryptEncodeDecodeDecrypt) { EXPECT_EQ(addressBob.string(), "FIO5VE6Dgy9FUmd1mFotXwF88HkQN1KysCWLPqpVnDMjRvGRi1YrM"); const Data message = parse_hex("0b70757273652e616c69636501310a66696f2e7265716f6274000000"); const Data iv = parse_hex("f300888ca4f512cebdc0020ff0f7224c"); - + const Data encrypted = Encryption::encrypt(privateKeyAlice, publicKeyBob, message, iv); EXPECT_EQ(hex(encrypted), "f300888ca4f512cebdc0020ff0f7224c0db2984c4ad9afb12629f01a8c6a76328bbde17405655dc4e3cb30dad272996fb1dea8e662e640be193e25d41147a904c571b664a7381ab41ef062448ac1e205"); const string encoded = Encryption::encode(encrypted); @@ -182,3 +182,5 @@ TEST(FIOEncryption, encryptEncodeDecodeDecrypt) { // verify that decrypted is the same as the original EXPECT_EQ(hex(decrypted), hex(message)); } + +} // namespace TW::FIO::tests diff --git a/tests/FIO/SignerTests.cpp b/tests/FIO/SignerTests.cpp index cdf1277a11b..e85ab9422d5 100644 --- a/tests/FIO/SignerTests.cpp +++ b/tests/FIO/SignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,19 +7,19 @@ #include "FIO/Actor.h" #include "FIO/Signer.h" -#include "HexCoding.h" -#include "Hash.h" #include "Base58.h" +#include "Hash.h" +#include "HexCoding.h" #include -using namespace TW; -using namespace TW::FIO; -using namespace std; +namespace TW::FIO::tests { +using namespace std; TEST(FIOSigner, SignEncode) { - string sig1 = Signer::signatureToBsase58(parse_hex("1f4fccc30bcba876963aef6de584daf7258306c02f4528fe25b116b517de8b349968bdc080cd6bef36f5a46d31a7c01ed0806ad215bb66a94f61e27a895d610983"));; + string sig1 = Signer::signatureToBsase58(parse_hex("1f4fccc30bcba876963aef6de584daf7258306c02f4528fe25b116b517de8b349968bdc080cd6bef36f5a46d31a7c01ed0806ad215bb66a94f61e27a895d610983")); + EXPECT_EQ("SIG_K1_K5hJTPeiV4bDkNR13mf66N2DY5AtVL4NU1iWE4G4dsczY2q68oCcUVxhzFdxjgV2eAeb2jNV1biqtCJ3SaNL8kkNgoZ43H", sig1); } @@ -74,3 +74,5 @@ TEST(FIOSigner, Actor) { EXPECT_EQ(actorArr[i], actor); } } + +} // namespace TW::FIO::tests diff --git a/tests/FIO/TWFIOTests.cpp b/tests/FIO/TWFIOTests.cpp index 932d96d3674..790320b054f 100644 --- a/tests/FIO/TWFIOTests.cpp +++ b/tests/FIO/TWFIOTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -16,10 +16,9 @@ #include -using namespace TW; -using namespace TW::FIO; -using namespace std; +namespace TW::FIO::tests { +using namespace std; TEST(TWFIO, Address) { auto privateKey = WRAP(TWPrivateKey, TWPrivateKeyCreateWithData(DATA("ba0828d5734b65e3bcc2c51c93dfc26dd71bd666cc0273adee77d73d9a322035").get())); @@ -151,6 +150,7 @@ TEST(TWFIO, NewFundsRequest) { // Therefore full equality cannot be checked, tail is cut off. The first N chars are checked, works in this case. EXPECT_EQ( R"({"compression":"none","packed_context_free_data":"","packed_trx":"289b295ec99b904215ff000000000100403ed4aa0ba85b00acba384dbdb89a01102b2f46fca756b200000000a8ed32328802106d6172696f4066696f746573746)", - output.json().substr(0, 195) - ); + output.json().substr(0, 195)); } + +} // namespace TW::FIO::tests diff --git a/tests/FIO/TransactionBuilderTests.cpp b/tests/FIO/TransactionBuilderTests.cpp index e1d2945f1e3..dd0a08581f5 100644 --- a/tests/FIO/TransactionBuilderTests.cpp +++ b/tests/FIO/TransactionBuilderTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -13,15 +13,10 @@ #include "HexCoding.h" #include - -#include #include -using namespace TW; -using namespace TW::FIO; -using namespace std; - namespace TW::FIO::tests { +using namespace std; const Data chainId = parse_hex("4e46572250454b796d7296eec9e8896327ea82dd40f2cd74cf1b1d8ba90bcd77"); // 5KEDWtAUJcFX6Vz38WXsAQAv2geNqT7UaZC8gYu9kTuryr3qkri FIO6m1fMdTpRkRBnedvYshXCxLFiC5suRU8KDfx8xxtXp2hntxpnf diff --git a/tests/Groestlcoin/AddressTests.cpp b/tests/Groestlcoin/AddressTests.cpp index d3910b6c382..a07719aaa0c 100644 --- a/tests/Groestlcoin/AddressTests.cpp +++ b/tests/Groestlcoin/AddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,8 +12,7 @@ #include -using namespace TW; -using namespace TW::Groestlcoin; +namespace TW::Groestlcoin::tests { TEST(GroestlcoinAddress, FromPublicKey) { const auto publicKey = PublicKey(parse_hex("03b85cc59b67c35851eb5060cfc3a759a482254553c5857075c9e247d74d412c91"), TWPublicKeyTypeSECP256k1); @@ -43,3 +42,5 @@ TEST(GroestlcoinAddress, Derive) { const auto address = TW::deriveAddress(TWCoinTypeGroestlcoin, wallet.getKey(TWCoinTypeGroestlcoin, path)); ASSERT_EQ(address, "grs1qw4teyraux2s77nhjdwh9ar8rl9dt7zww8r6lne"); } + +} // namespace TW::Groestlcoin::tests diff --git a/tests/Groestlcoin/TWGroestlcoinSigningTests.cpp b/tests/Groestlcoin/TWGroestlcoinSigningTests.cpp index 7e81ec429b1..b2c7127d6e5 100644 --- a/tests/Groestlcoin/TWGroestlcoinSigningTests.cpp +++ b/tests/Groestlcoin/TWGroestlcoinSigningTests.cpp @@ -4,7 +4,6 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Bitcoin/OutPoint.h" #include "Bitcoin/Script.h" #include "Hash.h" #include "HexCoding.h" @@ -12,8 +11,6 @@ #include "proto/Bitcoin.pb.h" #include "../interface/TWTestUtilities.h" #include "../Bitcoin/TxComparisonHelper.h" - -#include #include #include #include @@ -21,8 +18,7 @@ #include -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { TEST(GroestlcoinSigning, SignP2WPKH) { Proto::SigningInput input; @@ -187,3 +183,5 @@ TEST(GroestlcoinSigning, PlanP2WPKH) { EXPECT_TRUE(verifyPlan(plan, {4774}, 2500, 145)); EXPECT_EQ(plan.branch_id(), ""); } + +} // namespace TW::Bitcoin diff --git a/tests/IoTeX/StakingTests.cpp b/tests/IoTeX/StakingTests.cpp index fd0e074d312..8a2008b1908 100644 --- a/tests/IoTeX/StakingTests.cpp +++ b/tests/IoTeX/StakingTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,16 +6,13 @@ #include "Data.h" #include "HexCoding.h" -#include "IoTeX/Signer.h" #include "IoTeX/Staking.h" -#include "PrivateKey.h" #include "proto/IoTeX.pb.h" #include "../interface/TWTestUtilities.h" #include #include -using namespace TW; -using namespace TW::IoTeX; +namespace TW::IoTeX::tests { TEST(TWIoTeXStaking, Create) { std::string IOTEX_STAKING_CANDIDATE = "io19d0p3ah4g8ww9d7kcxfq87yxe7fnr8rpth5shj"; @@ -131,8 +128,7 @@ TEST(TWIoTeXStaking, CandidateUpdate) { "326e756b7034766763776b32676e6335637539617964"); } -Proto::SigningInput createSigningInput() -{ +Proto::SigningInput createSigningInput() { auto keyhex = parse_hex("cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1"); auto input = Proto::SigningInput(); input.set_version(1); @@ -332,3 +328,5 @@ TEST(TWIoTeXStaking, SignAll) { "35f53a536e014b32b85df50483ef04849b80ad60635b3b1979c5ba1096b65237"); } } + +} // namespace TW::IoTeX::tests diff --git a/tests/IoTeX/TWAnySignerTests.cpp b/tests/IoTeX/TWAnySignerTests.cpp index 3bcb630ece4..9807a5dfb8a 100644 --- a/tests/IoTeX/TWAnySignerTests.cpp +++ b/tests/IoTeX/TWAnySignerTests.cpp @@ -1,5 +1,4 @@ - -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,8 +11,7 @@ #include -using namespace TW; -using namespace TW::IoTeX; +namespace TW::IoTeX::tests { TEST(TWAnySignerIoTeX, Sign) { auto key = parse_hex("68ffa8ec149ce50da647166036555f73d57f662eb420e154621e5f24f6cf9748"); @@ -32,3 +30,5 @@ TEST(TWAnySignerIoTeX, Sign) { ASSERT_EQ(hex(output.encoded()), "0a39080110011801220131522e0a01311229696f3165326e7173797437666b707a733578377a6632756b306a6a3732746575356e36616b75337472124104fb30b196ce3e976593ecc2da220dca9cdea8c84d2373770042a930b892ac0f5cf762f20459c9100eb9d4d7597f5817bf21e10b53a0120b9ec1ba5cddfdcb669b1a41ec9757ae6c9009315830faaab250b6db0e9535b00843277f596ae0b2b9efc0bd4e14138c056fc4cdfa285d13dd618052b3d1cb7a3f554722005a2941bfede96601"); } + +} // namespace TW::IoTeX::tests diff --git a/tests/Kusama/AddressTests.cpp b/tests/Kusama/AddressTests.cpp index 7a7229a1167..10f6178d1df 100644 --- a/tests/Kusama/AddressTests.cpp +++ b/tests/Kusama/AddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,8 +11,7 @@ #include #include -using namespace TW; -using namespace TW::Kusama; +namespace TW::Kusama::tests { TEST(KusamaAddress, Validation) { // Substrate ed25519 @@ -49,3 +48,5 @@ TEST(KusamaAddress, FromString) { auto address = Address("CeVXtoU4py9e7F6upfM2ZarVave299TjcdaTSxhDDZrYgnM"); ASSERT_EQ(address.string(), "CeVXtoU4py9e7F6upfM2ZarVave299TjcdaTSxhDDZrYgnM"); } + +} // namespace TW::Kusama::tests \ No newline at end of file diff --git a/tests/Kusama/TWAnySignerTests.cpp b/tests/Kusama/TWAnySignerTests.cpp index d3bf8fd5adb..68875989066 100644 --- a/tests/Kusama/TWAnySignerTests.cpp +++ b/tests/Kusama/TWAnySignerTests.cpp @@ -12,8 +12,7 @@ #include -using namespace TW; -using namespace TW::Polkadot; +namespace TW::Polkadot::tests { TEST(TWAnySignerKusama, Sign) { auto key = parse_hex("0x8cdc538e96f460da9d639afc5c226f477ce98684d77fb31e88db74c1f1dd86b2"); @@ -39,3 +38,5 @@ TEST(TWAnySignerKusama, Sign) { ASSERT_EQ(hex(output.encoded()), "350284f41296779fd61a5bed6c2f506cc6c9ea93d6aeb357b9c69717193f434ba24ae700cd78b46eff36c433e642d7e9830805aab4f43eef70067ef32c8b2a294c510673a841c5f8a6e8900c03be40cfa475ae53e6f8aa61961563cb7cc0fa169ef9630d00040004000e33fdfb980e4499e5c3576e742a563b6a4fc0f6f598b1917fd7a6fe393ffc720700e40b5402"); } + +} // namespace TW::Polkadot::tests diff --git a/tests/Monacoin/TWMonacoinTransactionTests.cpp b/tests/Monacoin/TWMonacoinTransactionTests.cpp index 5cc5da208b1..29a70f4045f 100644 --- a/tests/Monacoin/TWMonacoinTransactionTests.cpp +++ b/tests/Monacoin/TWMonacoinTransactionTests.cpp @@ -1,5 +1,4 @@ - -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -15,8 +14,7 @@ #include -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { TEST(MonacoinTransaction, SignTransaction) { /* @@ -67,8 +65,7 @@ TEST(MonacoinTransaction, SignTransaction) { ASSERT_EQ(output.error(), Common::Proto::OK); ASSERT_EQ(hex(output.encoded()), - "0100000001441a513dccc3b660c09c42ceaac147fcdc12b5de4b8b56a078fce5d5ce420aed000000006a473044022047789dc7483b178199439bbfce0ab0caf532fec51095ba099d0d9b0b2169033402201745a0160d8d327655a8ef0542367396ce86bbb13df6b183d58c922e422cfa10012102fc08693599fda741558613cd44a50fc65953b1be797637f8790a495b85554f3effffffff0280f0fa02000000001976a914076df984229a2731cbf465ec8fbd35b8da94380f88ac60a2fa02000000001976a914fea39370769d4fed2d8ab98dd5daa482cc56113b88ac00000000" - ); + "0100000001441a513dccc3b660c09c42ceaac147fcdc12b5de4b8b56a078fce5d5ce420aed000000006a473044022047789dc7483b178199439bbfce0ab0caf532fec51095ba099d0d9b0b2169033402201745a0160d8d327655a8ef0542367396ce86bbb13df6b183d58c922e422cfa10012102fc08693599fda741558613cd44a50fc65953b1be797637f8790a495b85554f3effffffff0280f0fa02000000001976a914076df984229a2731cbf465ec8fbd35b8da94380f88ac60a2fa02000000001976a914fea39370769d4fed2d8ab98dd5daa482cc56113b88ac00000000"); } TEST(MonacoinTransaction, LockScripts) { @@ -93,3 +90,5 @@ TEST(MonacoinTransaction, LockScripts) { auto scriptData3 = WRAPD(TWBitcoinScriptData(script3.get())); assertHexEqual(scriptData3, "001422e6014ad3631f1939281c3625bc98db808fbfb0"); } + +} // namespace TW::Bitcoin diff --git a/tests/NEAR/AccountTests.cpp b/tests/NEAR/AccountTests.cpp index 36d38993b78..f1294306588 100644 --- a/tests/NEAR/AccountTests.cpp +++ b/tests/NEAR/AccountTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,11 +6,9 @@ #include "NEAR/Account.h" #include "HexCoding.h" - #include -using namespace TW; -using namespace TW::NEAR; +namespace TW::NEAR::tests { TEST(NEARAccount, Validation) { ASSERT_FALSE(Account::isValid("a")); @@ -22,3 +20,5 @@ TEST(NEARAccount, Validation) { ASSERT_TRUE(Account::isValid("test-trust.vlad.near")); ASSERT_TRUE(Account::isValid("deadbeef")); } + +} // namespace TW::NEAR::tests diff --git a/tests/NEAR/AddressTests.cpp b/tests/NEAR/AddressTests.cpp index 1da6ca22089..214cd3fab2b 100644 --- a/tests/NEAR/AddressTests.cpp +++ b/tests/NEAR/AddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,8 +11,7 @@ #include -using namespace TW; -using namespace TW::NEAR; +namespace TW::NEAR::tests { TEST(NEARAddress, Validation) { ASSERT_FALSE(Address::isValid("abc")); @@ -26,12 +25,10 @@ TEST(NEARAddress, Validation) { TEST(NEARAddress, FromString) { ASSERT_EQ( Address("NEAR2758Nk7CMUcxTwXdjVdSxNEidiZQWMZN3USJzj76q5ia3v2v2v").string(), - "917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d" - ); + "917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d"); ASSERT_EQ( Address("9685af3fe2dc231e5069ccff8ec6950eb961d42ebb9116a8ab9c0d38f9e45249").string(), - "9685af3fe2dc231e5069ccff8ec6950eb961d42ebb9116a8ab9c0d38f9e45249" - ); + "9685af3fe2dc231e5069ccff8ec6950eb961d42ebb9116a8ab9c0d38f9e45249"); } TEST(NEARAddress, FromPrivateKey) { @@ -42,3 +39,5 @@ TEST(NEARAddress, FromPrivateKey) { ASSERT_EQ(address.string(), "917b3d268d4b58f7fec1b150bd68d69be3ee5d4cc39855e341538465bb77860d"); } + +} // namespace TW::NEAR::tests diff --git a/tests/NEO/CoinReferenceTests.cpp b/tests/NEO/CoinReferenceTests.cpp index 9c707d5bdeb..90c1f2700dc 100644 --- a/tests/NEO/CoinReferenceTests.cpp +++ b/tests/NEO/CoinReferenceTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,12 +7,11 @@ #include "uint256.h" #include "HexCoding.h" #include "NEO/CoinReference.h" - #include +namespace TW::NEO::tests { + using namespace std; -using namespace TW; -using namespace TW::NEO; TEST(NEOCoinReference, Serialize) { auto coinReference = CoinReference(); @@ -28,3 +27,5 @@ TEST(NEOCoinReference, Deserialize) { EXPECT_EQ("bdecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4a", hex(store(coinReference.prevHash))); EXPECT_EQ(1, coinReference.prevIndex); } + +} // namespace TW::NEO::tests diff --git a/tests/NEO/SignerTests.cpp b/tests/NEO/SignerTests.cpp index 6f3b10fd913..fe33508c885 100644 --- a/tests/NEO/SignerTests.cpp +++ b/tests/NEO/SignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,9 +11,9 @@ #include +namespace TW::NEO::tests { + using namespace std; -using namespace TW; -using namespace TW::NEO; TEST(NEOSigner, FromPublicPrivateKey) { auto hexPrvKey = "4646464646464646464646464646464646464646464646464646464646464646"; @@ -57,14 +57,14 @@ TEST(NEOSigner, SigningTransaction) { transaction.version = 0x00; CoinReference coin; - coin.prevHash = load(parse_hex("9c85b39cd5677e2bfd6bf8a711e8da93a2f1d172b2a52c6ca87757a4bccc24de")); //reverse hash - coin.prevIndex = (uint16_t) 1; + coin.prevHash = load(parse_hex("9c85b39cd5677e2bfd6bf8a711e8da93a2f1d172b2a52c6ca87757a4bccc24de")); // reverse hash + coin.prevIndex = (uint16_t)1; transaction.inInputs.push_back(coin); { TransactionOutput out; out.assetId = load(parse_hex("9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc5")); - out.value = (int64_t) 1 * 100000000; + out.value = (int64_t)1 * 100000000; auto scriptHash = TW::NEO::Address("Ad9A1xPbuA5YBFr1XPznDwBwQzdckAjCev").toScriptHash(); out.scriptHash = load(scriptHash); transaction.outputs.push_back(out); @@ -73,7 +73,7 @@ TEST(NEOSigner, SigningTransaction) { { TransactionOutput out; out.assetId = load(parse_hex("9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc5")); - out.value = (int64_t) 892 * 100000000; + out.value = (int64_t)892 * 100000000; auto scriptHash = TW::NEO::Address("AdtSLMBqACP4jv8tRWwyweXGpyGG46eMXV").toScriptHash(); out.scriptHash = load(scriptHash); transaction.outputs.push_back(out); @@ -82,3 +82,5 @@ TEST(NEOSigner, SigningTransaction) { auto signedTx = transaction.serialize(); EXPECT_EQ(hex(signedTx), "800000019c85b39cd5677e2bfd6bf8a711e8da93a2f1d172b2a52c6ca87757a4bccc24de0100029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500e1f50500000000ea610aa6db39bd8c8556c9569d94b5e5a5d0ad199b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500fcbbc414000000f2908c7efc0c9e43ffa7e79170ba37e501e1b4ac0141405046619c8e20e1fdeec92ce95f3019f6e7cc057294eb16b2d5e55c105bf32eb27e1fc01c1858576228f1fef8c0945a8ad69688e52a4ed19f5b85f5eff7e961d7232102a41c2aea8568864b106553729d32b1317ec463aa23e7a3521455d95992e17a7aac"); } + +} // namespace TW::NEO::tests diff --git a/tests/NEO/TWAnySignerTests.cpp b/tests/NEO/TWAnySignerTests.cpp index 3bead1f67e6..e61fec59506 100644 --- a/tests/NEO/TWAnySignerTests.cpp +++ b/tests/NEO/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,8 +11,7 @@ #include -using namespace TW; -using namespace TW::NEO; +namespace TW::NEO::tests { Proto::SigningInput createInput() { const std::string NEO_ASSET_ID = "9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc5"; @@ -21,11 +20,11 @@ Proto::SigningInput createInput() { Proto::SigningInput input; auto privateKey = parse_hex("F18B2F726000E86B4950EBEA7BFF151F69635951BC4A31C44F28EE6AF7AEC128"); input.set_private_key(privateKey.data(), privateKey.size()); - input.set_fee(12345); //too low + input.set_fee(12345); // too low input.set_gas_asset_id(GAS_ASSET_ID); input.set_gas_change_address("AdtSLMBqACP4jv8tRWwyweXGpyGG46eMXV"); -#define ADD_UTXO_INPUT(hash, index , value, assetId) \ +#define ADD_UTXO_INPUT(hash, index, value, assetId) \ { \ auto utxo = input.add_inputs(); \ utxo->set_prev_hash(parse_hex(hash).data(), parse_hex(hash).size()); \ @@ -101,3 +100,5 @@ TEST(TWAnySignerNEO, Plan) { EXPECT_EQ(plan.fee(), 1408000); EXPECT_EQ(plan.error(), Common::Proto::OK); } + +} // namespace TW::NEO::tests diff --git a/tests/NEO/TransactionAttributeTests.cpp b/tests/NEO/TransactionAttributeTests.cpp index 1ebfd2f9992..d911270c92f 100644 --- a/tests/NEO/TransactionAttributeTests.cpp +++ b/tests/NEO/TransactionAttributeTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,13 +9,11 @@ #include "NEO/ReadData.h" #include "NEO/TransactionAttribute.h" #include "NEO/TransactionAttributeUsage.h" - -#include #include +namespace TW::NEO::tests { + using namespace std; -using namespace TW; -using namespace TW::NEO; TEST(NEOTransactionAttribute, Serialize) { auto transactionAttribute = TransactionAttribute(); @@ -86,6 +84,8 @@ TEST(NEOTransactionAttribute, Deserialize) { TEST(NEOTransactionAttribute, DeserializeInitialPositionAfterData) { auto transactionAttribute = TransactionAttribute(); EXPECT_THROW(transactionAttribute.deserialize(Data(), 1), std::invalid_argument); - + EXPECT_THROW(transactionAttribute.deserialize(Data({1}), 2), std::invalid_argument); } + +} // namespace TW::NEO::tests diff --git a/tests/NEO/TransactionOutputTests.cpp b/tests/NEO/TransactionOutputTests.cpp index 5c695cd9aab..84753ba029a 100644 --- a/tests/NEO/TransactionOutputTests.cpp +++ b/tests/NEO/TransactionOutputTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,13 +7,11 @@ #include "uint256.h" #include "HexCoding.h" #include "NEO/TransactionOutput.h" - -#include #include +namespace TW::NEO::tests { + using namespace std; -using namespace TW; -using namespace TW::NEO; TEST(NEOTransactionOutput, Serialize) { auto transactionOutput = TransactionOutput(); @@ -42,3 +40,5 @@ TEST(NEOTransactionOutput, Deserialize) { EXPECT_EQ(assetId, hex(store(transactionOutput.assetId))); EXPECT_EQ(scriptHash, hex(store(transactionOutput.scriptHash))); } + +} // namespace TW::NEO::tests diff --git a/tests/NEO/TransactionTests.cpp b/tests/NEO/TransactionTests.cpp index 7ea44361a46..08c328ea405 100644 --- a/tests/NEO/TransactionTests.cpp +++ b/tests/NEO/TransactionTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,13 +10,11 @@ #include "NEO/TransactionType.h" #include "NEO/TransactionAttributeUsage.h" #include "NEO/TransactionAttribute.h" - -#include #include +namespace TW::NEO::tests { + using namespace std; -using namespace TW; -using namespace TW::NEO; TEST(NEOTransaction, SerializeDeserializeEmpty) { auto transaction = Transaction(); @@ -26,7 +24,7 @@ TEST(NEOTransaction, SerializeDeserializeEmpty) { EXPECT_EQ(0ul, transaction.inInputs.size()); EXPECT_EQ(0ul, transaction.outputs.size()); auto serialized = transaction.serialize(); - + auto deserializedTransaction = Transaction(); deserializedTransaction.deserialize(serialized); EXPECT_EQ(transaction, deserializedTransaction); @@ -221,8 +219,7 @@ TEST(NEOTransaction, SerializeDeserializeMiner) { string notMiner = "1000d11f7a2800000000"; EXPECT_THROW( std::unique_ptr _deserializedTransaction(Transaction::deserializeFrom(parse_hex(notMiner))), - std::invalid_argument - ); + std::invalid_argument); } TEST(NEOTransaction, GetHash) { @@ -248,3 +245,5 @@ TEST(NEOTransaction, SerializeSize) { EXPECT_EQ(serialized.size(), static_cast(transaction.size())); } + +} // namespace TW::NEO::tests diff --git a/tests/NEO/WitnessTests.cpp b/tests/NEO/WitnessTests.cpp index ff2a579846b..7bd68fda171 100644 --- a/tests/NEO/WitnessTests.cpp +++ b/tests/NEO/WitnessTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,9 +11,9 @@ #include +namespace TW::NEO::tests { + using namespace std; -using namespace TW; -using namespace TW::NEO; TEST(NEOWitness, Serialize) { auto witness = Witness(); @@ -62,3 +62,5 @@ TEST(NEOWitness, SerializeDeserialize) { deWitness.deserialize(witness.serialize()); EXPECT_EQ(witness, deWitness); } + +} // namespace TW::NEO::tests diff --git a/tests/NULS/AddressTests.cpp b/tests/NULS/AddressTests.cpp index 9adba2e43e9..0082fac96fc 100644 --- a/tests/NULS/AddressTests.cpp +++ b/tests/NULS/AddressTests.cpp @@ -1,24 +1,22 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "NULS/Address.h" +#include "NULS/Address.h" #include "HexCoding.h" #include "PrivateKey.h" #include -using namespace TW; -using namespace TW::NULS; - +namespace TW::NULS::tests { TEST(NULSAddress, StaticInvalid) { ASSERT_FALSE(Address::isValid("abc")); ASSERT_FALSE(Address::isValid("aaeb60f3e94c9b9a09f33669435e7ef1beaed")); ASSERT_FALSE(Address::isValid("NULSd6HgbwcM8wz48f6UkFYHLVriT1L81X9z")); ASSERT_TRUE(Address::isValid("NULSd6HgUxmcJWc88iELEJ7RH9XHsazBQqnJc")); - ASSERT_TRUE(Address::isValid("NULSd6HgbwcM8wz48f6UkFYHLVriT1L81X9z2")); + ASSERT_TRUE(Address::isValid("NULSd6HgbwcM8wz48f6UkFYHLVriT1L81X9z2")); } TEST(NULSAddress, ChainID) { @@ -60,3 +58,5 @@ TEST(NULSAddress, FromPrivateKey33) { ASSERT_EQ(address.string(), "NULSd6HgXx8YkwEjePLWUmdRSZzPQzK6BXnsB"); } + +} // namespace TW::NULS::tests diff --git a/tests/NULS/TWAnySignerTests.cpp b/tests/NULS/TWAnySignerTests.cpp index bfab5b9177b..c0f5c3b0eea 100644 --- a/tests/NULS/TWAnySignerTests.cpp +++ b/tests/NULS/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,8 +12,7 @@ #include "../interface/TWTestUtilities.h" #include -using namespace TW; -using namespace TW::NULS; +namespace TW::NULS::tests { TEST(TWAnySignerNULS, Sign) { auto privateKey = parse_hex("0x9ce21dad67e0f0af2599b41b515a7f7018059418bab892a7b68f283d489abc4b"); @@ -37,3 +36,5 @@ TEST(TWAnySignerNULS, Sign) { EXPECT_EQ(hex(output.encoded()), "0200f885885d00008c0117010001f7ec6473df12e751d64cf20a8baa7edd50810f8101000100201d9a0000000000000000000000000000000000000000000000000000000000080000000000000000000117010001f05e7878971f3374515eabb6f16d75219d8873120100010080969800000000000000000000000000000000000000000000000000000000000000000000000000692103958b790c331954ed367d37bac901de5c2f06ac8368b37d7bd6cd5ae143c1d7e3463044022028019c0099e2233c7adb84bb03a9a5666ece4a5b65a026a090fa460f3679654702204df0fcb8762b5944b3aba033fa1a287ccb098150035dd8b66f52dc58d3d0843a"); } + +} // namespace TW::NULS::tests diff --git a/tests/Nebulas/AddressTests.cpp b/tests/Nebulas/AddressTests.cpp index 3cca8382bb1..45a70df9a09 100644 --- a/tests/Nebulas/AddressTests.cpp +++ b/tests/Nebulas/AddressTests.cpp @@ -1,19 +1,17 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. #include "Nebulas/Address.h" -#include "../src/Base58.h" #include "HexCoding.h" #include "PrivateKey.h" - #include +namespace TW::Nebulas::tests { + using namespace std; -using namespace TW; -using namespace TW::Nebulas; TEST(NebulasAddress, Invalid) { ASSERT_FALSE(Address::isValid("abc")); @@ -28,11 +26,10 @@ TEST(NebulasAddress, Invalid) { TEST(NebulasAddress, String) { ASSERT_THROW(Address("abc"), std::invalid_argument); ASSERT_EQ(Address("n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY").string(), - "n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY"); + "n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY"); ASSERT_EQ(Address(Base58::bitcoin.decode("n1TgpFZWCMmFd2sphb6RKsCvsEyMCNa2Yyv")).string(), - "n1TgpFZWCMmFd2sphb6RKsCvsEyMCNa2Yyv" - ); - + "n1TgpFZWCMmFd2sphb6RKsCvsEyMCNa2Yyv"); + const auto address = Address("n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY"); ASSERT_EQ(address.string(), "n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY"); } @@ -41,7 +38,7 @@ TEST(NebulasAddress, Data) { Data data; EXPECT_THROW(Address(data).string(), std::invalid_argument); ASSERT_EQ(Address(Base58::bitcoin.decode("n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY")).string(), - "n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY"); + "n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY"); } TEST(NebulasAddress, FromPrivateKey) { @@ -52,3 +49,5 @@ TEST(NebulasAddress, FromPrivateKey) { EXPECT_THROW(Address(privateKey.getPublicKey(TWPublicKeyTypeSECP256k1)), std::invalid_argument); } + +} // namespace TW::Nebulas::tests diff --git a/tests/Nebulas/TWAnySignerTests.cpp b/tests/Nebulas/TWAnySignerTests.cpp index 69008c4d8a6..bafee5a3fcf 100644 --- a/tests/Nebulas/TWAnySignerTests.cpp +++ b/tests/Nebulas/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,33 +12,34 @@ #include -using namespace TW; -using namespace TW::Nebulas; +namespace TW::Nebulas::tests { TEST(TWAnySignerNebulas, Sign) { Proto::SigningInput input; input.set_from_address("n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY"); input.set_to_address("n1SAeQRVn33bamxN4ehWUT7JGdxipwn8b17"); auto value = store(uint256_t(7)); - input.set_nonce(value.data(),value.size()); + input.set_nonce(value.data(), value.size()); value = store(uint256_t(1000000)); - input.set_gas_price(value.data(),value.size()); + input.set_gas_price(value.data(), value.size()); value = store(uint256_t(200000)); - input.set_gas_limit(value.data(),value.size()); + input.set_gas_limit(value.data(), value.size()); value = store(uint256_t(11000000000000000000ULL)); - input.set_amount(value.data(),value.size()); + input.set_amount(value.data(), value.size()); input.set_payload(""); value = store(uint256_t(1560052938)); - input.set_timestamp(value.data(),value.size()); + input.set_timestamp(value.data(), value.size()); const auto privateKey = parse_hex("d2fd0ec9f6268fc8d1f563e3e976436936708bdf0dc60c66f35890f5967a8d2b"); input.set_private_key(privateKey.data(), privateKey.size()); auto chainid = store(uint256_t(1)); input.set_chain_id(chainid.data(), chainid.size()); - + Proto::SigningOutput output; ANY_SIGN(input, TWCoinTypeNebulas); EXPECT_EQ(hex(output.signature()), "f53f4a9141ff8e462b094138eccd8c3a5d7865f9e9ab509626c78460a9e0b0fc35f7ed5ba1795ceb81a5e46b7580a6f7fb431d44fdba92515399cf6a8e47e71500"); EXPECT_EQ(output.raw(), "CiBQXdR2neMqnEu21q/U+OHqZHSBX9Q0hNiRfL2eCZO4hRIaGVefwtw23wEobqA40/7aIwQHghETxH4r+50aGhlXf89CeLWgHFjKu9/6tn4KNbelsMDAIIi2IhAAAAAAAAAAAJin2bgxTAAAKAcwyony5wU6CAoGYmluYXJ5QAFKEAAAAAAAAAAAAAAAAAAPQkBSEAAAAAAAAAAAAAAAAAADDUBYAWJB9T9KkUH/jkYrCUE47M2MOl14Zfnpq1CWJseEYKngsPw19+1boXlc64Gl5Gt1gKb3+0MdRP26klFTmc9qjkfnFQA="); } + +} // namespace TW::Nebulas::tests diff --git a/tests/Nebulas/TransactionTests.cpp b/tests/Nebulas/TransactionTests.cpp index 2774e02d623..0651403fd2a 100644 --- a/tests/Nebulas/TransactionTests.cpp +++ b/tests/Nebulas/TransactionTests.cpp @@ -1,6 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. -// -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -13,12 +11,12 @@ #include -using namespace std; -using namespace TW; -using namespace TW::Nebulas; - extern std::string htmlescape(const std::string& str); +namespace TW::Nebulas::tests { + +using namespace std; + TEST(NebulasTransaction, serialize) { auto from = Address("n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY"); auto to = Address("n1SAeQRVn33bamxN4ehWUT7JGdxipwn8b17"); @@ -36,7 +34,7 @@ TEST(NebulasTransaction, serialize) { auto signer = Signer(1); signer.sign(privateKey, transaction); transaction.serializeToRaw(); - + ASSERT_EQ(TW::Base64::encode(transaction.raw), "CiBQXdR2neMqnEu21q/U+OHqZHSBX9Q0hNiRfL2eCZO4hRIaGVefwtw23wEobqA40/7aIwQHghETxH4r+50aGhlXf89CeLWgHFjKu9/6tn4KNbelsMDAIIi2IhAAAAAAAAAAAJin2bgxTAAAKAcwyony5wU6CAoGYmluYXJ5QAFKEAAAAAAAAAAAAAAAAAAPQkBSEAAAAAAAAAAAAAAAAAADDUBYAWJB9T9KkUH/jkYrCUE47M2MOl14Zfnpq1CWJseEYKngsPw19+1boXlc64Gl5Gt1gKb3+0MdRP26klFTmc9qjkfnFQA="); } @@ -79,5 +77,7 @@ TEST(NebulasTransaction, serializeUnsigned) { /* timestamp: */ 1560052938, /* payload: */ std::string()); - ASSERT_THROW(transaction.serializeToRaw(),std::logic_error); -} \ No newline at end of file + ASSERT_THROW(transaction.serializeToRaw(), std::logic_error); +} + +} // namespace TW::Nebulas::tests diff --git a/tests/Ontology/AddressTests.cpp b/tests/Ontology/AddressTests.cpp index 7945dae19be..f6917282e9b 100644 --- a/tests/Ontology/AddressTests.cpp +++ b/tests/Ontology/AddressTests.cpp @@ -12,8 +12,7 @@ #include -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology::tests { TEST(OntologyAddress, validation) { ASSERT_FALSE(Address::isValid("abc")); @@ -44,4 +43,6 @@ TEST(OntologyAddress, fromMultiPubKeys) { uint8_t m = 2; auto multiAddress = Address(m, pubKeys); EXPECT_EQ("AYGWgijVZnrUa2tRoCcydsHUXR1111DgdW", multiAddress.string()); -} \ No newline at end of file +} + +} // namespace TW::Ontology::tests diff --git a/tests/Ontology/OngTests.cpp b/tests/Ontology/OngTests.cpp index 88ca8431eea..d4b4994ca50 100644 --- a/tests/Ontology/OngTests.cpp +++ b/tests/Ontology/OngTests.cpp @@ -11,8 +11,7 @@ #include #include -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology::tests { TEST(OntologyOng, decimals) { uint32_t nonce = 0; @@ -78,4 +77,6 @@ TEST(OntologyOng, withdraw) { "0ea6435f6f2b1335192a5d1b346fd431e8af912bfa4e1a23ad7d0ab7fc5b808655af5c9043232103d9fd62df33" "2403d9114f3fa3da0d5aec9dfa42948c2f50738d52470469a1a1eeac", rawTx); -} \ No newline at end of file +} + +} // namespace TW::Ontology::tests diff --git a/tests/Ontology/OntTests.cpp b/tests/Ontology/OntTests.cpp index e03c72b793b..20e9c3bbeb6 100644 --- a/tests/Ontology/OntTests.cpp +++ b/tests/Ontology/OntTests.cpp @@ -13,8 +13,7 @@ #include #include -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology::tests { TEST(OntologyOnt, decimals) { uint32_t nonce = 0; @@ -57,4 +56,6 @@ TEST(OntologyOnt, transfer) { "0576d7b092fabafd0913a67ccf8b2f8e3d2bd708f768c2bb67e2d2f759805608232103d9fd62df332403" "d9114f3fa3da0d5aec9dfa42948c2f50738d52470469a1a1eeac", rawTx); -} \ No newline at end of file +} + +} // namespace TW::Ontology::tests diff --git a/tests/Ontology/ParamsBuilderTests.cpp b/tests/Ontology/ParamsBuilderTests.cpp index 382ca6f3335..0534472852d 100644 --- a/tests/Ontology/ParamsBuilderTests.cpp +++ b/tests/Ontology/ParamsBuilderTests.cpp @@ -13,8 +13,7 @@ #include -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology::tests { TEST(ParamsBuilder, pushInt) { std::vector numVector{0, @@ -124,3 +123,5 @@ TEST(OntologyOep4, invokeOep4CodeTransfer) { auto expectCode = "02fd001496f688657b95be51c11a87b51adfda4ab69e9cbb1457e9d1a61f9aafa798b6c7fbeae35639681d7df653c1087472616e736665726733def739225d0f93dd2aed457d7b1fd074ec31ff"; EXPECT_EQ(expectCode, hex(invokeCode)); } + +} // namespace TW::Ontology::tests diff --git a/tests/Ontology/TransactionTests.cpp b/tests/Ontology/TransactionTests.cpp index 633686b4ebf..ccf7fc14094 100644 --- a/tests/Ontology/TransactionTests.cpp +++ b/tests/Ontology/TransactionTests.cpp @@ -16,8 +16,7 @@ #include #include -using namespace TW; -using namespace TW::Ontology; +namespace TW::Ontology::tests { TEST(OntologyTransaction, validity) { std::vector ontContract{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -63,3 +62,5 @@ TEST(OntologyTransaction, validity) { EXPECT_EQ(654ul, verifyPosition2); EXPECT_EQ(724ul, hex(result).length()); } + +} // namespace TW::Ontology::tests diff --git a/tests/Osmosis/AddressTests.cpp b/tests/Osmosis/AddressTests.cpp index 26cd5b668f9..68011e0dc75 100644 --- a/tests/Osmosis/AddressTests.cpp +++ b/tests/Osmosis/AddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,11 +11,7 @@ #include #include -using namespace TW; - -namespace TW::Osmosis::tests { - -using namespace TW::Cosmos; +namespace TW::Cosmos::tests { TEST(OsmosisAddress, Valid) { EXPECT_TRUE(Address::isValid(TWCoinTypeOsmosis, "osmo1mky69cn8ektwy0845vec9upsdphktxt0en97f5")); @@ -47,4 +43,4 @@ TEST(OsmosisAddress, FromString) { EXPECT_EQ(hex(address.getKeyHash()), "dd89a2e267cd96e23cf5a33382f030686f65996f"); } -} // namespace TW::Osmosis::tests +} // namespace TW::Cosmos::tests diff --git a/tests/Osmosis/SignerTests.cpp b/tests/Osmosis/SignerTests.cpp index 236de95c46c..a418f5fc6fb 100644 --- a/tests/Osmosis/SignerTests.cpp +++ b/tests/Osmosis/SignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,18 +7,13 @@ #include "Cosmos/Address.h" #include "Cosmos/Signer.h" #include "HexCoding.h" -#include "PrivateKey.h" #include "PublicKey.h" #include "proto/Cosmos.pb.h" #include "../interface/TWTestUtilities.h" #include -using namespace TW; - -namespace TW::Osmosis::tests { - -using namespace TW::Cosmos; +namespace TW::Cosmos::tests { TEST(OsmosisSigner, SignTransfer_81B4) { auto input = Proto::SigningInput(); @@ -61,4 +56,4 @@ TEST(OsmosisSigner, SignTransfer_81B4) { EXPECT_EQ(output.json(), ""); } -} // namespace TW::Osmosis::tests +} // namespace TW::Cosmos::tests diff --git a/tests/Osmosis/TWAnySignerTests.cpp b/tests/Osmosis/TWAnySignerTests.cpp index f599450333d..5985d55949c 100644 --- a/tests/Osmosis/TWAnySignerTests.cpp +++ b/tests/Osmosis/TWAnySignerTests.cpp @@ -12,11 +12,7 @@ #include "../interface/TWTestUtilities.h" #include -using namespace TW; - -namespace TW::Osmosis::tests { - -using namespace TW::Cosmos; +namespace TW::Cosmos::tests { TEST(TWAnySignerOsmosis, Sign) { auto privateKey = parse_hex("8bbec3772ddb4df68f3186440380c301af116d1422001c1877d6f5e4dba8c8af"); @@ -58,4 +54,4 @@ TEST(TWAnySignerOsmosis, Sign) { EXPECT_EQ(output.error(), ""); } -} // namespace TW::Osmosis::tests +} // namespace TW::Cosmos::tests diff --git a/tests/Ravencoin/TWRavencoinTransactionTests.cpp b/tests/Ravencoin/TWRavencoinTransactionTests.cpp index b9c220fdb0d..b90d76b91c8 100644 --- a/tests/Ravencoin/TWRavencoinTransactionTests.cpp +++ b/tests/Ravencoin/TWRavencoinTransactionTests.cpp @@ -1,5 +1,4 @@ - -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -18,8 +17,7 @@ #include -using namespace TW; -using namespace TW::Bitcoin; +namespace TW::Bitcoin { TEST(RavencoinTransaction, SignTransaction) { /* @@ -73,22 +71,23 @@ TEST(RavencoinTransaction, SignTransaction) { signedTx.encode(serialized, Transaction::SegwitFormatMode::NonSegwit); ASSERT_EQ( hex(serialized), - "0100000001445560237d8093da3487eb90bc7ff826fab43cdbe213c034d671ec4eb4827e0c000000006b483045022100d790bdaa3c44eb5e3a422365ca5fc009c4512625222e3378f2f16e7e6ef1732a0220688c1bb995b7ff2f12729e101d7c24b6314430317e7717911fdc35c0d84f2f0d012102138724e702d25b0fdce73372ccea9734f9349442d5a9681a5f4d831036cd9429ffffffff0280f0fa02000000001976a9149451f4546e09fc2e49ef9b5303924712ec2b038e88ac006cdc02000000001976a9145d6e33f3a108bbcc586cbbe90994d5baf5a9cce488ac00000000" - ); + "0100000001445560237d8093da3487eb90bc7ff826fab43cdbe213c034d671ec4eb4827e0c000000006b483045022100d790bdaa3c44eb5e3a422365ca5fc009c4512625222e3378f2f16e7e6ef1732a0220688c1bb995b7ff2f12729e101d7c24b6314430317e7717911fdc35c0d84f2f0d012102138724e702d25b0fdce73372ccea9734f9349442d5a9681a5f4d831036cd9429ffffffff0280f0fa02000000001976a9149451f4546e09fc2e49ef9b5303924712ec2b038e88ac006cdc02000000001976a9145d6e33f3a108bbcc586cbbe90994d5baf5a9cce488ac00000000"); } TEST(RavencoinTransaction, LockScripts) { - // P2PKH + // P2PKH // https://blockbook.ravencoin.org/tx/3717b528eb4925461d9de5a596d2eefe175985740b4fda153255e10135f236a6 - + auto script = WRAP(TWBitcoinScript, TWBitcoinScriptLockScriptForAddress(STRING("RNoSGCX8SPFscj8epDaJjqEpuZa2B5in88").get(), TWCoinTypeRavencoin)); auto scriptData = WRAPD(TWBitcoinScriptData(script.get())); assertHexEqual(scriptData, "76a9149451f4546e09fc2e49ef9b5303924712ec2b038e88ac"); // P2SH // https://ravencoin.network/api/tx/f600d07814677d1f60545c8f7f71260238595c4928d6fb87caa0f9dd732e9bb5 - + auto script2 = WRAP(TWBitcoinScript, TWBitcoinScriptLockScriptForAddress(STRING("rPWwn5h4QFZNaz1XmY39rc73sdYGGDdmq1").get(), TWCoinTypeRavencoin)); auto scriptData2 = WRAPD(TWBitcoinScriptData(script2.get())); assertHexEqual(scriptData2, "a914bd92088bb7e82d611a9b94fbb74a0908152b784f87"); } + +} // namespace TW::Bitcoin diff --git a/tests/Ripple/AddressTests.cpp b/tests/Ripple/AddressTests.cpp index 107a3007056..9af08ceccb1 100644 --- a/tests/Ripple/AddressTests.cpp +++ b/tests/Ripple/AddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,22 +7,19 @@ #include "Ripple/Address.h" #include "Ripple/XAddress.h" #include "HexCoding.h" -#include "PrivateKey.h" #include -using namespace std; -using namespace TW; -using namespace TW::Ripple; +namespace TW::Ripple { TEST(RippleAddress, FromPublicKey) { const auto publicKey = PublicKey(parse_hex("0303E20EC6B4A39A629815AE02C0A1393B9225E3B890CAE45B59F42FA29BE9668D"), TWPublicKeyTypeSECP256k1); const auto address = Address(publicKey); - ASSERT_EQ(string("rnBFvgZphmN39GWzUJeUitaP22Fr9be75H"), address.string()); + ASSERT_EQ(std::string("rnBFvgZphmN39GWzUJeUitaP22Fr9be75H"), address.string()); } TEST(RippleAddress, FromString) { - string classic = "rnBFvgZphmN39GWzUJeUitaP22Fr9be75H"; + std::string classic = "rnBFvgZphmN39GWzUJeUitaP22Fr9be75H"; const auto address = Address(classic); ASSERT_EQ(address.string(), classic); @@ -31,12 +28,12 @@ TEST(RippleAddress, FromString) { TEST(RippleXAddress, FromPublicKey) { const auto publicKey = PublicKey(parse_hex("0303E20EC6B4A39A629815AE02C0A1393B9225E3B890CAE45B59F42FA29BE9668D"), TWPublicKeyTypeSECP256k1); const auto address = XAddress(publicKey, 12345); - ASSERT_EQ(string("X76UnYEMbQfEs3mUqgtjp4zFy9exgThRj7XVZ6UxsdrBptF"), address.string()); + ASSERT_EQ(std::string("X76UnYEMbQfEs3mUqgtjp4zFy9exgThRj7XVZ6UxsdrBptF"), address.string()); } TEST(RippleXAddress, FromString) { - string xAddress = "X76UnYEMbQfEs3mUqgtjp4zFy9exgThRj7XVZ6UxsdrBptF"; - string xAddress2 = "X76UnYEMbQfEs3mUqgtjp4zFy9exgTsM93nriVZAPufrpE3"; + std::string xAddress = "X76UnYEMbQfEs3mUqgtjp4zFy9exgThRj7XVZ6UxsdrBptF"; + std::string xAddress2 = "X76UnYEMbQfEs3mUqgtjp4zFy9exgTsM93nriVZAPufrpE3"; const auto address = XAddress(xAddress); const auto address2 = XAddress(xAddress2); @@ -48,12 +45,14 @@ TEST(RippleXAddress, FromString) { } TEST(RippleAddress, isValid) { - string classicAddress = "r36yxStAh7qgTQNHTzjZvXybCTzUFhrfav"; - string bitcoinAddress = "1Ma2DrB78K7jmAwaomqZNRMCvgQrNjE2QC"; - string xAddress = "XVfvixWZQKkcenFRYApCjpTUyJ4BePTe3jJv7beatUZvQYh"; + std::string classicAddress = "r36yxStAh7qgTQNHTzjZvXybCTzUFhrfav"; + std::string bitcoinAddress = "1Ma2DrB78K7jmAwaomqZNRMCvgQrNjE2QC"; + std::string xAddress = "XVfvixWZQKkcenFRYApCjpTUyJ4BePTe3jJv7beatUZvQYh"; ASSERT_TRUE(Address::isValid(classicAddress)); ASSERT_TRUE(XAddress::isValid(xAddress)); ASSERT_FALSE(Address::isValid(bitcoinAddress)); ASSERT_FALSE(XAddress::isValid(bitcoinAddress)); } + +} // namespace TW::Ripple diff --git a/tests/Ronin/TWAnySignerTests.cpp b/tests/Ronin/TWAnySignerTests.cpp index 3edbfa75698..e469380d2d2 100644 --- a/tests/Ronin/TWAnySignerTests.cpp +++ b/tests/Ronin/TWAnySignerTests.cpp @@ -12,15 +12,11 @@ #include -using namespace TW; - namespace TW::Ronin::tests { -using namespace TW::Ethereum; - TEST(TWAnySignerRonin, Sign) { // https://explorer.roninchain.com/tx/0xf13a2c4421700f8782ca73eaf16bb8baf82bcf093e23570a1ff062cdd8dbf6c3 - Proto::SigningInput input; + Ethereum::Proto::SigningInput input; auto chainId = store(uint256_t(2020)); auto nonce = store(uint256_t(0)); auto gasPrice = store(uint256_t(1000000000)); @@ -41,7 +37,7 @@ TEST(TWAnySignerRonin, Sign) { std::string expected = "f86880843b9aca0082520894c36edf48e21cf395b206352a1819de658fd7f988830437df80820feca0442aa06b0d0465bfecf84b28e2ce614a32a1ccc12735dc03a5799517d6659d7aa004e1bf2efa30743f1b6d49dbec2671e9fb5ead1e7da15e352ca1df6fb86a8ba7"; // sign test - Proto::SigningOutput output; + Ethereum::Proto::SigningOutput output; ANY_SIGN(input, TWCoinTypeRonin); ASSERT_EQ(hex(output.encoded()), expected); diff --git a/tests/Solana/TransactionTests.cpp b/tests/Solana/TransactionTests.cpp index a06f6928460..c6ff726f613 100644 --- a/tests/Solana/TransactionTests.cpp +++ b/tests/Solana/TransactionTests.cpp @@ -8,14 +8,12 @@ #include "Solana/Transaction.h" #include "Solana/Program.h" #include "HexCoding.h" -#include "PublicKey.h" #include "BinaryCoding.h" #include -using namespace TW; -using namespace TW::Solana; +namespace TW::Solana { TEST(SolanaTransaction, TransferMessageData) { auto from = Address("6eoo7i1khGhVm8tLBMAdq4ax2FxkKP4G7mCcfHyr3STN"); @@ -181,3 +179,5 @@ TEST(SolanaTransaction, TransferTokenTransaction_3vZ67C) { "PGfKqEaH2zZXDMZLcU6LUKdBSzU1GJWJ1CJXtRYCxaCH7k8uok38WSadZfrZw3TGejiau7nSpan2GvbK26hQim24jRe2AupmcYJFrgsdaCt1Aqs5kpGjPqzgj9krgxTZwwob3xgC1NdHK5BcNwhxwRtrCphGEH7zUFpGFrFrHzgpf2KY8FvPiPELQyxzTBuyNtjLjMMreehSKShEjD9Xzp1QeC1pEF8JL6vUKzxMXuveoEYem8q8JiWszYzmTMfDk13JPgv7pXFGMqDV3yNGCLsWccBeSFKN4UKECre6x2QbUEiKGkHkMc4zQwwyD8tGmEMBAGm339qdANssEMNpDeJp2LxLDStSoWShHnotcrH7pUa94xCVvCPPaomF"; EXPECT_EQ(transaction.serialize(), expectedString); } + +} // namespace TW::Solana diff --git a/tests/Stellar/TransactionTests.cpp b/tests/Stellar/TransactionTests.cpp index d9324c4c339..b80e60a0274 100644 --- a/tests/Stellar/TransactionTests.cpp +++ b/tests/Stellar/TransactionTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,20 +6,18 @@ #include "../interface/TWTestUtilities.h" -#include "Stellar/Address.h" #include "Stellar/Signer.h" #include "HexCoding.h" #include "PrivateKey.h" #include -#include #include #include "BinaryCoding.h" #include +namespace TW::Stellar::tests { + using namespace std; -using namespace TW; -using namespace TW::Stellar; TEST(StellarTransaction, sign) { auto words = STRING("indicate rival expand cave giant same grocery burden ugly rose tuna blood"); @@ -143,3 +141,5 @@ TEST(StellarTransaction, signAcreateAccount) { const auto signature = signer.sign(); ASSERT_EQ(signature, "AAAAAAmpZryqzBA+OIlrquP4wvBsIf1H3U+GT/DTP5gZ31yiAAAD6AAAAAAAAAACAAAAAAAAAAIAAAAASZYC0gAAAAEAAAAAAAAAAAAAAADFgLYxeg6zm/f81Po8Gf2rS4m7q79hCV7kUFr27O16rgAAAAAAmJaAAAAAAAAAAAEZ31yiAAAAQNgqNDqbe0X60gyH+1xf2Tv2RndFiJmyfbrvVjsTfjZAVRrS2zE9hHlqPQKpZkGKEFka7+1ElOS+/m/1JDnauQg="); } + +} // namespace TW::Stellar::tests diff --git a/tests/Terra/SignerTestsClassic.cpp b/tests/Terra/SignerTestsClassic.cpp index a334919529d..06b5a4470c3 100644 --- a/tests/Terra/SignerTestsClassic.cpp +++ b/tests/Terra/SignerTestsClassic.cpp @@ -4,7 +4,6 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Coin.h" #include "HexCoding.h" #include "Base64.h" #include "proto/Cosmos.pb.h" @@ -17,9 +16,7 @@ #include #include -using namespace TW; -using namespace TW::Cosmos; - +namespace TW::Cosmos::tests { TEST(TerraClassicSigner, SignSendTx) { auto input = Proto::SigningInput(); @@ -305,7 +302,6 @@ TEST(TerraClassicSigner, SignWasmGeneric_EC4F85) { EXPECT_EQ(output.error(), ""); } - TEST(TerraClassicSigner, SignWasmGenericWithCoins_6651FC) { auto input = Proto::SigningInput(); input.set_signing_mode(Proto::Protobuf); @@ -454,3 +450,5 @@ TEST(TerraClassicSigner, SignWasmTerraTransferPayload) { } )"); } + +} // namespace TW::Cosmos::tests \ No newline at end of file diff --git a/tests/Tezos/ForgingTests.cpp b/tests/Tezos/ForgingTests.cpp index ec6542fef3c..66187be27d2 100644 --- a/tests/Tezos/ForgingTests.cpp +++ b/tests/Tezos/ForgingTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -12,15 +12,12 @@ #include "Tezos/BinaryCoding.h" #include "Tezos/Forging.h" #include "proto/Tezos.pb.h" - #include - #include #include #include -using namespace TW; -using namespace TW::Tezos; +namespace TW::Tezos::tests { TEST(Forging, ForgeBoolTrue) { auto expected = "ff"; @@ -265,3 +262,5 @@ TEST(TezosTransaction, forgeUndelegate) { ASSERT_EQ(hex(serialized.begin(), serialized.end()), expected); } + +} // namespace TW::Tezos::tests diff --git a/tests/Tezos/PublicKeyTests.cpp b/tests/Tezos/PublicKeyTests.cpp index baac0151631..66c7087dc7e 100644 --- a/tests/Tezos/PublicKeyTests.cpp +++ b/tests/Tezos/PublicKeyTests.cpp @@ -12,8 +12,7 @@ #include -using namespace TW; -using namespace TW::Tezos; +namespace TW::Tezos::tests { TEST(TezosPublicKey, forge) { auto input = parsePublicKey("edpkuAfEJCEatRgFpRGg3gn3FdWniLXBoubARreRwuVZPWufkgDBvR"); @@ -29,3 +28,5 @@ TEST(TezosPublicKey, parse) { auto expected = PublicKey(bytes, TWPublicKeyTypeED25519); ASSERT_EQ(output, expected); } + +} // namespace TW::Tezos::tests diff --git a/tests/Theta/TransactionTests.cpp b/tests/Theta/TransactionTests.cpp index 19699afcc78..3ff9a4b3926 100644 --- a/tests/Theta/TransactionTests.cpp +++ b/tests/Theta/TransactionTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,8 +10,7 @@ #include -using namespace TW; -using namespace TW::Theta; +namespace TW::Theta::tests { TEST(ThetaTransaction, Encode) { const auto from = Ethereum::Address("0x2E833968E5bB786Ae419c4d13189fB081Cc43bab"); @@ -35,3 +34,5 @@ TEST(ThetaTransaction, EncodeWithSignature) { "ccdef053ec7cabd18070325c9c436efe1abbacd14eb7561d3fc10501d9d8949f1233798e905e17356007" "1255140b4a8abd3ec6c20a14"); } + +} // namespace TW::Theta::tests diff --git a/tests/VeChain/TWAnySignerTests.cpp b/tests/VeChain/TWAnySignerTests.cpp index 289c725d42b..783ecf827b6 100644 --- a/tests/VeChain/TWAnySignerTests.cpp +++ b/tests/VeChain/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,8 +10,7 @@ #include #include -using namespace TW; -using namespace TW::VeChain; +namespace TW::VeChain::tests { TEST(TWAnySignerVeChain, Sign) { auto input = Proto::SigningInput(); @@ -36,3 +35,5 @@ TEST(TWAnySignerVeChain, Sign) { ASSERT_EQ(hex(output.encoded()), "f86a010101dcdb943535353535353535353535353535353535353535843130303080808252088001c0b841bf8edf9600e645b5abd677cb52f585e7f655d1361075d511b37f707a9f31da6702d28739933b264527a1d05b046f5b74044b88c30c3f5a09d616bd7a4af4901601"); } + +} // namespace TW::VeChain::tests diff --git a/tests/WalletConsoleTests.cpp b/tests/WalletConsoleTests.cpp index 0e7dbf5a25c..e6bdfc9be62 100644 --- a/tests/WalletConsoleTests.cpp +++ b/tests/WalletConsoleTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,29 +6,29 @@ #include "../walletconsole/lib/CommandExecutor.h" #include "../walletconsole/lib/WalletConsole.h" -#include "../walletconsole/lib/Util.h" #include #include #include -using namespace TW; -using namespace TW::WalletConsole; -using namespace std; +namespace TW::WalletConsole::tests { -// Test some command execution +using namespace std; static stringstream outputss; static CommandExecutor cmd(outputss); -static int staticInit() { cmd.init(); return 0; } +static int staticInit() { + cmd.init(); + return 0; +} static int dummyStatic = staticInit(); static const string mnemonic1 = "edge defense waste choose enrich upon flee junk siren film clown finish luggage leader kid quick brick print evidence swap drill paddle truly occur"; int countLines(const string& text) { int lines = 0; - for(auto i = 0ul; i < text.length(); ++i) - { - if (text[i] == '\n') ++lines; + for (auto i = 0ul; i < text.length(); ++i) { + if (text[i] == '\n') + ++lines; } return lines; } @@ -41,7 +41,9 @@ TEST(WalletConsole, loopExit) { stringstream inss; stringstream outss; - inss << "coin eth" << endl << "newKey" << endl << "exit" << endl; + inss << "coin eth" << endl + << "newKey" << endl + << "exit" << endl; TW::WalletConsole::WalletConsole console(inss, outss); console.loop(); string res = outss.str(); @@ -285,7 +287,6 @@ TEST(WalletConsole, dumpdp) { } } - TEST(WalletConsole, dumpXpub) { cmd.executeLine("coin btc"); auto pos1 = outputss.str().length(); @@ -444,7 +445,6 @@ TEST(WalletConsole, fileWriteRead) { string res1 = outputss.str().substr(pos1); EXPECT_TRUE(res1.find("Written to ") != string::npos); - auto pos2 = outputss.str().length(); cmd.executeLine("fileR " + fileName); string res2 = outputss.str().substr(pos2); @@ -458,14 +458,11 @@ TEST(WalletConsole, fileWriteRead) { EXPECT_TRUE(res3.find("already exists, not overwriting") != string::npos); // clean up created file - try - { + try { std::remove(fileName.c_str()); + } catch (...) { } - catch(...) - { - } - + auto pos4 = outputss.str().length(); cmd.executeLine("fileR __NO_SUCH_FILE__"); string res4 = outputss.str().substr(pos4); @@ -485,3 +482,5 @@ TEST(WalletConsole, harmonyAddressDerivation) { EXPECT_TRUE(res1.find("Result") != string::npos); EXPECT_TRUE(res1.find("rror") == string::npos); } + +} // namespace TW::WalletConsole::tests diff --git a/tests/Waves/TWAnySignerTests.cpp b/tests/Waves/TWAnySignerTests.cpp index 9bb037ba987..bc57276977e 100644 --- a/tests/Waves/TWAnySignerTests.cpp +++ b/tests/Waves/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,13 +11,12 @@ #include #include -using namespace TW; -using namespace TW::Waves; +namespace TW::Waves::tests { TEST(TWAnySignerWaves, Sign) { auto input = Proto::SigningInput(); const auto privateKey = Base58::bitcoin.decode("83mqJpmgB5Mko1567sVAdqZxVKsT6jccXt3eFSi4G1zE"); - + input.set_timestamp(int64_t(1559146613)); input.set_private_key(privateKey.data(), privateKey.size()); auto& message = *input.mutable_transfer_message(); @@ -33,3 +32,5 @@ TEST(TWAnySignerWaves, Sign) { ASSERT_EQ(hex(output.signature()), "5d6a77b1fd9b53d9735cd2543ba94215664f2b07d6c7befb081221fcd49f5b6ad6b9ac108582e8d3e74943bdf35fd80d985edf4b4de1fb1c5c427e84d0879f8f"); } + +} // namespace TW::Waves::tests diff --git a/tests/Waves/TransactionTests.cpp b/tests/Waves/TransactionTests.cpp index bfb7998d99f..1e2f1354d8b 100644 --- a/tests/Waves/TransactionTests.cpp +++ b/tests/Waves/TransactionTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -14,19 +14,18 @@ #include #include -using json = nlohmann::json; +namespace TW::Waves::tests { +using json = nlohmann::json; using namespace std; -using namespace TW; -using namespace TW::Waves; TEST(WavesTransaction, serialize) { const auto privateKey = - PrivateKey(parse_hex("9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); + PrivateKey(parse_hex("9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); auto input = Proto::SigningInput(); input.set_timestamp(int64_t(1526641218066)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - + auto& message = *input.mutable_transfer_message(); message.set_amount(int64_t(100000000)); message.set_asset(""); @@ -35,19 +34,18 @@ TEST(WavesTransaction, serialize) { message.set_to("3PLgzJXQiN77G7KgnR1WVa8jBYhF2dmWndx"); message.set_attachment("falafel"); auto tx1 = Transaction( - input, - /* pub_key */ - parse_hex("d528aabec35ca100d87c7b7a128632faf19cd44531819457445113a32a21ef22")); + input, + /* pub_key */ + parse_hex("d528aabec35ca100d87c7b7a128632faf19cd44531819457445113a32a21ef22")); auto serialized1 = tx1.serializeToSign(); ASSERT_EQ(hex(serialized1), "0402d528aabec35ca100d87c7b7a128632faf19cd44531819457445113a32a21ef" "2200000000016372e852120000000005f5e1000000000005f5e1000157cdc9381c" "071beb5abd27738d5cd36cf75f3cbfdd69e8e6bb000766616c6166656c"); - - + auto input2 = Proto::SigningInput(); input2.set_timestamp(int64_t(1)); input2.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - + auto& message2 = *input2.mutable_transfer_message(); message2.set_amount(int64_t(1)); message2.set_asset("DacnEpaUVFRCYk8Fcd1F3cqUZuT4XG7qW9mRyoZD81zq"); @@ -71,11 +69,11 @@ TEST(WavesTransaction, serialize) { TEST(WavesTransaction, failedSerialize) { // 141 bytes attachment const auto privateKey = - PrivateKey(parse_hex("9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); + PrivateKey(parse_hex("9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); auto input = Proto::SigningInput(); input.set_timestamp(int64_t(1526641218066)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - + auto& message = *input.mutable_transfer_message(); message.set_amount(int64_t(100000000)); message.set_asset(""); @@ -93,18 +91,18 @@ TEST(WavesTransaction, failedSerialize) { } TEST(WavesTransaction, jsonSerialize) { - + const auto privateKey = PrivateKey(parse_hex("9864a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a")); const auto publicKeyCurve25519 = privateKey.getPublicKey(TWPublicKeyTypeCURVE25519); ASSERT_EQ(hex(Data(publicKeyCurve25519.bytes.begin(), publicKeyCurve25519.bytes.end())), "559a50cb45a9a8e8d4f83295c354725990164d10bb505275d1a3086c08fb935d"); const auto address = Address(publicKeyCurve25519); - + auto input = Proto::SigningInput(); input.set_timestamp(int64_t(1526641218066)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - + auto& message = *input.mutable_transfer_message(); message.set_amount(int64_t(10000000)); message.set_asset("DacnEpaUVFRCYk8Fcd1F3cqUZuT4XG7qW9mRyoZD81zq"); @@ -113,10 +111,9 @@ TEST(WavesTransaction, jsonSerialize) { message.set_to(address.string()); message.set_attachment("falafel"); auto tx1 = Transaction( - input, - /* pub_key */ - parse_hex("559a50cb45a9a8e8d4f83295c354725990164d10bb505275d1a3086c08fb935d")); - + input, + /* pub_key */ + parse_hex("559a50cb45a9a8e8d4f83295c354725990164d10bb505275d1a3086c08fb935d")); auto signature = Signer::sign(privateKey, tx1); @@ -128,7 +125,7 @@ TEST(WavesTransaction, jsonSerialize) { ASSERT_EQ(json["senderPublicKey"], "6mA8eQjie53kd4jbZrwL3ZhMBqCX6nzit1k55tR2X7zU"); ASSERT_EQ(json["timestamp"], int64_t(1526641218066)); ASSERT_EQ(json["proofs"].dump(), "[\"5ynN2NUiFHkQzw9bK8R7dZcNfTWMAtcWRJsrMvFFM6dUT3fSnPCCX7CTajNU8bJCB" - "H69vU1mnwfx4zpDtF1SkzKg\"]"); + "H69vU1mnwfx4zpDtF1SkzKg\"]"); ASSERT_EQ(json["recipient"], "3P2uzAzX9XTu1t32GkWw68YFFLwtapWvDds"); ASSERT_EQ(json["assetId"], "DacnEpaUVFRCYk8Fcd1F3cqUZuT4XG7qW9mRyoZD81zq"); ASSERT_EQ(json["feeAssetId"], "DacnEpaUVFRCYk8Fcd1F3cqUZuT4XG7qW9mRyoZD82zq"); @@ -136,3 +133,5 @@ TEST(WavesTransaction, jsonSerialize) { ASSERT_EQ(json["attachment"], "4t2Xazb2SX"); ASSERT_EQ(json.dump(), "{\"amount\":10000000,\"assetId\":\"DacnEpaUVFRCYk8Fcd1F3cqUZuT4XG7qW9mRyoZD81zq\",\"attachment\":\"4t2Xazb2SX\",\"fee\":100000000,\"feeAssetId\":\"DacnEpaUVFRCYk8Fcd1F3cqUZuT4XG7qW9mRyoZD82zq\",\"proofs\":[\"5ynN2NUiFHkQzw9bK8R7dZcNfTWMAtcWRJsrMvFFM6dUT3fSnPCCX7CTajNU8bJCBH69vU1mnwfx4zpDtF1SkzKg\"],\"recipient\":\"3P2uzAzX9XTu1t32GkWw68YFFLwtapWvDds\",\"senderPublicKey\":\"6mA8eQjie53kd4jbZrwL3ZhMBqCX6nzit1k55tR2X7zU\",\"timestamp\":1526641218066,\"type\":4,\"version\":2}"); } + +} // namespace TW::Waves::tests diff --git a/tests/Zilliqa/AddressTests.cpp b/tests/Zilliqa/AddressTests.cpp index e4f0a49e269..440df29db64 100644 --- a/tests/Zilliqa/AddressTests.cpp +++ b/tests/Zilliqa/AddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -13,8 +13,7 @@ #include -using namespace TW; -using namespace TW::Zilliqa; +namespace TW::Zilliqa::tests { TEST(ZilliqaAddress, FromPrivateKey) { const auto privateKey = @@ -39,22 +38,19 @@ TEST(ZilliqaAddress, Validation) { TEST(ZilliqaAddress, Checksum) { ASSERT_EQ( checksum(parse_hex("4BAF5FADA8E5DB92C3D3242618C5B47133AE003C")), - "4BAF5faDA8e5Db92C3d3242618c5B47133AE003C" - ); + "4BAF5faDA8e5Db92C3d3242618c5B47133AE003C"); ASSERT_EQ( checksum(parse_hex("448261915A80CDE9BDE7C7A791685200D3A0BF4E")), - "448261915a80cdE9BDE7C7a791685200D3A0bf4E" - ); + "448261915a80cdE9BDE7C7a791685200D3A0bf4E"); ASSERT_EQ( checksum(parse_hex("0xDED02FD979FC2E55C0243BD2F52DF022C40ADA1E")), - "Ded02fD979fC2e55c0243bd2F52df022c40ADa1E" - ); + "Ded02fD979fC2e55c0243bd2F52df022c40ADa1E"); ASSERT_EQ( checksum(parse_hex("0x13F06E60297BEA6A3C402F6F64C416A6B31E586E")), - "13F06E60297bea6A3c402F6f64c416A6b31e586e" - ); + "13F06E60297bea6A3c402F6f64c416A6b31e586e"); ASSERT_EQ( checksum(parse_hex("0x1A90C25307C3CC71958A83FA213A2362D859CF33")), - "1a90C25307C3Cc71958A83fa213A2362D859CF33" - ); + "1a90C25307C3Cc71958A83fa213A2362D859CF33"); } + +} // namespace TW::Zilliqa::tests diff --git a/tests/Zilliqa/SignerTests.cpp b/tests/Zilliqa/SignerTests.cpp index b7b3b95ccd7..5c49cf46952 100644 --- a/tests/Zilliqa/SignerTests.cpp +++ b/tests/Zilliqa/SignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -13,8 +13,7 @@ #include -using namespace TW; -using namespace TW::Zilliqa; +namespace TW::Zilliqa::tests { TEST(ZilliqaSigner, PreImage) { auto privateKey = PrivateKey(parse_hex("0E891B9DFF485000C7D1DC22ECF3A583CC50328684321D61947A86E57CF6C638")); @@ -106,5 +105,7 @@ TEST(ZilliqaSigner, SigningData) { auto output = Signer::sign(input); ASSERT_EQ(output.json(), R"({"amount":"10000000000000","code":"","data":"{\"_tag\":\"DelegateStake\",\"params\":[{\"type\":\"ByStr20\",\"value\":\"0x122219cCeAb410901e96c3A0e55E46231480341b\",\"vname\":\"ssnaddr\"}]}","gasLimit":"5000","gasPrice":"2000000000","nonce":56,"pubKey":"03fb30b196ce3e976593ecc2da220dca9cdea8c84d2373770042a930b892ac0f5c","signature":"437fb5c3ce2c6b01f9d490f670539fae4533c82a21fa7edfe6b23df70d732937e8c578c8d6ed24be9150f5126f7b7c977a467af8947ef92a720908a761a6eb0d","toAddr":"43D459eC504C7432959c086B0ac7F7855E984306","version":65537})"); - ASSERT_EQ(hex(output.signature().begin(), output.signature().end()), "437fb5c3ce2c6b01f9d490f670539fae4533c82a21fa7edfe6b23df70d732937e8c578c8d6ed24be9150f5126f7b7c977a467af8947ef92a720908a761a6eb0d"); + ASSERT_EQ(hex(output.signature().begin(), output.signature().end()), "437fb5c3ce2c6b01f9d490f670539fae4533c82a21fa7edfe6b23df70d732937e8c578c8d6ed24be9150f5126f7b7c977a467af8947ef92a720908a761a6eb0d"); } + +} // namespace TW::Zilliqa::tests \ No newline at end of file diff --git a/tests/Zilliqa/TWAnySignerTests.cpp b/tests/Zilliqa/TWAnySignerTests.cpp index e9cbe99aa3f..876e6abec5b 100644 --- a/tests/Zilliqa/TWAnySignerTests.cpp +++ b/tests/Zilliqa/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,8 +11,7 @@ #include #include -using namespace TW; -using namespace TW::Zilliqa; +namespace TW::Zilliqa::tests { TEST(TWAnySignerZilliqa, Sign) { auto input = Proto::SigningInput(); @@ -45,3 +44,5 @@ TEST(TWAnySignerZilliqa, SignJSON) { ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeZilliqa)); assertStringsEqual(result, "7b22616d6f756e74223a2231303030303030303030303030222c22636f6465223a22222c2264617461223a22222c226761734c696d6974223a2231222c226761735072696365223a2231303030303030303030222c226e6f6e6365223a322c227075624b6579223a22303366623330623139366365336539373635393365636332646132323064636139636465613863383464323337333737303034326139333062383932616330663563222c227369676e6174757265223a223030316661346466303863313161346137396539366536393339396565343865656563633738323331613738623033353561386361373833633737633133393433366533373933346665636332323532656438646163303065323335653232643138343130343631666238393636383563343237303634323733386564323638222c22746f41646472223a2237464363614366303636613546323645653341466663324544314641393831304465616136333243222c2276657273696f6e223a36353533377d"); } + +} // namespace TW::Zilliqa::tests \ No newline at end of file From d0417e1e403d94bd9dbd2a32d453bdb01e936b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20=22Doom=22=20Doumergue?= Date: Tue, 6 Sep 2022 22:18:01 +0200 Subject: [PATCH 070/497] Fix the enum value generated in `coinDispatcher` when adding a new coin (#2561) --- codegen/bin/newcoin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen/bin/newcoin b/codegen/bin/newcoin index b2336c50489..af985bd292b 100755 --- a/codegen/bin/newcoin +++ b/codegen/bin/newcoin @@ -68,7 +68,7 @@ def insert_coin_entry(coin) insert_target_line(target_file, target_line, "// end_of_coin_includes_marker_do_not_modify\n") target_line = "#{entryName}::Entry #{entryName}DP;" + $flag_comment + "\n" insert_target_line(target_file, target_line, "// end_of_coin_dipatcher_declarations_marker_do_not_modify\n") - target_line = " case TWCoinType#{entryName}: entry = &#{entryName}DP; break;" + $flag_comment + "\n" + target_line = " case TWBlockchain#{entryName}: entry = &#{entryName}DP; break;" + $flag_comment + "\n" insert_target_line(target_file, target_line, " // end_of_coin_dipatcher_switch_marker_do_not_modify\n") end From 6351d2660ac96940d8d4fc4a848ac9a3752c0676 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 8 Sep 2022 06:20:19 +0200 Subject: [PATCH 071/497] fix(include_path): fix data include path (#2563) --- src/Aion/Signer.h | 2 +- src/Aion/Transaction.h | 2 +- src/Algorand/Address.h | 2 +- src/Algorand/AssetTransfer.h | 2 +- src/Algorand/OptInAssetTransaction.h | 2 +- src/Algorand/Signer.h | 2 +- src/Algorand/Transfer.h | 2 +- src/Bitcoin/Address.h | 2 +- src/Bitcoin/CashAddress.h | 2 +- src/Bitcoin/OutPoint.h | 2 +- src/Bitcoin/Script.h | 2 +- src/Bitcoin/SegwitAddress.h | 2 +- src/Bitcoin/Transaction.h | 2 +- src/Bitcoin/TransactionInput.h | 2 +- src/Bitcoin/TransactionOutput.h | 2 +- src/Bitcoin/TransactionPlan.h | 2 +- src/Bitcoin/TransactionSigner.h | 2 +- src/Cosmos/Address.h | 2 +- src/Cosmos/Signer.h | 2 +- src/Decred/Address.h | 2 +- src/Decred/OutPoint.h | 2 +- src/Decred/Transaction.h | 2 +- src/Decred/TransactionInput.h | 2 +- src/Decred/TransactionOutput.h | 2 +- src/EOS/Address.h | 2 +- src/EOS/Name.h | 2 +- src/EOS/Serialization.h | 2 +- src/EOS/Signer.h | 2 +- src/EOS/Transaction.h | 2 +- src/Elrond/Address.h | 2 +- src/Elrond/Signer.h | 2 +- src/Ethereum/RLP.h | 2 +- src/Ethereum/Signer.h | 2 +- src/Everscale/Address.h | 2 +- src/Everscale/Cell.h | 2 +- src/Everscale/Signer.h | 2 +- src/FIO/Action.cpp | 2 +- src/FIO/Action.h | 2 +- src/FIO/Address.h | 2 +- src/FIO/Encryption.h | 2 +- src/FIO/NewFundsRequest.h | 2 +- src/FIO/Signer.h | 2 +- src/FIO/Transaction.h | 2 +- src/FIO/TransactionBuilder.h | 2 +- src/Filecoin/Signer.h | 2 +- src/Groestlcoin/Address.h | 2 +- src/Harmony/Signer.h | 2 +- src/Icon/Signer.h | 2 +- src/Keystore/AESParameters.h | 2 +- src/Keystore/EncryptionParameters.h | 2 +- src/Keystore/PBKDF2Parameters.h | 2 +- src/Keystore/ScryptParameters.h | 2 +- src/Keystore/StoredKey.h | 2 +- src/Kusama/Address.h | 2 +- src/NEAR/Address.h | 2 +- src/NEAR/Serialization.h | 2 +- src/NEO/Address.cpp | 2 +- src/NEO/Address.h | 2 +- src/NEO/CoinReference.h | 2 +- src/NEO/ISerializable.h | 2 +- src/NEO/MinerTransaction.h | 2 +- src/NEO/ReadData.cpp | 2 +- src/NEO/ReadData.h | 2 +- src/NEO/Script.h | 2 +- src/NEO/Signer.h | 2 +- src/NEO/TransactionAttribute.h | 2 +- src/NEO/TransactionOutput.h | 2 +- src/NEO/Witness.h | 2 +- src/Nano/Signer.h | 2 +- src/Nebulas/Signer.h | 2 +- src/Nervos/Address.h | 2 +- src/Nervos/CellOutput.h | 2 +- src/Nervos/Constants.h | 2 +- src/Nervos/OutPoint.h | 2 +- src/Nervos/Script.h | 2 +- src/Nervos/Serialization.h | 2 +- src/Nervos/Transaction.h | 2 +- src/Nervos/TransactionPlan.h | 2 +- src/Nervos/Witness.h | 2 +- src/Nimiq/Signer.h | 2 +- src/Oasis/Address.h | 2 +- src/Oasis/Signer.h | 2 +- src/Ontology/Asset.h | 2 +- src/Ontology/Oep4.h | 2 +- src/Ontology/Ong.h | 2 +- src/Ontology/Ont.h | 2 +- src/Ontology/ParamsBuilder.h | 2 +- src/Ontology/SigData.h | 2 +- src/Polkadot/Address.h | 2 +- src/Polkadot/Extrinsic.h | 2 +- src/Polkadot/ScaleCodec.h | 2 +- src/Polkadot/Signer.h | 2 +- src/Ripple/Address.h | 2 +- src/Ripple/Signer.h | 2 +- src/Ripple/Transaction.h | 2 +- src/Ripple/XAddress.h | 2 +- src/Solana/Signer.h | 2 +- src/Solana/Transaction.h | 2 +- src/Stellar/Address.h | 2 +- src/Stellar/Signer.h | 2 +- src/THORChain/Signer.h | 2 +- src/Tezos/Address.h | 2 +- src/Tezos/BinaryCoding.cpp | 2 +- src/Tezos/BinaryCoding.h | 2 +- src/Tezos/OperationList.h | 2 +- src/Tezos/Signer.h | 2 +- src/Theta/Signer.h | 2 +- src/Theta/Transaction.h | 2 +- src/Tron/Address.h | 2 +- src/Tron/Serialization.h | 2 +- src/Tron/Signer.h | 2 +- src/VeChain/Clause.h | 2 +- src/VeChain/Signer.h | 2 +- src/VeChain/Transaction.h | 2 +- src/Waves/Address.cpp | 2 +- src/Waves/Address.h | 2 +- src/Waves/Signer.h | 2 +- src/Waves/Transaction.h | 2 +- src/Zilliqa/AddressChecksum.h | 2 +- src/Zilliqa/Signer.h | 2 +- src/interface/TWHash.cpp | 2 +- src/interface/TWStoredKey.cpp | 2 +- 122 files changed, 122 insertions(+), 122 deletions(-) diff --git a/src/Aion/Signer.h b/src/Aion/Signer.h index 68a95d79628..76d5e97d36b 100644 --- a/src/Aion/Signer.h +++ b/src/Aion/Signer.h @@ -7,7 +7,7 @@ #pragma once #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../PrivateKey.h" #include "../proto/Aion.pb.h" diff --git a/src/Aion/Transaction.h b/src/Aion/Transaction.h index dc975dcaac9..b5e54bc4d85 100644 --- a/src/Aion/Transaction.h +++ b/src/Aion/Transaction.h @@ -7,7 +7,7 @@ #pragma once #include "Address.h" -#include "../Data.h" +#include "Data.h" #include diff --git a/src/Algorand/Address.h b/src/Algorand/Address.h index 93f82788676..dc4af6666fe 100644 --- a/src/Algorand/Address.h +++ b/src/Algorand/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Algorand/AssetTransfer.h b/src/Algorand/AssetTransfer.h index 030a90dcc2d..63b4b51fc86 100644 --- a/src/Algorand/AssetTransfer.h +++ b/src/Algorand/AssetTransfer.h @@ -8,7 +8,7 @@ #include "Address.h" #include "BaseTransaction.h" -#include "../Data.h" +#include "Data.h" #include "../proto/Algorand.pb.h" namespace TW::Algorand { diff --git a/src/Algorand/OptInAssetTransaction.h b/src/Algorand/OptInAssetTransaction.h index 8412c3e4e46..8616cbd8900 100644 --- a/src/Algorand/OptInAssetTransaction.h +++ b/src/Algorand/OptInAssetTransaction.h @@ -8,7 +8,7 @@ #include "Address.h" #include "BaseTransaction.h" -#include "../Data.h" +#include "Data.h" #include "../proto/Algorand.pb.h" namespace TW::Algorand { diff --git a/src/Algorand/Signer.h b/src/Algorand/Signer.h index 7942022585c..4f8ef6a2730 100644 --- a/src/Algorand/Signer.h +++ b/src/Algorand/Signer.h @@ -10,7 +10,7 @@ #include "OptInAssetTransaction.h" #include "Transfer.h" -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" namespace TW::Algorand { diff --git a/src/Algorand/Transfer.h b/src/Algorand/Transfer.h index 29b4f6169e5..dbf94ac2b48 100644 --- a/src/Algorand/Transfer.h +++ b/src/Algorand/Transfer.h @@ -8,7 +8,7 @@ #include "Address.h" #include "BaseTransaction.h" -#include "../Data.h" +#include "Data.h" #include "../proto/Algorand.pb.h" namespace TW::Algorand { diff --git a/src/Bitcoin/Address.h b/src/Bitcoin/Address.h index 9ab00322ed8..48ae90a8760 100644 --- a/src/Bitcoin/Address.h +++ b/src/Bitcoin/Address.h @@ -7,7 +7,7 @@ #pragma once #include "../Base58Address.h" -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Bitcoin/CashAddress.h b/src/Bitcoin/CashAddress.h index f428a43634e..1ad14b9213f 100644 --- a/src/Bitcoin/CashAddress.h +++ b/src/Bitcoin/CashAddress.h @@ -7,7 +7,7 @@ #pragma once #include "Address.h" -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Bitcoin/OutPoint.h b/src/Bitcoin/OutPoint.h index 89943b7b8a4..0abed5a31a1 100644 --- a/src/Bitcoin/OutPoint.h +++ b/src/Bitcoin/OutPoint.h @@ -7,7 +7,7 @@ #pragma once #include "algorithm/to_array.h" -#include "../Data.h" +#include "Data.h" #include "../proto/Bitcoin.pb.h" #include diff --git a/src/Bitcoin/Script.h b/src/Bitcoin/Script.h index 83de655387c..f8f0e7257d9 100644 --- a/src/Bitcoin/Script.h +++ b/src/Bitcoin/Script.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "OpCodes.h" #include diff --git a/src/Bitcoin/SegwitAddress.h b/src/Bitcoin/SegwitAddress.h index 480b6694d49..8a073b6f1fa 100644 --- a/src/Bitcoin/SegwitAddress.h +++ b/src/Bitcoin/SegwitAddress.h @@ -7,7 +7,7 @@ #pragma once #include "../PublicKey.h" -#include "../Data.h" +#include "Data.h" #include #include diff --git a/src/Bitcoin/Transaction.h b/src/Bitcoin/Transaction.h index c64957802ec..b45fa14c6ab 100644 --- a/src/Bitcoin/Transaction.h +++ b/src/Bitcoin/Transaction.h @@ -14,7 +14,7 @@ #include "UTXO.h" #include "../PrivateKey.h" #include "../Hash.h" -#include "../Data.h" +#include "Data.h" #include "SignatureVersion.h" #include "../proto/Bitcoin.pb.h" diff --git a/src/Bitcoin/TransactionInput.h b/src/Bitcoin/TransactionInput.h index a7b57df2f9c..8a9b28399ae 100644 --- a/src/Bitcoin/TransactionInput.h +++ b/src/Bitcoin/TransactionInput.h @@ -8,7 +8,7 @@ #include "OutPoint.h" #include "Script.h" -#include "../Data.h" +#include "Data.h" #include diff --git a/src/Bitcoin/TransactionOutput.h b/src/Bitcoin/TransactionOutput.h index 499787d0dbc..0a4ac788218 100644 --- a/src/Bitcoin/TransactionOutput.h +++ b/src/Bitcoin/TransactionOutput.h @@ -8,7 +8,7 @@ #include "Amount.h" #include "Script.h" -#include "../Data.h" +#include "Data.h" #include diff --git a/src/Bitcoin/TransactionPlan.h b/src/Bitcoin/TransactionPlan.h index 0b7e4b7309f..1225082d307 100644 --- a/src/Bitcoin/TransactionPlan.h +++ b/src/Bitcoin/TransactionPlan.h @@ -8,7 +8,7 @@ #include "Amount.h" #include "UTXO.h" -#include "../Data.h" +#include "Data.h" #include "../proto/Bitcoin.pb.h" namespace TW::Bitcoin { diff --git a/src/Bitcoin/TransactionSigner.h b/src/Bitcoin/TransactionSigner.h index 3803703e046..f75c88851cb 100644 --- a/src/Bitcoin/TransactionSigner.h +++ b/src/Bitcoin/TransactionSigner.h @@ -10,7 +10,7 @@ #include "Transaction.h" #include "TransactionBuilder.h" #include "Signer.h" -#include "../Data.h" +#include "Data.h" #include "../KeyPair.h" #include "../Result.h" #include "../proto/Bitcoin.pb.h" diff --git a/src/Cosmos/Address.h b/src/Cosmos/Address.h index 36e5399bbf6..f13753db89a 100644 --- a/src/Cosmos/Address.h +++ b/src/Cosmos/Address.h @@ -7,7 +7,7 @@ #pragma once #include "../Bech32Address.h" -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include "../Coin.h" #include diff --git a/src/Cosmos/Signer.h b/src/Cosmos/Signer.h index b22a4fd2d48..b380af3b1ea 100644 --- a/src/Cosmos/Signer.h +++ b/src/Cosmos/Signer.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../proto/Cosmos.pb.h" #include diff --git a/src/Decred/Address.h b/src/Decred/Address.h index d86bfcba2bf..fb534ccffc0 100644 --- a/src/Decred/Address.h +++ b/src/Decred/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Decred/OutPoint.h b/src/Decred/OutPoint.h index 3ce3b5b169a..315d78e693d 100644 --- a/src/Decred/OutPoint.h +++ b/src/Decred/OutPoint.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../Bitcoin/OutPoint.h" #include "../proto/Bitcoin.pb.h" diff --git a/src/Decred/Transaction.h b/src/Decred/Transaction.h index ba53dcba98f..ee2a36fc7d2 100644 --- a/src/Decred/Transaction.h +++ b/src/Decred/Transaction.h @@ -11,7 +11,7 @@ #include "TransactionOutput.h" #include "Bitcoin/Transaction.h" #include "Bitcoin/Script.h" -#include "../Data.h" +#include "Data.h" #include "../proto/Decred.pb.h" #include "Bitcoin/SignatureVersion.h" diff --git a/src/Decred/TransactionInput.h b/src/Decred/TransactionInput.h index 98e1a2933ac..dde3c075055 100644 --- a/src/Decred/TransactionInput.h +++ b/src/Decred/TransactionInput.h @@ -8,7 +8,7 @@ #include "OutPoint.h" #include "../Bitcoin/Script.h" -#include "../Data.h" +#include "Data.h" #include #include diff --git a/src/Decred/TransactionOutput.h b/src/Decred/TransactionOutput.h index 7d5cf89b30f..2d9575d4a08 100644 --- a/src/Decred/TransactionOutput.h +++ b/src/Decred/TransactionOutput.h @@ -8,7 +8,7 @@ #include "../Bitcoin/Amount.h" #include "../Bitcoin/Script.h" -#include "../Data.h" +#include "Data.h" namespace TW::Decred { diff --git a/src/EOS/Address.h b/src/EOS/Address.h index f0484c046c1..0749b8244b7 100644 --- a/src/EOS/Address.h +++ b/src/EOS/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include "Prefixes.h" diff --git a/src/EOS/Name.h b/src/EOS/Name.h index a3fca26df6f..6fb75b9e7e4 100644 --- a/src/EOS/Name.h +++ b/src/EOS/Name.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" namespace TW::EOS { diff --git a/src/EOS/Serialization.h b/src/EOS/Serialization.h index af6f3820fa4..f6aa5c83680 100644 --- a/src/EOS/Serialization.h +++ b/src/EOS/Serialization.h @@ -2,7 +2,7 @@ #include -#include "../Data.h" +#include "Data.h" #include "../BinaryCoding.h" #include diff --git a/src/EOS/Signer.h b/src/EOS/Signer.h index 1aee6d97364..95832639489 100644 --- a/src/EOS/Signer.h +++ b/src/EOS/Signer.h @@ -8,7 +8,7 @@ #include "Prefixes.h" #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../PrivateKey.h" #include "../proto/EOS.pb.h" diff --git a/src/EOS/Transaction.h b/src/EOS/Transaction.h index 1d31ee9da36..63a93edad09 100644 --- a/src/EOS/Transaction.h +++ b/src/EOS/Transaction.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "Action.h" #include "Prefixes.h" diff --git a/src/Elrond/Address.h b/src/Elrond/Address.h index 13e722ab193..a638b4af8bd 100644 --- a/src/Elrond/Address.h +++ b/src/Elrond/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include "../Bech32Address.h" diff --git a/src/Elrond/Signer.h b/src/Elrond/Signer.h index 046f5e52d67..df43bf1295d 100644 --- a/src/Elrond/Signer.h +++ b/src/Elrond/Signer.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../proto/Elrond.pb.h" diff --git a/src/Ethereum/RLP.h b/src/Ethereum/RLP.h index 7bdc17c60ed..c65ecbbc6cb 100644 --- a/src/Ethereum/RLP.h +++ b/src/Ethereum/RLP.h @@ -7,7 +7,7 @@ #pragma once #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../uint256.h" #include diff --git a/src/Ethereum/Signer.h b/src/Ethereum/Signer.h index 29f88105c83..3fb42172c1d 100644 --- a/src/Ethereum/Signer.h +++ b/src/Ethereum/Signer.h @@ -8,7 +8,7 @@ #include "RLP.h" #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../PrivateKey.h" #include "../proto/Ethereum.pb.h" diff --git a/src/Everscale/Address.h b/src/Everscale/Address.h index 19dbcb7db72..d97ec61f44c 100644 --- a/src/Everscale/Address.h +++ b/src/Everscale/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Everscale/Cell.h b/src/Everscale/Cell.h index 565fd4daea5..0a621ffcf19 100644 --- a/src/Everscale/Cell.h +++ b/src/Everscale/Cell.h @@ -12,7 +12,7 @@ #include -#include "../Data.h" +#include "Data.h" #include "../Hash.h" namespace TW::Everscale { diff --git a/src/Everscale/Signer.h b/src/Everscale/Signer.h index 99ed125d1c9..35cfcd953a0 100644 --- a/src/Everscale/Signer.h +++ b/src/Everscale/Signer.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../proto/Everscale.pb.h" diff --git a/src/FIO/Action.cpp b/src/FIO/Action.cpp index 9a64137e7bb..db6a0c9d536 100644 --- a/src/FIO/Action.cpp +++ b/src/FIO/Action.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. #include "Action.h" -#include "../Data.h" +#include "Data.h" namespace TW::FIO { diff --git a/src/FIO/Action.h b/src/FIO/Action.h index 5390175400e..70566cfd7ba 100644 --- a/src/FIO/Action.h +++ b/src/FIO/Action.h @@ -7,7 +7,7 @@ #pragma once #include "EOS/Name.h" // Name is reused -#include "../Data.h" +#include "Data.h" #include "../BinaryCoding.h" #include diff --git a/src/FIO/Address.h b/src/FIO/Address.h index 25dba8e7bf5..2d00fa70dfa 100644 --- a/src/FIO/Address.h +++ b/src/FIO/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/FIO/Encryption.h b/src/FIO/Encryption.h index 659f099c7e1..e293f3358fd 100644 --- a/src/FIO/Encryption.h +++ b/src/FIO/Encryption.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../PublicKey.h" diff --git a/src/FIO/NewFundsRequest.h b/src/FIO/NewFundsRequest.h index e3602fd54b1..3b58d2c3a40 100644 --- a/src/FIO/NewFundsRequest.h +++ b/src/FIO/NewFundsRequest.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include diff --git a/src/FIO/Signer.h b/src/FIO/Signer.h index 7604ca4f953..c41b072ed72 100644 --- a/src/FIO/Signer.h +++ b/src/FIO/Signer.h @@ -7,7 +7,7 @@ #pragma once #include "Address.h" -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../PublicKey.h" #include "../proto/FIO.pb.h" diff --git a/src/FIO/Transaction.h b/src/FIO/Transaction.h index 67f70939ff7..1bfa26369b2 100644 --- a/src/FIO/Transaction.h +++ b/src/FIO/Transaction.h @@ -7,7 +7,7 @@ #pragma once #include "Action.h" -#include "../Data.h" +#include "Data.h" #include diff --git a/src/FIO/TransactionBuilder.h b/src/FIO/TransactionBuilder.h index eede5d91ca2..607e0d48963 100644 --- a/src/FIO/TransactionBuilder.h +++ b/src/FIO/TransactionBuilder.h @@ -10,7 +10,7 @@ #include "Address.h" #include "../proto/FIO.pb.h" -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include diff --git a/src/Filecoin/Signer.h b/src/Filecoin/Signer.h index 523abc45d6b..b266e95e120 100644 --- a/src/Filecoin/Signer.h +++ b/src/Filecoin/Signer.h @@ -8,7 +8,7 @@ #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../PrivateKey.h" #include "../proto/Filecoin.pb.h" diff --git a/src/Groestlcoin/Address.h b/src/Groestlcoin/Address.h index 2084cea1b9f..d29c37d4e68 100644 --- a/src/Groestlcoin/Address.h +++ b/src/Groestlcoin/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Harmony/Signer.h b/src/Harmony/Signer.h index b674b953549..dc0cac9ada9 100644 --- a/src/Harmony/Signer.h +++ b/src/Harmony/Signer.h @@ -8,7 +8,7 @@ #include "Staking.h" #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../PrivateKey.h" #include "../proto/Harmony.pb.h" diff --git a/src/Icon/Signer.h b/src/Icon/Signer.h index 987ae90e546..209757dc00f 100644 --- a/src/Icon/Signer.h +++ b/src/Icon/Signer.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../proto/Icon.pb.h" #include diff --git a/src/Keystore/AESParameters.h b/src/Keystore/AESParameters.h index 5f6b994157c..edae9ab9b4f 100644 --- a/src/Keystore/AESParameters.h +++ b/src/Keystore/AESParameters.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include diff --git a/src/Keystore/EncryptionParameters.h b/src/Keystore/EncryptionParameters.h index 744ebe47277..edd368e19cb 100644 --- a/src/Keystore/EncryptionParameters.h +++ b/src/Keystore/EncryptionParameters.h @@ -9,7 +9,7 @@ #include "AESParameters.h" #include "PBKDF2Parameters.h" #include "ScryptParameters.h" -#include "../Data.h" +#include "Data.h" #include #include diff --git a/src/Keystore/PBKDF2Parameters.h b/src/Keystore/PBKDF2Parameters.h index 0d473b5615b..175a5106157 100644 --- a/src/Keystore/PBKDF2Parameters.h +++ b/src/Keystore/PBKDF2Parameters.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../HexCoding.h" #include diff --git a/src/Keystore/ScryptParameters.h b/src/Keystore/ScryptParameters.h index 541d4419e43..b29faa0e344 100644 --- a/src/Keystore/ScryptParameters.h +++ b/src/Keystore/ScryptParameters.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../HexCoding.h" #include diff --git a/src/Keystore/StoredKey.h b/src/Keystore/StoredKey.h index ae76b5bf6a1..96d3010064b 100644 --- a/src/Keystore/StoredKey.h +++ b/src/Keystore/StoredKey.h @@ -8,7 +8,7 @@ #include "Account.h" #include "EncryptionParameters.h" -#include "../Data.h" +#include "Data.h" #include "../HDWallet.h" #include diff --git a/src/Kusama/Address.h b/src/Kusama/Address.h index c973018e172..9635b6972ca 100644 --- a/src/Kusama/Address.h +++ b/src/Kusama/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include "../Polkadot/SS58Address.h" #include diff --git a/src/NEAR/Address.h b/src/NEAR/Address.h index 5a81fd24c03..791aa107b9f 100644 --- a/src/NEAR/Address.h +++ b/src/NEAR/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/NEAR/Serialization.h b/src/NEAR/Serialization.h index 1e2ecd9e493..54a9d7041d9 100644 --- a/src/NEAR/Serialization.h +++ b/src/NEAR/Serialization.h @@ -7,7 +7,7 @@ #pragma once #include "../proto/NEAR.pb.h" -#include "../Data.h" +#include "Data.h" namespace TW::NEAR { diff --git a/src/NEO/Address.cpp b/src/NEO/Address.cpp index 14a2df31c07..64c4c28a808 100644 --- a/src/NEO/Address.cpp +++ b/src/NEO/Address.cpp @@ -6,7 +6,7 @@ #include "OpCode.h" #include "../Base58.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../Ontology/ParamsBuilder.h" diff --git a/src/NEO/Address.h b/src/NEO/Address.h index d3d78ab7088..993cba859c3 100644 --- a/src/NEO/Address.h +++ b/src/NEO/Address.h @@ -9,7 +9,7 @@ #include #include "../Base58Address.h" -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" namespace TW::NEO { diff --git a/src/NEO/CoinReference.h b/src/NEO/CoinReference.h index ad185c0e143..1a7dd9fd120 100644 --- a/src/NEO/CoinReference.h +++ b/src/NEO/CoinReference.h @@ -7,7 +7,7 @@ #pragma once #include "../uint256.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../BinaryCoding.h" #include "ISerializable.h" diff --git a/src/NEO/ISerializable.h b/src/NEO/ISerializable.h index 64e30ee0754..ce2245a643d 100644 --- a/src/NEO/ISerializable.h +++ b/src/NEO/ISerializable.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../BinaryCoding.h" #include "ReadData.h" diff --git a/src/NEO/MinerTransaction.h b/src/NEO/MinerTransaction.h index ca73b306958..73ff8daf129 100644 --- a/src/NEO/MinerTransaction.h +++ b/src/NEO/MinerTransaction.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "Transaction.h" namespace TW::NEO { diff --git a/src/NEO/ReadData.cpp b/src/NEO/ReadData.cpp index f18a6312d5c..f0889883487 100644 --- a/src/NEO/ReadData.cpp +++ b/src/NEO/ReadData.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../Data.h" +#include "Data.h" #include "ReadData.h" #include diff --git a/src/NEO/ReadData.h b/src/NEO/ReadData.h index c757c308f4f..fbe297c9ba3 100644 --- a/src/NEO/ReadData.h +++ b/src/NEO/ReadData.h @@ -9,7 +9,7 @@ #include #include -#include "../Data.h" +#include "Data.h" #include "../BinaryCoding.h" namespace TW { diff --git a/src/NEO/Script.h b/src/NEO/Script.h index 64d47982754..80090432607 100644 --- a/src/NEO/Script.h +++ b/src/NEO/Script.h @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. #pragma once -#include "../Data.h" +#include "Data.h" namespace TW::NEO { diff --git a/src/NEO/Signer.h b/src/NEO/Signer.h index bb00b08e09e..55c68339ce2 100644 --- a/src/NEO/Signer.h +++ b/src/NEO/Signer.h @@ -8,7 +8,7 @@ #include "Address.h" #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../proto/NEO.pb.h" diff --git a/src/NEO/TransactionAttribute.h b/src/NEO/TransactionAttribute.h index bdad6b80a12..be027e9bfd0 100644 --- a/src/NEO/TransactionAttribute.h +++ b/src/NEO/TransactionAttribute.h @@ -9,7 +9,7 @@ #include "TransactionAttributeUsage.h" #include "ISerializable.h" #include "Serializable.h" -#include "../Data.h" +#include "Data.h" namespace TW::NEO { diff --git a/src/NEO/TransactionOutput.h b/src/NEO/TransactionOutput.h index 86b51af36bc..dd99028a687 100644 --- a/src/NEO/TransactionOutput.h +++ b/src/NEO/TransactionOutput.h @@ -7,7 +7,7 @@ #pragma once #include "../uint256.h" -#include "../Data.h" +#include "Data.h" #include "../BinaryCoding.h" #include "ReadData.h" #include "ISerializable.h" diff --git a/src/NEO/Witness.h b/src/NEO/Witness.h index 6f0e7c9d139..2562bbb7f4e 100644 --- a/src/NEO/Witness.h +++ b/src/NEO/Witness.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "ISerializable.h" #include "Serializable.h" diff --git a/src/Nano/Signer.h b/src/Nano/Signer.h index ea41ff542b2..8ca6fe318d5 100644 --- a/src/Nano/Signer.h +++ b/src/Nano/Signer.h @@ -7,7 +7,7 @@ #pragma once #include "Address.h" -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include diff --git a/src/Nebulas/Signer.h b/src/Nebulas/Signer.h index 86a74d2bed2..2beed1448ce 100644 --- a/src/Nebulas/Signer.h +++ b/src/Nebulas/Signer.h @@ -7,7 +7,7 @@ #pragma once #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../proto/Nebulas.pb.h" #include "../uint256.h" diff --git a/src/Nervos/Address.h b/src/Nervos/Address.h index a31de6349e0..3b8c28fab7c 100644 --- a/src/Nervos/Address.h +++ b/src/Nervos/Address.h @@ -8,7 +8,7 @@ #include -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Nervos/CellOutput.h b/src/Nervos/CellOutput.h index 2b8f85af9a2..ca2b267d0cf 100644 --- a/src/Nervos/CellOutput.h +++ b/src/Nervos/CellOutput.h @@ -7,7 +7,7 @@ #pragma once #include "Script.h" -#include "../Data.h" +#include "Data.h" #include "../proto/Nervos.pb.h" #include diff --git a/src/Nervos/Constants.h b/src/Nervos/Constants.h index d128c7d581e..97678b77bd7 100644 --- a/src/Nervos/Constants.h +++ b/src/Nervos/Constants.h @@ -9,7 +9,7 @@ #include "Address.h" #include "CellDep.h" #include "OutPoint.h" -#include "../Data.h" +#include "Data.h" #include "../HexCoding.h" #include diff --git a/src/Nervos/OutPoint.h b/src/Nervos/OutPoint.h index a37d5a4e38b..f6fc82e90f0 100644 --- a/src/Nervos/OutPoint.h +++ b/src/Nervos/OutPoint.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../proto/Nervos.pb.h" #include diff --git a/src/Nervos/Script.h b/src/Nervos/Script.h index 8f22bdf119e..7c0abffec5c 100644 --- a/src/Nervos/Script.h +++ b/src/Nervos/Script.h @@ -8,7 +8,7 @@ #include "Address.h" #include "Constants.h" -#include "../Data.h" +#include "Data.h" #include "../proto/Nervos.pb.h" #include diff --git a/src/Nervos/Serialization.h b/src/Nervos/Serialization.h index 99c62b50dc0..9a2c66dee71 100644 --- a/src/Nervos/Serialization.h +++ b/src/Nervos/Serialization.h @@ -7,7 +7,7 @@ #pragma once #include "../BinaryCoding.h" -#include "../Data.h" +#include "Data.h" #include "../HexCoding.h" #include "../uint256.h" diff --git a/src/Nervos/Transaction.h b/src/Nervos/Transaction.h index 713115861ba..6121b0a6866 100644 --- a/src/Nervos/Transaction.h +++ b/src/Nervos/Transaction.h @@ -18,7 +18,7 @@ #include "../Coin.h" #include "../CoinEntry.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../KeyPair.h" #include "../PrivateKey.h" diff --git a/src/Nervos/TransactionPlan.h b/src/Nervos/TransactionPlan.h index aded69fe9da..7fc800e44a3 100644 --- a/src/Nervos/TransactionPlan.h +++ b/src/Nervos/TransactionPlan.h @@ -16,7 +16,7 @@ #include "../Coin.h" #include "../CoinEntry.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../KeyPair.h" #include "../PrivateKey.h" diff --git a/src/Nervos/Witness.h b/src/Nervos/Witness.h index 13a60640fef..f53aa398f7a 100644 --- a/src/Nervos/Witness.h +++ b/src/Nervos/Witness.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include diff --git a/src/Nimiq/Signer.h b/src/Nimiq/Signer.h index 52baa9f03f0..022f98ba424 100644 --- a/src/Nimiq/Signer.h +++ b/src/Nimiq/Signer.h @@ -7,7 +7,7 @@ #pragma once #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../PrivateKey.h" #include "../proto/Nimiq.pb.h" diff --git a/src/Oasis/Address.h b/src/Oasis/Address.h index d9784cd63f1..c4eb73f3ef0 100644 --- a/src/Oasis/Address.h +++ b/src/Oasis/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include "../Bech32Address.h" diff --git a/src/Oasis/Signer.h b/src/Oasis/Signer.h index 76df838c029..90e92d0e5b9 100644 --- a/src/Oasis/Signer.h +++ b/src/Oasis/Signer.h @@ -9,7 +9,7 @@ #include -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../proto/Oasis.pb.h" #include "Transaction.h" diff --git a/src/Ontology/Asset.h b/src/Ontology/Asset.h index 95e15a1f9cc..a393db0f18e 100644 --- a/src/Ontology/Asset.h +++ b/src/Ontology/Asset.h @@ -10,7 +10,7 @@ #include "Signer.h" #include "Transaction.h" #include "../BinaryCoding.h" -#include "../Data.h" +#include "Data.h" #include #include diff --git a/src/Ontology/Oep4.h b/src/Ontology/Oep4.h index f3b8ebdc3bc..d121d8a1ceb 100644 --- a/src/Ontology/Oep4.h +++ b/src/Ontology/Oep4.h @@ -10,7 +10,7 @@ #include "Asset.h" #include "ParamsBuilder.h" #include "Transaction.h" -#include "../Data.h" +#include "Data.h" namespace TW::Ontology { diff --git a/src/Ontology/Ong.h b/src/Ontology/Ong.h index d4d616bc47b..8537f605967 100644 --- a/src/Ontology/Ong.h +++ b/src/Ontology/Ong.h @@ -7,7 +7,7 @@ #pragma once #include "Asset.h" -#include "../Data.h" +#include "Data.h" namespace TW::Ontology { diff --git a/src/Ontology/Ont.h b/src/Ontology/Ont.h index 567c9f97625..88806c2a197 100644 --- a/src/Ontology/Ont.h +++ b/src/Ontology/Ont.h @@ -7,7 +7,7 @@ #pragma once #include "Asset.h" -#include "../Data.h" +#include "Data.h" namespace TW::Ontology { diff --git a/src/Ontology/ParamsBuilder.h b/src/Ontology/ParamsBuilder.h index e8fa0c558f3..0a4acfd55c5 100644 --- a/src/Ontology/ParamsBuilder.h +++ b/src/Ontology/ParamsBuilder.h @@ -7,7 +7,7 @@ #pragma once #include "../BinaryCoding.h" -#include "../Data.h" +#include "Data.h" #include #include diff --git a/src/Ontology/SigData.h b/src/Ontology/SigData.h index dd76b9d54cb..0ee703922c1 100644 --- a/src/Ontology/SigData.h +++ b/src/Ontology/SigData.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" namespace TW::Ontology { diff --git a/src/Polkadot/Address.h b/src/Polkadot/Address.h index 46a38376b5d..10f3828c2a0 100644 --- a/src/Polkadot/Address.h +++ b/src/Polkadot/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include "SS58Address.h" #include diff --git a/src/Polkadot/Extrinsic.h b/src/Polkadot/Extrinsic.h index dc20eb75908..ccac8260998 100644 --- a/src/Polkadot/Extrinsic.h +++ b/src/Polkadot/Extrinsic.h @@ -7,7 +7,7 @@ #pragma once #include "Address.h" -#include "../Data.h" +#include "Data.h" #include "../proto/Polkadot.pb.h" #include "../uint256.h" #include "ScaleCodec.h" diff --git a/src/Polkadot/ScaleCodec.h b/src/Polkadot/ScaleCodec.h index 6afbc285694..e0d1c3ca20d 100644 --- a/src/Polkadot/ScaleCodec.h +++ b/src/Polkadot/ScaleCodec.h @@ -7,7 +7,7 @@ #pragma once #include "../BinaryCoding.h" -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include "SS58Address.h" #include diff --git a/src/Polkadot/Signer.h b/src/Polkadot/Signer.h index 4b790bd8b42..d893d64a010 100644 --- a/src/Polkadot/Signer.h +++ b/src/Polkadot/Signer.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../proto/Polkadot.pb.h" diff --git a/src/Ripple/Address.h b/src/Ripple/Address.h index 5aa88a4c168..ffa8acbec2d 100644 --- a/src/Ripple/Address.h +++ b/src/Ripple/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Ripple/Signer.h b/src/Ripple/Signer.h index 9674fdb5cd2..ab49851839b 100644 --- a/src/Ripple/Signer.h +++ b/src/Ripple/Signer.h @@ -7,7 +7,7 @@ #pragma once #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../PrivateKey.h" diff --git a/src/Ripple/Transaction.h b/src/Ripple/Transaction.h index e718f319de4..a51f82eefab 100644 --- a/src/Ripple/Transaction.h +++ b/src/Ripple/Transaction.h @@ -8,7 +8,7 @@ #include "Address.h" #include "XAddress.h" -#include "../Data.h" +#include "Data.h" #include "../proto/Ripple.pb.h" namespace TW::Ripple { diff --git a/src/Ripple/XAddress.h b/src/Ripple/XAddress.h index dc60e67a57d..75454734821 100644 --- a/src/Ripple/XAddress.h +++ b/src/Ripple/XAddress.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Solana/Signer.h b/src/Solana/Signer.h index 8b86befe832..46bed571ffb 100644 --- a/src/Solana/Signer.h +++ b/src/Solana/Signer.h @@ -7,7 +7,7 @@ #pragma once #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../PrivateKey.h" #include "../proto/Solana.pb.h" diff --git a/src/Solana/Transaction.h b/src/Solana/Transaction.h index b29bd5ee5b8..8ea3e6c5fca 100644 --- a/src/Solana/Transaction.h +++ b/src/Solana/Transaction.h @@ -9,7 +9,7 @@ #include "Address.h" #include "../Base58.h" #include "../BinaryCoding.h" -#include "../Data.h" +#include "Data.h" #include #include diff --git a/src/Stellar/Address.h b/src/Stellar/Address.h index 6183aaeaace..6f42dd14926 100644 --- a/src/Stellar/Address.h +++ b/src/Stellar/Address.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Stellar/Signer.h b/src/Stellar/Signer.h index a37c3f0338c..7cf60a41094 100644 --- a/src/Stellar/Signer.h +++ b/src/Stellar/Signer.h @@ -6,7 +6,7 @@ #pragma once #include "Address.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../PrivateKey.h" #include "../proto/Stellar.pb.h" diff --git a/src/THORChain/Signer.h b/src/THORChain/Signer.h index 5488f281291..e524abfb5ee 100644 --- a/src/THORChain/Signer.h +++ b/src/THORChain/Signer.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../proto/Cosmos.pb.h" #include diff --git a/src/Tezos/Address.h b/src/Tezos/Address.h index c939ee66276..eb360abc6bd 100644 --- a/src/Tezos/Address.h +++ b/src/Tezos/Address.h @@ -7,7 +7,7 @@ #pragma once #include "../Base58Address.h" -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Tezos/BinaryCoding.cpp b/src/Tezos/BinaryCoding.cpp index 1e1758bfee4..1f030be4cfd 100644 --- a/src/Tezos/BinaryCoding.cpp +++ b/src/Tezos/BinaryCoding.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. #include "../Base58.h" -#include "../Data.h" +#include "Data.h" #include "../HexCoding.h" #include "../PublicKey.h" #include "../PrivateKey.h" diff --git a/src/Tezos/BinaryCoding.h b/src/Tezos/BinaryCoding.h index 39d34885f7f..9bee6a3bd46 100644 --- a/src/Tezos/BinaryCoding.h +++ b/src/Tezos/BinaryCoding.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include "../PrivateKey.h" diff --git a/src/Tezos/OperationList.h b/src/Tezos/OperationList.h index 8ed3152b684..a6f3a4a9f70 100644 --- a/src/Tezos/OperationList.h +++ b/src/Tezos/OperationList.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "proto/Tezos.pb.h" #include "../PrivateKey.h" #include diff --git a/src/Tezos/Signer.h b/src/Tezos/Signer.h index e1a64844dbd..a6e16cf4733 100644 --- a/src/Tezos/Signer.h +++ b/src/Tezos/Signer.h @@ -7,7 +7,7 @@ #pragma once #include "OperationList.h" -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../proto/Tezos.pb.h" diff --git a/src/Theta/Signer.h b/src/Theta/Signer.h index 1fe12da5dd3..e4dbe975fd4 100644 --- a/src/Theta/Signer.h +++ b/src/Theta/Signer.h @@ -9,7 +9,7 @@ #include #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../proto/Theta.pb.h" diff --git a/src/Theta/Transaction.h b/src/Theta/Transaction.h index 58a3531a0a5..20edd2d0de6 100644 --- a/src/Theta/Transaction.h +++ b/src/Theta/Transaction.h @@ -10,7 +10,7 @@ #include #include "Coins.h" -#include "../Data.h" +#include "Data.h" #include "../Ethereum/Address.h" namespace TW::Theta { diff --git a/src/Tron/Address.h b/src/Tron/Address.h index 7577171a5b3..2c7a37128ee 100644 --- a/src/Tron/Address.h +++ b/src/Tron/Address.h @@ -7,7 +7,7 @@ #pragma once #include "../Base58Address.h" -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Tron/Serialization.h b/src/Tron/Serialization.h index 13181c7ac47..7f3c074cfd5 100644 --- a/src/Tron/Serialization.h +++ b/src/Tron/Serialization.h @@ -7,7 +7,7 @@ #pragma once #include "./Protobuf/TronInternal.pb.h" -#include "../Data.h" +#include "Data.h" #include namespace TW::Tron { diff --git a/src/Tron/Signer.h b/src/Tron/Signer.h index 2336c3c8fc2..33a06fff775 100644 --- a/src/Tron/Signer.h +++ b/src/Tron/Signer.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../proto/Tron.pb.h" diff --git a/src/VeChain/Clause.h b/src/VeChain/Clause.h index 9bbb1bc6435..71d56d7d785 100644 --- a/src/VeChain/Clause.h +++ b/src/VeChain/Clause.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../Ethereum/Address.h" #include "../proto/VeChain.pb.h" #include "../uint256.h" diff --git a/src/VeChain/Signer.h b/src/VeChain/Signer.h index 2ef5bd0dd7b..f0a2a92d22b 100644 --- a/src/VeChain/Signer.h +++ b/src/VeChain/Signer.h @@ -8,7 +8,7 @@ #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../PrivateKey.h" diff --git a/src/VeChain/Transaction.h b/src/VeChain/Transaction.h index ba905028550..c4229b795d3 100644 --- a/src/VeChain/Transaction.h +++ b/src/VeChain/Transaction.h @@ -7,7 +7,7 @@ #pragma once #include "Clause.h" -#include "../Data.h" +#include "Data.h" #include #include diff --git a/src/Waves/Address.cpp b/src/Waves/Address.cpp index 2e8ce6f05bc..2f5ad758be7 100644 --- a/src/Waves/Address.cpp +++ b/src/Waves/Address.cpp @@ -7,7 +7,7 @@ #include "Address.h" #include "../Base58.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include diff --git a/src/Waves/Address.h b/src/Waves/Address.h index df518415334..fed1743c9de 100644 --- a/src/Waves/Address.h +++ b/src/Waves/Address.h @@ -7,7 +7,7 @@ #pragma once #include "../Base58Address.h" -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/src/Waves/Signer.h b/src/Waves/Signer.h index 4540029e28c..f7504d61132 100644 --- a/src/Waves/Signer.h +++ b/src/Waves/Signer.h @@ -7,7 +7,7 @@ #pragma once #include "Transaction.h" -#include "../Data.h" +#include "Data.h" #include "../Hash.h" #include "../PrivateKey.h" #include "../proto/Waves.pb.h" diff --git a/src/Waves/Transaction.h b/src/Waves/Transaction.h index b22fd54a030..539af362566 100644 --- a/src/Waves/Transaction.h +++ b/src/Waves/Transaction.h @@ -7,7 +7,7 @@ #pragma once #include "Address.h" -#include "../Data.h" +#include "Data.h" #include "../proto/Waves.pb.h" #include diff --git a/src/Zilliqa/AddressChecksum.h b/src/Zilliqa/AddressChecksum.h index c2f32e63152..a91665deda1 100644 --- a/src/Zilliqa/AddressChecksum.h +++ b/src/Zilliqa/AddressChecksum.h @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include namespace TW::Zilliqa { diff --git a/src/Zilliqa/Signer.h b/src/Zilliqa/Signer.h index d4089e4e485..c1ce6f9cfe6 100644 --- a/src/Zilliqa/Signer.h +++ b/src/Zilliqa/Signer.h @@ -7,7 +7,7 @@ #pragma once #include "Address.h" -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../proto/Zilliqa.pb.h" diff --git a/src/interface/TWHash.cpp b/src/interface/TWHash.cpp index 0e6019a3f54..fc442c13fcd 100644 --- a/src/interface/TWHash.cpp +++ b/src/interface/TWHash.cpp @@ -6,7 +6,7 @@ #include #include "../Hash.h" -#include "../Data.h" +#include "Data.h" #include "BinaryCoding.h" #include diff --git a/src/interface/TWStoredKey.cpp b/src/interface/TWStoredKey.cpp index 4974e87c29e..bccd49a9a03 100644 --- a/src/interface/TWStoredKey.cpp +++ b/src/interface/TWStoredKey.cpp @@ -7,7 +7,7 @@ #include #include "../Coin.h" -#include "../Data.h" +#include "Data.h" #include "../HDWallet.h" #include "../Keystore/StoredKey.h" From a0c3b5b037173f715260cf36895284533d936472 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 9 Sep 2022 15:02:30 +0200 Subject: [PATCH 072/497] [Cosmos]: Add missing chain id (#2558) * feat(cosmos): add missing chain ids * feat(chain_id_cosmos): add some tests --- registry.json | 5 +++++ tests/Cosmos/TWCoinTypeTests.cpp | 2 ++ tests/Kava/TWCoinTypeTests.cpp | 2 ++ tests/Terra/TWCoinTypeTests.cpp | 2 ++ 4 files changed, 11 insertions(+) diff --git a/registry.json b/registry.json index 5ff19c81691..ddb7b73a287 100644 --- a/registry.json +++ b/registry.json @@ -400,6 +400,7 @@ "coinId": 118, "symbol": "ATOM", "decimals": 6, + "chainId": "cosmoshub-4", "blockchain": "Cosmos", "derivation": [ { @@ -918,6 +919,7 @@ "symbol": "LUNC", "decimals": 6, "blockchain": "Cosmos", + "chainId": "columbus-5", "derivation": [ { "path": "m/44'/330'/0'/0/0" @@ -1138,6 +1140,7 @@ "symbol": "KAVA", "decimals": 6, "blockchain": "Cosmos", + "chainId": "kava_2222-10", "derivation": [ { "path": "m/44'/459'/0'/0/0" @@ -1226,6 +1229,7 @@ "coinId": 494, "decimals": 6, "blockchain": "Cosmos", + "chainId": "laozi-mainnet", "derivation": [ { "path": "m/44'/494'/0'/0/0" @@ -2577,6 +2581,7 @@ "symbol": "EVMOS", "decimals": 18, "blockchain": "Cosmos", + "chainId": "evmos_9001-2", "derivation": [ { "path": "m/44'/60'/0'/0/0" diff --git a/tests/Cosmos/TWCoinTypeTests.cpp b/tests/Cosmos/TWCoinTypeTests.cpp index e6e94c4a999..10d3a2d3cc4 100644 --- a/tests/Cosmos/TWCoinTypeTests.cpp +++ b/tests/Cosmos/TWCoinTypeTests.cpp @@ -21,11 +21,13 @@ TEST(TWCosmosCoinType, TWCoinType) { auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeCosmos, accId.get())); auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeCosmos)); auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeCosmos)); + const auto chainId = WRAPS(TWCoinTypeChainId(TWCoinTypeCosmos)); ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeCosmos), 6); ASSERT_EQ(TWBlockchainCosmos, TWCoinTypeBlockchain(TWCoinTypeCosmos)); ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeCosmos)); ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeCosmos)); + assertStringsEqual(chainId, "cosmoshub-4"); assertStringsEqual(symbol, "ATOM"); assertStringsEqual(txUrl, "https://mintscan.io/cosmos/txs/541FA06FB37AC1BF61922143783DD76FECA361830F9876D0342536EE8A87A790"); assertStringsEqual(accUrl, "https://mintscan.io/cosmos/account/cosmos1gu6y2a0ffteesyeyeesk23082c6998xyzmt9mz"); diff --git a/tests/Kava/TWCoinTypeTests.cpp b/tests/Kava/TWCoinTypeTests.cpp index b8c061f97fc..0852f499368 100644 --- a/tests/Kava/TWCoinTypeTests.cpp +++ b/tests/Kava/TWCoinTypeTests.cpp @@ -21,11 +21,13 @@ TEST(TWKavaCoinType, TWCoinType) { auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeKava, accId.get())); auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeKava)); auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeKava)); + const auto chainId = WRAPS(TWCoinTypeChainId(TWCoinTypeKava)); ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeKava), 6); ASSERT_EQ(TWBlockchainCosmos, TWCoinTypeBlockchain(TWCoinTypeKava)); ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeKava)); ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeKava)); + assertStringsEqual(chainId, "kava_2222-10"); assertStringsEqual(symbol, "KAVA"); assertStringsEqual(txUrl, "https://mintscan.io/kava/txs/2988DF83FCBFAA38179D583A96734CBD071541D6768221BB23111BC8136D5E6A"); assertStringsEqual(accUrl, "https://mintscan.io/kava/account/kava1xd39avn2f008jmvua0eupg39zsp2xn3wf802vn"); diff --git a/tests/Terra/TWCoinTypeTests.cpp b/tests/Terra/TWCoinTypeTests.cpp index 52aba87d23e..b812faa478a 100644 --- a/tests/Terra/TWCoinTypeTests.cpp +++ b/tests/Terra/TWCoinTypeTests.cpp @@ -41,11 +41,13 @@ TEST(TWTerraCoinType, TWCoinTypeClassic) { auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeTerra, accId.get())); auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeTerra)); auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeTerra)); + const auto chainId = WRAPS(TWCoinTypeChainId(TWCoinTypeTerra)); ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeTerra), 6); ASSERT_EQ(TWBlockchainCosmos, TWCoinTypeBlockchain(TWCoinTypeTerra)); ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeTerra)); ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeTerra)); + assertStringsEqual(chainId, "columbus-5"); assertStringsEqual(symbol, "LUNC"); assertStringsEqual(txUrl, "https://finder.terra.money/classic/tx/D28D8AFC7CE89F2A22FA2DBF78D2C0A36E549BB830C4D9FA7459E3F723CA7182"); assertStringsEqual(accUrl, "https://finder.terra.money/classic/address/terra16t3gx5rqvz6ru37yzn3shuu20erv4ngmfr59zf"); From 6acc0aa1007c776df425fa5595935385706226e9 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Sun, 11 Sep 2022 14:02:25 +0200 Subject: [PATCH 073/497] [Tools]: Swift API codegen (#2564) --- tools/doxygen_convert_comments | 28 ++++++++++++++++++++++++++++ tools/generate-files | 3 +++ tools/ios-build | 2 +- tools/ios-doc | 19 +++++++++++++++++++ tools/ios-xcframework | 4 ++++ tools/ios-xcframework-release | 3 +++ tools/library | 2 ++ 7 files changed, 60 insertions(+), 1 deletion(-) create mode 100755 tools/doxygen_convert_comments create mode 100755 tools/ios-doc diff --git a/tools/doxygen_convert_comments b/tools/doxygen_convert_comments new file mode 100755 index 00000000000..3c76e250487 --- /dev/null +++ b/tools/doxygen_convert_comments @@ -0,0 +1,28 @@ +#!/bin/bash + +SWIFT_PARAMETER_PATTERN='s/\\param\s+([^\s]+)/\- Parameter $1:/g' +SWIFT_RETURN_PATTERN='s/\\return/\- Returns:/g' +SWIFT_NOTE_PATTERN='s/\\note/\- Note:/g' +SWIFT_SEE_PATTERN='s/\\see/\- SeeAlso:/g' +SWIFT_FOLDER_PATH="swift/Sources/Generated/*.swift" +SWIFT_FOLDER_PATH_BAK="swift/Sources/Generated/*.bak" + +function process_swift_comments() { + perl -pi.bak -e "$SWIFT_PARAMETER_PATTERN" "$1" + perl -pi.bak -e "$SWIFT_RETURN_PATTERN" "$1" + perl -pi.bak -e "$SWIFT_NOTE_PATTERN" "$1" + perl -pi.bak -e "$SWIFT_SEE_PATTERN" "$1" +} + + +function swift_convert() { + echo "Processing swift convertion" + + for d in $SWIFT_FOLDER_PATH ; do + process_swift_comments $d + done + + rm -rf $SWIFT_FOLDER_PATH_BAK +} + +swift_convert diff --git a/tools/generate-files b/tools/generate-files index 75aec1ca64f..54c041b5fbe 100755 --- a/tools/generate-files +++ b/tools/generate-files @@ -49,6 +49,9 @@ codegen/bin/coins # Generate interface code codegen/bin/codegen +# Convert doxygen comments to appropriate format +tools/doxygen_convert_comments + # Generate Java, C++ and Swift Protobuf files if [ -x "$(command -v protoc-gen-swift)" ]; then "$PROTOC" -I=$PREFIX/include -I=src/proto --cpp_out=src/proto --java_out=lite:jni/java --swift_out=swift/Sources/Generated/Protobuf --swift_opt=Visibility=Public src/proto/*.proto diff --git a/tools/ios-build b/tools/ios-build index bf5fa47251a..e1b3945ecfc 100755 --- a/tools/ios-build +++ b/tools/ios-build @@ -23,7 +23,7 @@ init() { # build destination archivePath build() { echo "Building scheme: $1, destination: $2, path: $3" - xcodebuild archive -project swift/${FRAMEWORK}.xcodeproj -scheme "$1" -destination "$2" -archivePath "$BUILD_FOLDER/$3".xcarchive SKIP_INSTALL=NO | xcpretty + xcodebuild archive -project swift/${FRAMEWORK}.xcodeproj -scheme "$1" -destination "$2" -archivePath "$BUILD_FOLDER/$3".xcarchive SKIP_INSTALL=NO | xcbeautify } build_ios_arm64() { diff --git a/tools/ios-doc b/tools/ios-doc new file mode 100755 index 00000000000..be998bff74c --- /dev/null +++ b/tools/ios-doc @@ -0,0 +1,19 @@ +#!/bin/bash + +# https://developer.apple.com/documentation/xcode/distributing-documentation-to-external-developers + +pushd swift +mkdir -p build + +export DOCC_JSON_PRETTYPRINT="YES" +xcodebuild -workspace TrustWalletCore.xcworkspace -derivedDataPath build/docsData -scheme WalletCore -destination 'platform=iOS Simulator,name=iPhone 13 Pro Max' -parallelizeTargets docbuild | xcbeautify + +pushd build + +mv `find docsData/Build/Products -type d -name "*.doccarchive"` . + +echo "Zipping docc archive..." +zip -rq WalletCore.doccarchive.zip WalletCore.doccarchive + +popd # build +popd # swift diff --git a/tools/ios-xcframework b/tools/ios-xcframework index 6b5f21808aa..d5d667f4b14 100755 --- a/tools/ios-xcframework +++ b/tools/ios-xcframework @@ -5,6 +5,10 @@ set -e +echo "Building Docc..." +tools/ios-doc + +echo "Building xcframework..." pushd swift fastlane ios xcframework popd diff --git a/tools/ios-xcframework-release b/tools/ios-xcframework-release index 61b41de44d5..0ce859a8cc1 100755 --- a/tools/ios-xcframework-release +++ b/tools/ios-xcframework-release @@ -82,4 +82,7 @@ echo "protobuf dsyms url is: ${protobuf_dsyms_url}" core_dsyms_url=$(wc_upload_asset ${release_url} ${core_dsyms_filename}) echo "core dsyms url is: ${core_dsyms_url}" +docc_url=$(wc_upload_asset ${release_url} WalletCore.doccarchive.zip) +echo "docc url is: ${docc_url}" + popd diff --git a/tools/library b/tools/library index fe02dc8a57f..27746bd18f9 100755 --- a/tools/library +++ b/tools/library @@ -9,6 +9,7 @@ wc_read_version() { } wc_release_url() { + set -o pipefail tag="$1" id=$(curl "https://api.github.com/repos/trustwallet/wallet-core/releases/tags/${tag}" | jq ".id") @@ -21,6 +22,7 @@ wc_release_url() { } wc_upload_asset() { + set -o pipefail release_url="$1" filename="$2" From ea3a05acb3467088f4c68c87722a2bd8ffdccd01 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 12 Sep 2022 02:54:01 +0200 Subject: [PATCH 074/497] improvements(boost): remove boost::variant usage in favor of std::variant (#2565) --- src/Keystore/EncryptionParameters.cpp | 38 +++++++++++---------------- src/Keystore/EncryptionParameters.h | 6 ++--- tests/Keystore/StoredKeyTests.cpp | 20 +++++++------- 3 files changed, 29 insertions(+), 35 deletions(-) diff --git a/src/Keystore/EncryptionParameters.cpp b/src/Keystore/EncryptionParameters.cpp index 052a35b043d..ad7e6ecf348 100644 --- a/src/Keystore/EncryptionParameters.cpp +++ b/src/Keystore/EncryptionParameters.cpp @@ -11,8 +11,6 @@ #include #include #include - -#include #include using namespace TW; @@ -58,14 +56,12 @@ nlohmann::json EncryptionParameters::json() const { j[CodingKeys::cipher] = cipher; j[CodingKeys::cipherParams] = cipherParams.json(); - if (kdfParams.which() == 0) { - auto scryptParams = boost::get(kdfParams); + if (auto* scryptParams = std::get_if(&kdfParams); scryptParams) { j[CodingKeys::kdf] = "scrypt"; - j[CodingKeys::kdfParams] = scryptParams.json(); - } else if (kdfParams.which() == 1) { - auto pbkdf2Params = boost::get(kdfParams); + j[CodingKeys::kdfParams] = scryptParams->json(); + } else if (auto* pbkdf2Params = std::get_if(&kdfParams); pbkdf2Params) { j[CodingKeys::kdf] = "pbkdf2"; - j[CodingKeys::kdfParams] = pbkdf2Params.json(); + j[CodingKeys::kdfParams] = pbkdf2Params->json(); } return j; @@ -73,7 +69,7 @@ nlohmann::json EncryptionParameters::json() const { EncryptedPayload::EncryptedPayload(const Data& password, const Data& data, const EncryptionParameters& params) : params(std::move(params)), _mac() { - auto scryptParams = boost::get(params.kdfParams); + auto scryptParams = std::get(this->params.kdfParams); auto derivedKey = Data(scryptParams.desiredKeyLength); scrypt(reinterpret_cast(password.data()), password.size(), scryptParams.salt.data(), scryptParams.salt.size(), scryptParams.n, scryptParams.r, scryptParams.p, derivedKey.data(), @@ -83,7 +79,7 @@ EncryptedPayload::EncryptedPayload(const Data& password, const Data& data, const auto result = aes_encrypt_key128(derivedKey.data(), &ctx); assert(result == EXIT_SUCCESS); if (result == EXIT_SUCCESS) { - Data iv = params.cipherParams.iv; + Data iv = this->params.cipherParams.iv; encrypted = Data(data.size()); aes_ctr_encrypt(data.data(), encrypted.data(), static_cast(data.size()), iv.data(), aes_ctr_cbuf_inc, &ctx); @@ -100,19 +96,17 @@ Data EncryptedPayload::decrypt(const Data& password) const { auto derivedKey = Data(); auto mac = Data(); - if (params.kdfParams.which() == 0) { - auto scryptParams = boost::get(params.kdfParams); - derivedKey.resize(scryptParams.defaultDesiredKeyLength); - scrypt(password.data(), password.size(), scryptParams.salt.data(), - scryptParams.salt.size(), scryptParams.n, scryptParams.r, scryptParams.p, derivedKey.data(), - scryptParams.defaultDesiredKeyLength); + if (auto* scryptParams = std::get_if(¶ms.kdfParams); scryptParams) { + derivedKey.resize(scryptParams->defaultDesiredKeyLength); + scrypt(password.data(), password.size(), scryptParams->salt.data(), + scryptParams->salt.size(), scryptParams->n, scryptParams->r, scryptParams->p, derivedKey.data(), + scryptParams->defaultDesiredKeyLength); mac = computeMAC(derivedKey.end() - 16, derivedKey.end(), encrypted); - } else if (params.kdfParams.which() == 1) { - auto pbkdf2Params = boost::get(params.kdfParams); - derivedKey.resize(pbkdf2Params.defaultDesiredKeyLength); - pbkdf2_hmac_sha256(password.data(), static_cast(password.size()), pbkdf2Params.salt.data(), - static_cast(pbkdf2Params.salt.size()), pbkdf2Params.iterations, derivedKey.data(), - pbkdf2Params.defaultDesiredKeyLength); + } else if (auto* pbkdf2Params = std::get_if(¶ms.kdfParams); pbkdf2Params) { + derivedKey.resize(pbkdf2Params->defaultDesiredKeyLength); + pbkdf2_hmac_sha256(password.data(), static_cast(password.size()), pbkdf2Params->salt.data(), + static_cast(pbkdf2Params->salt.size()), pbkdf2Params->iterations, derivedKey.data(), + pbkdf2Params->defaultDesiredKeyLength); mac = computeMAC(derivedKey.end() - 16, derivedKey.end(), encrypted); } else { throw DecryptionError::unsupportedKDF; diff --git a/src/Keystore/EncryptionParameters.h b/src/Keystore/EncryptionParameters.h index edd368e19cb..6592b9756cd 100644 --- a/src/Keystore/EncryptionParameters.h +++ b/src/Keystore/EncryptionParameters.h @@ -12,7 +12,7 @@ #include "Data.h" #include -#include +#include #include #include @@ -40,12 +40,12 @@ struct EncryptionParameters { AESParameters cipherParams = AESParameters(); /// Key derivation function parameters. - boost::variant kdfParams = ScryptParameters(); + std::variant kdfParams = ScryptParameters(); EncryptionParameters() = default; /// Initializes with standard values. - EncryptionParameters(AESParameters cipherParams, boost::variant kdfParams) + EncryptionParameters(AESParameters cipherParams, std::variant kdfParams) : cipherParams(std::move(cipherParams)) , kdfParams(std::move(kdfParams)) {} diff --git a/tests/Keystore/StoredKeyTests.cpp b/tests/Keystore/StoredKeyTests.cpp index f68af94833d..e792c0f7ab5 100644 --- a/tests/Keystore/StoredKeyTests.cpp +++ b/tests/Keystore/StoredKeyTests.cpp @@ -297,10 +297,10 @@ TEST(StoredKey, LoadPBKDF2Key) { EXPECT_EQ(key.id, "3198bc9c-6672-5ab3-d995-4942343ae5b6"); const auto& payload = key.payload; - ASSERT_TRUE(payload.params.kdfParams.which() == 1); - EXPECT_EQ(boost::get(payload.params.kdfParams).desiredKeyLength, 32ul); - EXPECT_EQ(boost::get(payload.params.kdfParams).iterations, 262144ul); - EXPECT_EQ(hex(boost::get(payload.params.kdfParams).salt), "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd"); + ASSERT_TRUE(std::holds_alternative(payload.params.kdfParams)); + EXPECT_EQ(std::get(payload.params.kdfParams).desiredKeyLength, 32ul); + EXPECT_EQ(std::get(payload.params.kdfParams).iterations, 262144ul); + EXPECT_EQ(hex(std::get(payload.params.kdfParams).salt), "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd"); EXPECT_EQ(hex(payload.decrypt(TW::data("testpassword"))), "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d"); } @@ -346,12 +346,12 @@ TEST(StoredKey, ReadWallet) { EXPECT_EQ(hex(header._mac), "2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097"); EXPECT_EQ(hex(header.params.cipherParams.iv), "83dbcc02d8ccb40e466191a123791e0e"); - ASSERT_TRUE(header.params.kdfParams.which() == 0); - EXPECT_EQ(boost::get(header.params.kdfParams).desiredKeyLength, 32ul); - EXPECT_EQ(boost::get(header.params.kdfParams).n, 262144ul); - EXPECT_EQ(boost::get(header.params.kdfParams).p, 8ul); - EXPECT_EQ(boost::get(header.params.kdfParams).r, 1ul); - EXPECT_EQ(hex(boost::get(header.params.kdfParams).salt), "ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19"); + ASSERT_TRUE(std::holds_alternative(header.params.kdfParams)); + EXPECT_EQ(std::get(header.params.kdfParams).desiredKeyLength, 32ul); + EXPECT_EQ(std::get(header.params.kdfParams).n, 262144ul); + EXPECT_EQ(std::get(header.params.kdfParams).p, 8ul); + EXPECT_EQ(std::get(header.params.kdfParams).r, 1ul); + EXPECT_EQ(hex(std::get(header.params.kdfParams).salt), "ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19"); } TEST(StoredKey, ReadMyEtherWallet) { From 5dec537f069be8ef4d3ee10ba9358934ffdd89c6 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 14 Sep 2022 06:46:05 +0200 Subject: [PATCH 075/497] [Improvements]: add json signatures to cosmos signing output (#2569) * feat(cosmos): add evmos support for json signing * feat(cosmos): add signature to cosmos.proto Update Signer.cpp Update SignerTests.cpp for evmos * feat(cosmos): add signatures also in protobuf signing * feat(cosmos): use coin type in json serialization * improvements(cosmos): fix per review * Update src/proto/Cosmos.proto Co-authored-by: Adam V <13562139+catenocrypt@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Adam V <13562139+catenocrypt@users.noreply.github.com> Co-authored-by: Adam V <13562139+catenocrypt@users.noreply.github.com> --- src/Cosmos/JsonSerialization.cpp | 16 +++-- src/Cosmos/JsonSerialization.h | 4 +- src/Cosmos/Signer.cpp | 11 +++- src/Cosmos/Signer.h | 2 +- src/proto/Cosmos.proto | 2 + tests/Evmos/SignerTests.cpp | 90 +++++++++++++++++++++++++++ tests/FIO/TWFIOTests.cpp | 12 ++-- tests/FIO/TransactionBuilderTests.cpp | 26 ++++---- 8 files changed, 135 insertions(+), 28 deletions(-) create mode 100644 tests/Evmos/SignerTests.cpp diff --git a/src/Cosmos/JsonSerialization.cpp b/src/Cosmos/JsonSerialization.cpp index 0b4879f98b9..bb7e28c98b8 100644 --- a/src/Cosmos/JsonSerialization.cpp +++ b/src/Cosmos/JsonSerialization.cpp @@ -25,8 +25,16 @@ const string TYPE_PREFIX_MSG_UNDELEGATE = "cosmos-sdk/MsgUndelegate"; const string TYPE_PREFIX_MSG_REDELEGATE = "cosmos-sdk/MsgBeginRedelegate"; const string TYPE_PREFIX_MSG_WITHDRAW_REWARD = "cosmos-sdk/MsgWithdrawDelegationReward"; const string TYPE_PREFIX_PUBLIC_KEY = "tendermint/PubKeySecp256k1"; +const string TYPE_EVMOS_PREFIX_PUBLIC_KEY = "ethermint/PubKeyEthSecp256k1"; const string TYPE_PREFIX_WASM_MSG_EXECUTE = "wasm/MsgExecuteContract"; +static inline std::string coinTypeToPrefixPublicKey(TWCoinType coin) noexcept { + if (coin == TWCoinTypeNativeEvmos) { + return TYPE_EVMOS_PREFIX_PUBLIC_KEY; + } + return TYPE_PREFIX_PUBLIC_KEY; +} + static string broadcastMode(Proto::BroadcastMode mode) { switch (mode) { case Proto::BroadcastMode::BLOCK: @@ -183,10 +191,10 @@ static json messagesJSON(const Proto::SigningInput& input) { return j; } -static json signatureJSON(const Data& signature, const Data& pubkey) { +json signatureJSON(const Data& signature, const Data& pubkey, TWCoinType coin) { return { {"pub_key", { - {"type", TYPE_PREFIX_PUBLIC_KEY}, + {"type", coinTypeToPrefixPublicKey(coin)}, {"value", Base64::encode(pubkey)} }}, {"signature", Base64::encode(signature)} @@ -204,7 +212,7 @@ json signaturePreimageJSON(const Proto::SigningInput& input) { }; } -json transactionJSON(const Proto::SigningInput& input, const Data& signature) { +json transactionJSON(const Proto::SigningInput& input, const Data& signature, TWCoinType coin) { auto privateKey = PrivateKey(input.private_key()); auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); json tx = { @@ -212,7 +220,7 @@ json transactionJSON(const Proto::SigningInput& input, const Data& signature) { {"memo", input.memo()}, {"msg", messagesJSON(input)}, {"signatures", json::array({ - signatureJSON(signature, Data(publicKey.bytes)) + signatureJSON(signature, Data(publicKey.bytes), coin) })} }; return broadcastJSON(tx, input.mode()); diff --git a/src/Cosmos/JsonSerialization.h b/src/Cosmos/JsonSerialization.h index 3de2cd43443..72212d972f9 100644 --- a/src/Cosmos/JsonSerialization.h +++ b/src/Cosmos/JsonSerialization.h @@ -8,6 +8,7 @@ #include "Data.h" #include "../proto/Cosmos.pb.h" +#include #include extern const std::string TYPE_PREFIX_MSG_SEND; @@ -24,6 +25,7 @@ using string = std::string; using json = nlohmann::json; json signaturePreimageJSON(const Proto::SigningInput& input); -json transactionJSON(const Proto::SigningInput& input, const Data& signature); +json transactionJSON(const Proto::SigningInput& input, const Data& signature, TWCoinType coin); +json signatureJSON(const Data& signature, const Data& pubkey, TWCoinType coin); } // namespace TW::Cosmos::json diff --git a/src/Cosmos/Signer.cpp b/src/Cosmos/Signer.cpp index 6ef51e88af2..b8b538ad8f5 100644 --- a/src/Cosmos/Signer.cpp +++ b/src/Cosmos/Signer.cpp @@ -17,7 +17,7 @@ namespace TW::Cosmos { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input, TWCoinType coin) noexcept { switch (input.signing_mode()) { case Proto::JSON: - return signJsonSerialized(input); + return signJsonSerialized(input, coin); case Proto::Protobuf: default: @@ -25,7 +25,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input, TWCoinType c } } -Proto::SigningOutput Signer::signJsonSerialized(const Proto::SigningInput& input) noexcept { +Proto::SigningOutput Signer::signJsonSerialized(const Proto::SigningInput& input, TWCoinType coin) noexcept { auto key = PrivateKey(input.private_key()); auto preimage = Json::signaturePreimageJSON(input).dump(); auto hash = Hash::sha256(preimage); @@ -33,16 +33,18 @@ Proto::SigningOutput Signer::signJsonSerialized(const Proto::SigningInput& input auto output = Proto::SigningOutput(); auto signature = Data(signedHash.begin(), signedHash.end() - 1); - auto txJson = Json::transactionJSON(input, signature); + auto txJson = Json::transactionJSON(input, signature, coin); output.set_json(txJson.dump()); output.set_signature(signature.data(), signature.size()); output.set_serialized(""); output.set_error(""); + output.set_signature_json(txJson["tx"]["signatures"].dump()); return output; } Proto::SigningOutput Signer::signProtobuf(const Proto::SigningInput& input, TWCoinType coin) noexcept { using namespace Protobuf; + using namespace Json; try { const auto serializedTxBody = buildProtoTxBody(input); const auto serializedAuthInfo = buildAuthInfo(input, coin); @@ -51,10 +53,13 @@ Proto::SigningOutput Signer::signProtobuf(const Proto::SigningInput& input, TWCo auto output = Proto::SigningOutput(); const std::string jsonSerialized = buildProtoTxJson(input, serializedTxRaw); + auto publicKey = PrivateKey(input.private_key()).getPublicKey(TWPublicKeyTypeSECP256k1); + auto signatures = nlohmann::json::array({signatureJSON(signature, publicKey.bytes, coin)}); output.set_serialized(jsonSerialized); output.set_signature(signature.data(), signature.size()); output.set_json(""); output.set_error(""); + output.set_signature_json(signatures.dump()); return output; } catch (const std::exception& ex) { auto output = Proto::SigningOutput(); diff --git a/src/Cosmos/Signer.h b/src/Cosmos/Signer.h index b380af3b1ea..4a3407021e7 100644 --- a/src/Cosmos/Signer.h +++ b/src/Cosmos/Signer.h @@ -20,7 +20,7 @@ class Signer { static Proto::SigningOutput sign(const Proto::SigningInput& input, TWCoinType coin) noexcept; /// Signs a Proto::SigningInput transaction, using Json serialization - static Proto::SigningOutput signJsonSerialized(const Proto::SigningInput& input) noexcept; + static Proto::SigningOutput signJsonSerialized(const Proto::SigningInput& input, TWCoinType coin) noexcept; /// Signs a Proto::SigningInput transaction, using binary Protobuf serialization static Proto::SigningOutput signProtobuf(const Proto::SigningInput& input, TWCoinType coin) noexcept; diff --git a/src/proto/Cosmos.proto b/src/proto/Cosmos.proto index 64401fac061..0aa1497fc6f 100644 --- a/src/proto/Cosmos.proto +++ b/src/proto/Cosmos.proto @@ -318,4 +318,6 @@ message SigningOutput { // Set in case of error string error = 4; + // signatures array json string + string signature_json = 5; } diff --git a/tests/Evmos/SignerTests.cpp b/tests/Evmos/SignerTests.cpp new file mode 100644 index 00000000000..dee1cb4ae35 --- /dev/null +++ b/tests/Evmos/SignerTests.cpp @@ -0,0 +1,90 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "Base64.h" +#include "proto/Cosmos.pb.h" +#include "Cosmos/Address.h" +#include "Cosmos/Signer.h" + +#include + +#include +#include + +namespace TW::Cosmos::evmos::tests { + +TEST(EvmosSigner, SignTxJsonEthermintKeyType) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::JSON); // obsolete + input.set_account_number(1037); + input.set_chain_id("evmos_9001-2"); + input.set_memo(""); + input.set_sequence(8); + + auto fromAddress = Address("evmos", parse_hex("BC2DA90C84049370D1B7C528BC164BC588833F21")); + auto toAddress = Address("evmos", parse_hex("12E8FE8B81ECC1F4F774EA6EC8DF267138B9F2D9")); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_send_coins_message(); + message.set_from_address(fromAddress.string()); + message.set_to_address(toAddress.string()); + auto amountOfTx = message.add_amounts(); + amountOfTx->set_denom("muon"); + amountOfTx->set_amount("1"); + + auto& fee = *input.mutable_fee(); + fee.set_gas(200000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("muon"); + amountOfFee->set_amount("200"); + + auto privateKey = parse_hex("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeNativeEvmos); + auto anotherExpectedJson =R"( + { + "mode":"block", + "tx":{"fee":{"amount":[{"amount":"200","denom":"muon"}],"gas":"200000"}, + "memo":"", + "msg":[{"type":"cosmos-sdk/MsgSend", + "value":{"amount":[{"amount":"1","denom":"muon"}], + "from_address":"evmos1hsk6jryyqjfhp5dhc55tc9jtckygx0ep4mur4z", + "to_address":"evmos1zt50azupanqlfam5afhv3hexwyutnuke45f6ye"}}], + "signatures": + [ + { + "pub_key": + { + "type":"ethermint/PubKeyEthSecp256k1", + "value":"AlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3F" + }, + "signature":"RWt8aaBxdMAeEjym8toWskJ6WaJpEF9Ciucz2lAHkvNnTicGpzxwTUzJbJXRirSnGkejhISaYtDw2RBiq0vg5w==" + } + ]} + })"_json; + + /// This tx is not broadcasted, we just want to test the signature format (ethermint/PubKeyEthSecp256k1) + EXPECT_EQ(anotherExpectedJson, nlohmann::json::parse(output.json())); + + auto signatures = nlohmann::json::parse(output.signature_json()); + + auto expectedSignatures = R"( + [ + { + "pub_key": + { + "type":"ethermint/PubKeyEthSecp256k1", + "value":"AlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3F" + }, + "signature":"RWt8aaBxdMAeEjym8toWskJ6WaJpEF9Ciucz2lAHkvNnTicGpzxwTUzJbJXRirSnGkejhISaYtDw2RBiq0vg5w==" + } + ])"_json; + EXPECT_EQ(signatures, expectedSignatures); +} + +} diff --git a/tests/FIO/TWFIOTests.cpp b/tests/FIO/TWFIOTests.cpp index 790320b054f..cd2af1396f2 100644 --- a/tests/FIO/TWFIOTests.cpp +++ b/tests/FIO/TWFIOTests.cpp @@ -38,7 +38,7 @@ TEST(TWFIO, Address) { ASSERT_TRUE(TWAnyAddressEqual(address.get(), address2.get())); } -const Data chainId = parse_hex("4e46572250454b796d7296eec9e8896327ea82dd40f2cd74cf1b1d8ba90bcd77"); +const Data gChainId = parse_hex("4e46572250454b796d7296eec9e8896327ea82dd40f2cd74cf1b1d8ba90bcd77"); // 5KEDWtAUJcFX6Vz38WXsAQAv2geNqT7UaZC8gYu9kTuryr3qkri FIO6m1fMdTpRkRBnedvYshXCxLFiC5suRU8KDfx8xxtXp2hntxpnf const PrivateKey privKeyBA = PrivateKey(parse_hex("ba0828d5734b65e3bcc2c51c93dfc26dd71bd666cc0273adee77d73d9a322035")); const PublicKey pubKey6M = privKeyBA.getPublicKey(TWPublicKeyTypeSECP256k1); @@ -47,7 +47,7 @@ const Address addr6M(pubKey6M); TEST(TWFIO, RegisterFioAddress) { Proto::SigningInput input; input.set_expiry(1579784511); - input.mutable_chain_params()->set_chain_id(string(chainId.begin(), chainId.end())); + input.mutable_chain_params()->set_chain_id(string(gChainId.begin(), gChainId.end())); input.mutable_chain_params()->set_head_block_number(39881); input.mutable_chain_params()->set_ref_block_prefix(4279583376); input.set_private_key(string(privKeyBA.bytes.begin(), privKeyBA.bytes.end())); @@ -65,7 +65,7 @@ TEST(TWFIO, RegisterFioAddress) { TEST(TWFIO, AddPubAddress) { Proto::SigningInput input; input.set_expiry(1579729429); - input.mutable_chain_params()->set_chain_id(string(chainId.begin(), chainId.end())); + input.mutable_chain_params()->set_chain_id(string(gChainId.begin(), gChainId.end())); input.mutable_chain_params()->set_head_block_number(11565); input.mutable_chain_params()->set_ref_block_prefix(4281229859); input.set_private_key(string(privKeyBA.bytes.begin(), privKeyBA.bytes.end())); @@ -92,7 +92,7 @@ TEST(TWFIO, AddPubAddress) { TEST(TWFIO, Transfer) { Proto::SigningInput input; input.set_expiry(1579790000); - input.mutable_chain_params()->set_chain_id(string(chainId.begin(), chainId.end())); + input.mutable_chain_params()->set_chain_id(string(gChainId.begin(), gChainId.end())); input.mutable_chain_params()->set_head_block_number(50000); input.mutable_chain_params()->set_ref_block_prefix(4000123456); input.set_private_key(string(privKeyBA.bytes.begin(), privKeyBA.bytes.end())); @@ -110,7 +110,7 @@ TEST(TWFIO, Transfer) { TEST(TWFIO, RenewFioAddress) { Proto::SigningInput input; input.set_expiry(1579785000); - input.mutable_chain_params()->set_chain_id(string(chainId.begin(), chainId.end())); + input.mutable_chain_params()->set_chain_id(string(gChainId.begin(), gChainId.end())); input.mutable_chain_params()->set_head_block_number(39881); input.mutable_chain_params()->set_ref_block_prefix(4279583376); input.set_private_key(string(privKeyBA.bytes.begin(), privKeyBA.bytes.end())); @@ -128,7 +128,7 @@ TEST(TWFIO, RenewFioAddress) { TEST(TWFIO, NewFundsRequest) { Proto::SigningInput input; input.set_expiry(1579785000); - input.mutable_chain_params()->set_chain_id(string(chainId.begin(), chainId.end())); + input.mutable_chain_params()->set_chain_id(string(gChainId.begin(), gChainId.end())); input.mutable_chain_params()->set_head_block_number(39881); input.mutable_chain_params()->set_ref_block_prefix(4279583376); input.set_private_key(string(privKeyBA.bytes.begin(), privKeyBA.bytes.end())); diff --git a/tests/FIO/TransactionBuilderTests.cpp b/tests/FIO/TransactionBuilderTests.cpp index dd0a08581f5..c0caf1faa12 100644 --- a/tests/FIO/TransactionBuilderTests.cpp +++ b/tests/FIO/TransactionBuilderTests.cpp @@ -20,9 +20,9 @@ using namespace std; const Data chainId = parse_hex("4e46572250454b796d7296eec9e8896327ea82dd40f2cd74cf1b1d8ba90bcd77"); // 5KEDWtAUJcFX6Vz38WXsAQAv2geNqT7UaZC8gYu9kTuryr3qkri FIO6m1fMdTpRkRBnedvYshXCxLFiC5suRU8KDfx8xxtXp2hntxpnf -const PrivateKey privKeyBA = PrivateKey(parse_hex("ba0828d5734b65e3bcc2c51c93dfc26dd71bd666cc0273adee77d73d9a322035")); -const PublicKey pubKey6M = privKeyBA.getPublicKey(TWPublicKeyTypeSECP256k1); -const Address addr6M(pubKey6M); +const PrivateKey gPrivKeyBA = PrivateKey(parse_hex("ba0828d5734b65e3bcc2c51c93dfc26dd71bd666cc0273adee77d73d9a322035")); +const PublicKey gPubKey6MA = gPrivKeyBA.getPublicKey(TWPublicKeyTypeSECP256k1); +const Address gAddr6M(gPubKey6MA); TEST(FIOTransactionBuilder, RegisterFioAddressGeneric) { Proto::SigningInput input; @@ -30,10 +30,10 @@ TEST(FIOTransactionBuilder, RegisterFioAddressGeneric) { input.mutable_chain_params()->set_chain_id(string(chainId.begin(), chainId.end())); input.mutable_chain_params()->set_head_block_number(39881); input.mutable_chain_params()->set_ref_block_prefix(4279583376); - input.set_private_key(string(privKeyBA.bytes.begin(), privKeyBA.bytes.end())); + input.set_private_key(string(gPrivKeyBA.bytes.begin(), gPrivKeyBA.bytes.end())); input.set_tpid("rewards@wallet"); input.mutable_action()->mutable_register_fio_address_message()->set_fio_address("adam@fiotestnet"); - input.mutable_action()->mutable_register_fio_address_message()->set_owner_fio_public_key(addr6M.string()); + input.mutable_action()->mutable_register_fio_address_message()->set_owner_fio_public_key(gAddr6M.string()); input.mutable_action()->mutable_register_fio_address_message()->set_fee(5000000000); auto json = TransactionBuilder::sign(input); @@ -45,7 +45,7 @@ TEST(FIOTransactionBuilder, RegisterFioAddress) { ChainParams chainParams{chainId, 39881, 4279583376}; uint64_t fee = 5000000000; - string t = TransactionBuilder::createRegisterFioAddress(addr6M, privKeyBA, "adam@fiotestnet", + string t = TransactionBuilder::createRegisterFioAddress(gAddr6M, gPrivKeyBA, "adam@fiotestnet", chainParams, fee, "rewards@wallet", 1579784511); EXPECT_EQ(R"({"compression":"none","packed_context_free_data":"","packed_trx":"3f99295ec99b904215ff0000000001003056372503a85b0000c6eaa66498ba01102b2f46fca756b200000000a8ed3232650f6164616d4066696f746573746e65743546494f366d31664d645470526b52426e6564765973685843784c4669433573755255384b44667838787874587032686e7478706e6600f2052a01000000102b2f46fca756b20e726577617264734077616c6c657400","signatures":["SIG_K1_K19ugLriG3ApYgjJCRDsy21p9xgsjbDtqBuZrmAEix9XYzndR1kNbJ6fXCngMJMAhxUHfwHAsPnh58otXiJZkazaM1EkS5"]})", t); @@ -54,7 +54,7 @@ TEST(FIOTransactionBuilder, RegisterFioAddress) { TEST(FIOTransactionBuilder, AddPubAddress) { ChainParams chainParams{chainId, 11565, 4281229859}; - string t = TransactionBuilder::createAddPubAddress(addr6M, privKeyBA, "adam@fiotestnet", {{"BTC", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v"}, {"ETH", "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51"}, {"BNB", "bnb1ts3dg54apwlvr9hupv2n0j6e46q54znnusjk9s"}}, + string t = TransactionBuilder::createAddPubAddress(gAddr6M, gPrivKeyBA, "adam@fiotestnet", {{"BTC", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v"}, {"ETH", "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51"}, {"BNB", "bnb1ts3dg54apwlvr9hupv2n0j6e46q54znnusjk9s"}}, chainParams, 0, "rewards@wallet", 1579729429); EXPECT_EQ(R"({"compression":"none","packed_context_free_data":"","packed_trx":"15c2285e2d2d23622eff0000000001003056372503a85b0000c6eaa664523201102b2f46fca756b200000000a8ed3232c9010f6164616d4066696f746573746e65740303425443034254432a626331717679343037347267676b647232707a773576706e6e3632656730736d7a6c787770373064377603455448034554482a30786365356342366339324461333762624261393142643430443443394434443732344133613846353103424e4203424e422a626e6231747333646735346170776c76723968757076326e306a366534367135347a6e6e75736a6b39730000000000000000102b2f46fca756b20e726577617264734077616c6c657400","signatures":["SIG_K1_K3zimaMKU8cBhVRPw46KM2u7uQWaAKXrnoeYZ7MEbp6sVJcDQmQR2RtdavpUPwkAnYUkd8NqLun8H48tcxZBcTUgkiPGVJ"]})", t); @@ -66,7 +66,7 @@ TEST(FIOTransactionBuilder, Transfer) { uint64_t amount = 1000000000; uint64_t fee = 250000000; - string t = TransactionBuilder::createTransfer(addr6M, privKeyBA, payee, amount, + string t = TransactionBuilder::createTransfer(gAddr6M, gPrivKeyBA, payee, amount, chainParams, fee, "rewards@wallet", 1579790000); EXPECT_EQ(R"({"compression":"none","packed_context_free_data":"","packed_trx":"b0ae295e50c3400a6dee00000000010000980ad20ca85be0e1d195ba85e7cd01102b2f46fca756b200000000a8ed32325d3546494f37754d5a6f6565693548745841443234433479436b70575762663234626a597472524e6a57646d474358485a63637775694500ca9a3b0000000080b2e60e00000000102b2f46fca756b20e726577617264734077616c6c657400","signatures":["SIG_K1_K9VRCnvaTYN7vgcoVKVXgyJTdKUGV8hLXgFLoEbvqAcFxy7DXQ1rSnAfEuabi4ATkgmvnpaSBdVFN7TBtM1wrbZYqeJQw9"]})", t); @@ -76,7 +76,7 @@ TEST(FIOTransactionBuilder, RenewFioAddress) { ChainParams chainParams{chainId, 39881, 4279583376}; uint64_t fee = 3000000000; - string t = TransactionBuilder::createRenewFioAddress(addr6M, privKeyBA, "nick@fiotestnet", + string t = TransactionBuilder::createRenewFioAddress(gAddr6M, gPrivKeyBA, "nick@fiotestnet", chainParams, fee, "rewards@wallet", 1579785000); EXPECT_EQ(R"({"compression":"none","packed_context_free_data":"","packed_trx":"289b295ec99b904215ff0000000001003056372503a85b80b1ba2919aea6ba01102b2f46fca756b200000000a8ed32322f0f6e69636b4066696f746573746e6574005ed0b200000000102b2f46fca756b20e726577617264734077616c6c657400","signatures":["SIG_K1_Jxz7oCJ7Z4ECsxqb2utqBcyP3zPQCeQCBws9wWQjyptUKoWVk2AyCVEqtdMHJwqtLniio5Z7npMnaZB8E4pa2G75P9uGkb"]})", t); @@ -87,7 +87,7 @@ TEST(FIOTransactionBuilder, NewFundsRequest) { ChainParams chainParams{chainId, 18484, 3712870657}; const Data iv = parse_hex("000102030405060708090a0b0c0d0e0f"); // use fixed iv for testability string t = TransactionBuilder::createNewFundsRequest( - Address("FIO5NMm9Vf3NjYFnhoc7yxTCrLW963KPUCzeMGv3SJ6zR3GMez4ub"), privKeyBA, + Address("FIO5NMm9Vf3NjYFnhoc7yxTCrLW963KPUCzeMGv3SJ6zR3GMez4ub"), gPrivKeyBA, "tag@fiotestnet", "FIO7iYHtDhs45smFgSqLyJ6Zi4D3YG8K5bZGyxmshLCDXXBPbbmJN", "dapixbp@fiotestnet", "14R4wEsGT58chmqo7nB65Dy4je6TiijDWc", "1", "BTC", "payment", "", "", chainParams, 800000000, "", 1583528215, iv); @@ -98,7 +98,7 @@ TEST(FIOTransactionBuilder, NewFundsRequest) { uint64_t fee = 3000000000; const Data iv = parse_hex("000102030405060708090a0b0c0d0e0f"); // use fixed iv for testability - string t = TransactionBuilder::createNewFundsRequest(addr6M, privKeyBA, + string t = TransactionBuilder::createNewFundsRequest(gAddr6M, gPrivKeyBA, "mario@fiotestnet", "FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o", "alice@fiotestnet", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v", "5", "BTC", "Memo", "Hash", "https://trustwallet.com", chainParams, fee, "rewards@wallet", 1579785000, iv); @@ -107,7 +107,7 @@ TEST(FIOTransactionBuilder, NewFundsRequest) { } TEST(FIOTransaction, ActionRegisterFioAddressInternal) { - RegisterFioAddressData radata("adam@fiotestnet", addr6M.string(), + RegisterFioAddressData radata("adam@fiotestnet", gAddr6M.string(), 5000000000, "rewards@wallet", "qdfejz2a5wpl"); Data ser1; radata.serialize(ser1); @@ -240,7 +240,7 @@ TEST(FIOTransactionBuilder, expirySetDefault) { // May throw nlohmann::json::type_error void createTxWithChainParam(const ChainParams& paramIn, ChainParams& paramOut) { - string tx = TransactionBuilder::createAddPubAddress(addr6M, privKeyBA, "adam@fiotestnet", {{"BTC", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v"}}, + string tx = TransactionBuilder::createAddPubAddress(gAddr6M, gPrivKeyBA, "adam@fiotestnet", {{"BTC", "bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v"}}, paramIn, 0, "rewards@wallet", 1579729429); // retrieve chain params from encoded tx; parse out packed tx try { From 9014082e18106325be746f54a37d7a17926d05c4 Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Wed, 14 Sep 2022 16:45:47 +0100 Subject: [PATCH 076/497] [Improvements] Move TWAnyAddress logic to an internal class (#2529) * [Improvements] Move TWAnyAddress logic to an internal class Improve TWAnyAddress memory handling by moving its logic to an internal class Address. Also, change internal representation to std::string * Fix ambigious class name issue * Change approach to use factory methods; other minor fixes --- src/AnyAddress.cpp | 32 +++++++++++++++++++++ src/AnyAddress.h | 41 +++++++++++++++++++++++++++ src/interface/TWAnyAddress.cpp | 37 +++++++++--------------- tests/AnyAddressTests.cpp | 34 ++++++++++++++++++++++ tests/FIO/EncryptionTests.cpp | 4 +-- tests/FIO/TWFIOTests.cpp | 4 +-- tests/FIO/TransactionBuilderTests.cpp | 4 +-- 7 files changed, 127 insertions(+), 29 deletions(-) create mode 100644 src/AnyAddress.cpp create mode 100644 src/AnyAddress.h create mode 100644 tests/AnyAddressTests.cpp diff --git a/src/AnyAddress.cpp b/src/AnyAddress.cpp new file mode 100644 index 00000000000..504e309da1c --- /dev/null +++ b/src/AnyAddress.cpp @@ -0,0 +1,32 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "AnyAddress.h" + +#include +#include "Coin.h" + +namespace TW { + +Data AnyAddress::getData() const { + return TW::addressToData(coin, address); +} + +AnyAddress* AnyAddress::createAddress(const std::string& address, enum TWCoinType coin) { + auto normalized = TW::normalizeAddress(coin, address); + if (normalized.empty()) { + return nullptr; + } + + return new AnyAddress{.address = std::move(normalized), .coin = coin}; +} + +AnyAddress* AnyAddress::createAddress(const PublicKey& publicKey, enum TWCoinType coin) { + auto derivedAddress = TW::deriveAddress(coin, publicKey); + return new AnyAddress{.address = std::move(derivedAddress), .coin = coin}; +} + +} // namespace TW diff --git a/src/AnyAddress.h b/src/AnyAddress.h new file mode 100644 index 00000000000..78e8878a2fd --- /dev/null +++ b/src/AnyAddress.h @@ -0,0 +1,41 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" +#include "PublicKey.h" + +#include +#include +#include +#include + +namespace TW { + +class AnyAddress { +public: + std::string address; + + enum TWCoinType coin; + + static AnyAddress* createAddress(const std::string& address, enum TWCoinType coin); + static AnyAddress* createAddress(const PublicKey& publicKey, enum TWCoinType coin); + + Data getData() const; +}; + +inline bool operator==(const AnyAddress& lhs, const AnyAddress& rhs) { + return lhs.address == rhs.address && lhs.coin == rhs.coin; +} + +} // namespace TW + +/// Wrapper for C interface. +struct TWAnyAddress { + // Pointer to the underlying implementation + TW::AnyAddress* impl; +}; diff --git a/src/interface/TWAnyAddress.cpp b/src/interface/TWAnyAddress.cpp index abb7a0e5fdd..57594be3847 100644 --- a/src/interface/TWAnyAddress.cpp +++ b/src/interface/TWAnyAddress.cpp @@ -8,18 +8,12 @@ #include #include - -#include "../Coin.h" - -using namespace TW; - -struct TWAnyAddress { - TWString* address; - enum TWCoinType coin; -}; +#include "Data.h" +#include "Coin.h" +#include "AnyAddress.h" bool TWAnyAddressEqual(struct TWAnyAddress* _Nonnull lhs, struct TWAnyAddress* _Nonnull rhs) { - return TWStringEqual(lhs->address, rhs->address) && lhs->coin == rhs->coin; + return *lhs->impl == *rhs->impl; } bool TWAnyAddressIsValid(TWString* _Nonnull string, enum TWCoinType coin) { @@ -30,35 +24,32 @@ bool TWAnyAddressIsValid(TWString* _Nonnull string, enum TWCoinType coin) { struct TWAnyAddress* _Nullable TWAnyAddressCreateWithString(TWString* _Nonnull string, enum TWCoinType coin) { const auto& address = *reinterpret_cast(string); - auto normalized = TW::normalizeAddress(coin, address); - if (normalized.empty()) { return nullptr; } - return new TWAnyAddress{TWStringCreateWithUTF8Bytes(normalized.c_str()), coin}; + auto *impl = TW::AnyAddress::createAddress(address, coin); + if (impl == nullptr) { + return nullptr; + } + return new TWAnyAddress{impl}; } struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKey( struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin) { - auto address = TW::deriveAddress(coin, publicKey->impl); - return new TWAnyAddress{TWStringCreateWithUTF8Bytes(address.c_str()), coin}; + return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin)}; } void TWAnyAddressDelete(struct TWAnyAddress* _Nonnull address) { - TWStringDelete(address->address); + delete address->impl; delete address; } TWString* _Nonnull TWAnyAddressDescription(struct TWAnyAddress* _Nonnull address) { - return TWStringCreateWithUTF8Bytes(TWStringUTF8Bytes(address->address)); + return TWStringCreateWithUTF8Bytes(address->impl->address.c_str()); } enum TWCoinType TWAnyAddressCoin(struct TWAnyAddress* _Nonnull address) { - return address->coin; + return address->impl->coin; } TWData* _Nonnull TWAnyAddressData(struct TWAnyAddress* _Nonnull address) { - const auto& string = *reinterpret_cast(address->address); - Data data; - try { - data = TW::addressToData(address->coin, string); - } catch (...) {} + auto data = address->impl->getData(); return TWDataCreateWithBytes(data.data(), data.size()); } diff --git a/tests/AnyAddressTests.cpp b/tests/AnyAddressTests.cpp new file mode 100644 index 00000000000..bc7dc5af2b2 --- /dev/null +++ b/tests/AnyAddressTests.cpp @@ -0,0 +1,34 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "AnyAddress.h" +#include "HexCoding.h" + +#include + +namespace TW::tests { + +constexpr auto ANY_ADDRESS_TEST_ADDRESS = "bc1qcj2vfjec3c3luf9fx9vddnglhh9gawmncmgxhz"; +constexpr auto ANY_ADDRESS_TEST_PUBKEY = "02753f5c275e1847ba4d2fd3df36ad00af2e165650b35fe3991e9c9c46f68b12bc"; + +TEST(AnyAddress, createFromString) { + std::unique_ptr addr(AnyAddress::createAddress(ANY_ADDRESS_TEST_ADDRESS, TWCoinTypeBitcoin)); + EXPECT_EQ(ANY_ADDRESS_TEST_ADDRESS, addr->address); +} + +TEST(AnyAddress, createFromPubKey) { + const Data key = parse_hex(ANY_ADDRESS_TEST_PUBKEY); + PublicKey publicKey(key, TWPublicKeyTypeSECP256k1); + std::unique_ptr addr(AnyAddress::createAddress(publicKey, TWCoinTypeBitcoin)); + EXPECT_EQ(ANY_ADDRESS_TEST_ADDRESS, addr->address); +} + +TEST(AnyAddress, createFromWrongString) { + std::unique_ptr addr(AnyAddress::createAddress("1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaax", TWCoinTypeBitcoin)); + EXPECT_EQ(nullptr, addr); +} + +} // namespace TW::tests diff --git a/tests/FIO/EncryptionTests.cpp b/tests/FIO/EncryptionTests.cpp index 3fc2171ce40..ac0c2ff9321 100644 --- a/tests/FIO/EncryptionTests.cpp +++ b/tests/FIO/EncryptionTests.cpp @@ -15,7 +15,7 @@ #include -namespace TW::FIO::tests { +namespace TW::FIO::EncryptionTests { using namespace std; @@ -183,4 +183,4 @@ TEST(FIOEncryption, encryptEncodeDecodeDecrypt) { EXPECT_EQ(hex(decrypted), hex(message)); } -} // namespace TW::FIO::tests +} // namespace TW::FIO::EncryptionTests diff --git a/tests/FIO/TWFIOTests.cpp b/tests/FIO/TWFIOTests.cpp index cd2af1396f2..acbdf2e889a 100644 --- a/tests/FIO/TWFIOTests.cpp +++ b/tests/FIO/TWFIOTests.cpp @@ -16,7 +16,7 @@ #include -namespace TW::FIO::tests { +namespace TW::FIO::TWFIOTests { using namespace std; @@ -153,4 +153,4 @@ TEST(TWFIO, NewFundsRequest) { output.json().substr(0, 195)); } -} // namespace TW::FIO::tests +} // namespace TW::FIO::TWFIOTests diff --git a/tests/FIO/TransactionBuilderTests.cpp b/tests/FIO/TransactionBuilderTests.cpp index c0caf1faa12..ff7b73d9484 100644 --- a/tests/FIO/TransactionBuilderTests.cpp +++ b/tests/FIO/TransactionBuilderTests.cpp @@ -15,7 +15,7 @@ #include #include -namespace TW::FIO::tests { +namespace TW::FIO::TransactionBuilderTests { using namespace std; const Data chainId = parse_hex("4e46572250454b796d7296eec9e8896327ea82dd40f2cd74cf1b1d8ba90bcd77"); @@ -346,4 +346,4 @@ TEST(FIOTransactionBuilder, encodeString) { } } -} // namespace TW::FIO::tests +} // namespace TW::FIO::TransactionBuilderTests From 8760e5936b2ad3fe7b3d6ca499dfbab12c7ed861 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Sat, 17 Sep 2022 14:23:08 +0200 Subject: [PATCH 077/497] [evmos]: authz tx unit tests (#2573) * feat(evmos): add a unit test of authz tx for evmos --- src/proto/Cosmos.proto | 1 + tests/Evmos/SignerTests.cpp | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/proto/Cosmos.proto b/src/proto/Cosmos.proto index 0aa1497fc6f..ddeacaa1f5a 100644 --- a/src/proto/Cosmos.proto +++ b/src/proto/Cosmos.proto @@ -318,6 +318,7 @@ message SigningOutput { // Set in case of error string error = 4; + // signatures array json string string signature_json = 5; } diff --git a/tests/Evmos/SignerTests.cpp b/tests/Evmos/SignerTests.cpp index dee1cb4ae35..53f599038eb 100644 --- a/tests/Evmos/SignerTests.cpp +++ b/tests/Evmos/SignerTests.cpp @@ -9,6 +9,7 @@ #include "proto/Cosmos.pb.h" #include "Cosmos/Address.h" #include "Cosmos/Signer.h" +#include "../interface/TWTestUtilities.h" #include @@ -87,4 +88,39 @@ TEST(EvmosSigner, SignTxJsonEthermintKeyType) { EXPECT_EQ(signatures, expectedSignatures); } +TEST(EvmosSigner, CompoundingAuthz) { + // Successfully broadcasted https://www.mintscan.io/evmos/txs/8D811CEC078420C41220F0B584EA0AC037763380FAC31E0E352E4BB4D1D18B79 + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(2139877); + input.set_chain_id("evmos_9001-2"); + input.set_memo(""); + input.set_sequence(3); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_auth_grant(); + message.set_granter("evmos12m9grgas60yk0kult076vxnsrqz8xpjy9rpf3e"); + message.set_grantee("evmos18fzq4nac28gfma6gqfvkpwrgpm5ctar2z9mxf3"); + auto& grant_stake = *message.mutable_grant_stake(); + grant_stake.mutable_allow_list()->add_address("evmosvaloper1umk407eed7af6anvut6llg2zevnf0dn0feqqny"); + grant_stake.set_authorization_type(TW::Cosmos::Proto::Message_AuthorizationType_DELEGATE); + message.set_expiration(1692309600); + + auto& fee = *input.mutable_fee(); + fee.set_gas(180859); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("aevmos"); + amountOfFee->set_amount("4521475000000000"); + + auto privateKey = parse_hex("79bcbded1a5678ab34e6d9db9ad78e4e480e7b22723cc5fbf59e843732e1a8e5"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeNativeEvmos); + auto expected = R"( + { + "mode":"BROADCAST_MODE_BLOCK", + "tx_bytes":"CvUBCvIBCh4vY29zbW9zLmF1dGh6LnYxYmV0YTEuTXNnR3JhbnQSzwEKLGV2bW9zMTJtOWdyZ2FzNjB5azBrdWx0MDc2dnhuc3Jxejh4cGp5OXJwZjNlEixldm1vczE4ZnpxNG5hYzI4Z2ZtYTZncWZ2a3B3cmdwbTVjdGFyMno5bXhmMxpxCmcKKi9jb3Ntb3Muc3Rha2luZy52MWJldGExLlN0YWtlQXV0aG9yaXphdGlvbhI5EjUKM2V2bW9zdmFsb3BlcjF1bWs0MDdlZWQ3YWY2YW52dXQ2bGxnMnpldm5mMGRuMGZlcXFueSABEgYI4LD6pgYSfQpZCk8KKC9ldGhlcm1pbnQuY3J5cHRvLnYxLmV0aHNlY3AyNTZrMS5QdWJLZXkSIwohA4B2WHbj6sH/GWE7z/YW5PRnXYFGaGRAov7gZZI2Fv2nEgQKAggBGAMSIAoaCgZhZXZtb3MSEDQ1MjE0NzUwMDAwMDAwMDAQ+4QLGkAm17CZgB7m+CPVlITnrHosklMTL9zrUeGRs8FL8N0GcRami9zdJ+e3xuXOtJmwP7G6QNh85CRYjFj8a8lpmmJM" + })"; + assertJSONEqual(output.serialized(), expected); +} } From 8f5eb89217caa600e64ad742669ddc5b95820240 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sat, 17 Sep 2022 22:45:37 +0900 Subject: [PATCH 078/497] Add TypeScript KeyStore (#2559) * Add ts keystone namespace and interface * reuse cpp derivation path for swift * redefine IKeyStore interfaces, add ExtensionStorage * refactor and add FileSystemStorage * Add TWDerivationPathTests * Add KeyStore/FileSystemStorage tests * Test get key and export mnemonic * Fix code coverage * Add chrome storage mock and tests * bump coverage stats * move generated d.ts to src folder * simplify closures * update wasm ci to ubuntu-22.04 --- .github/workflows/wasm-ci.yml | 2 +- codegen/lib/ts_helper.rb | 8 +- coverage.stats | 2 +- include/TrustWalletCore/TWDerivationPath.h | 103 ++ .../TrustWalletCore/TWDerivationPathIndex.h | 53 + src/DerivationPath.h | 62 +- src/interface/TWDerivationPath.cpp | 65 + src/interface/TWDerivationPathIndex.cpp | 32 + swift/Sources/DerivationPath.Index.swift | 49 - swift/Sources/DerivationPath.swift | 117 -- .../Extensions/DerivationPath+Extension.swift | 119 ++ swift/Tests/DerivationPathTests.swift | 31 +- tests/{ => Keystore}/DerivationPathTests.cpp | 26 +- tests/Nervos/TWNervosAddressTests.cpp | 18 +- tests/Ripple/TWRippleAddressTests.cpp | 15 +- tests/Ronin/TWAnySignerTests.cpp | 2 + tests/Solana/TWSolanaAddressTests.cpp | 13 +- tests/interface/TWDerivationPathTests.cpp | 64 + wasm/index.ts | 5 +- wasm/package-lock.json | 1389 ++++++++++++++++- wasm/package.json | 4 +- wasm/src/keystore/default-impl.ts | 159 ++ wasm/src/keystore/extension-storage.ts | 72 + wasm/src/keystore/fs-storage.ts | 45 + wasm/src/keystore/index.ts | 10 + wasm/src/keystore/types.ts | 93 ++ wasm/tests/KeyStore+extension.test.ts | 68 + wasm/tests/KeyStore+fs.test.ts | 70 + wasm/tests/mock.ts | 53 + wasm/tests/setup.test.ts | 3 + 30 files changed, 2514 insertions(+), 238 deletions(-) create mode 100644 include/TrustWalletCore/TWDerivationPath.h create mode 100644 include/TrustWalletCore/TWDerivationPathIndex.h create mode 100644 src/interface/TWDerivationPath.cpp create mode 100644 src/interface/TWDerivationPathIndex.cpp delete mode 100644 swift/Sources/DerivationPath.Index.swift delete mode 100644 swift/Sources/DerivationPath.swift create mode 100644 swift/Sources/Extensions/DerivationPath+Extension.swift rename tests/{ => Keystore}/DerivationPathTests.cpp (95%) create mode 100644 tests/interface/TWDerivationPathTests.cpp create mode 100644 wasm/src/keystore/default-impl.ts create mode 100644 wasm/src/keystore/extension-storage.ts create mode 100644 wasm/src/keystore/fs-storage.ts create mode 100644 wasm/src/keystore/index.ts create mode 100644 wasm/src/keystore/types.ts create mode 100644 wasm/tests/KeyStore+extension.test.ts create mode 100644 wasm/tests/KeyStore+fs.test.ts create mode 100644 wasm/tests/mock.ts diff --git a/.github/workflows/wasm-ci.yml b/.github/workflows/wasm-ci.yml index 64a2449e9ad..d383cc49195 100644 --- a/.github/workflows/wasm-ci.yml +++ b/.github/workflows/wasm-ci.yml @@ -8,7 +8,7 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 diff --git a/codegen/lib/ts_helper.rb b/codegen/lib/ts_helper.rb index 78fb1908ea3..a75027b8999 100644 --- a/codegen/lib/ts_helper.rb +++ b/codegen/lib/ts_helper.rb @@ -47,8 +47,9 @@ def self.type(t) def self.combine_declaration_files wasm_src = File.expand_path(File.join(File.dirname(__FILE__), '../../wasm')) header = File.expand_path('copyright_header.erb', File.join(File.dirname(__FILE__), 'templates')) + combined_path = "#{wasm_src}/src/wallet-core.d.ts" - combined = File.open("#{wasm_src}/wallet-core.d.ts", 'w') + combined = File.open(combined_path, 'w') # append header combined.write(File.read(header)) @@ -65,10 +66,9 @@ def self.combine_declaration_files FileUtils.remove_dir("#{wasm_src}/lib/generated", true) # generate WalletCore interface - interface = "export interface WalletCore {\n" - combined = File.open("#{wasm_src}/wallet-core.d.ts", 'r') + combined = File.open(combined_path, 'r') all_lines = combined.read combined.close @@ -86,7 +86,7 @@ def self.combine_declaration_files end interface += "}\n" - File.open("#{wasm_src}/wallet-core.d.ts", 'a') do |file| + File.open(combined_path, 'a') do |file| file << interface end end diff --git a/coverage.stats b/coverage.stats index 7aebde8602a..b99dacf6dff 100644 --- a/coverage.stats +++ b/coverage.stats @@ -1 +1 @@ -94.9 \ No newline at end of file +95.0 \ No newline at end of file diff --git a/include/TrustWalletCore/TWDerivationPath.h b/include/TrustWalletCore/TWDerivationPath.h new file mode 100644 index 00000000000..910288f600f --- /dev/null +++ b/include/TrustWalletCore/TWDerivationPath.h @@ -0,0 +1,103 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" +#include "TWCoinType.h" +#include "TWDerivationPath.h" +#include "TWPurpose.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +/// Represents a BIP44 DerivationPath in C++. +TW_EXPORT_CLASS +struct TWDerivationPath; + +/// Creates a new DerivationPath with a purpose, coin, account, change and address. +/// Must be deleted with TWDerivationPathDelete after use. +/// +/// \param purpose The purpose of the Path. +/// \param coin The coin type of the Path. +/// \param account The derivation of the Path. +/// \param change The derivation path of the Path. +/// \param address hex encoded public key. +/// \return A new DerivationPath. +TW_EXPORT_STATIC_METHOD +struct TWDerivationPath* _Nonnull TWDerivationPathCreate(enum TWPurpose purpose, uint32_t coin, uint32_t account, uint32_t change, uint32_t address); + +/// Creates a new DerivationPath with a string +/// +/// \param string The string of the Path. +/// \return A new DerivationPath or null if string is invalid. +TW_EXPORT_STATIC_METHOD +struct TWDerivationPath* _Nullable TWDerivationPathCreateWithString(TWString* _Nonnull string); + +/// Deletes a DerivationPath. +/// +/// \param path DerivationPath to delete. +TW_EXPORT_METHOD +void TWDerivationPathDelete(struct TWDerivationPath* _Nonnull path); + +/// Returns the index component of a DerivationPath. +/// +/// \param path DerivationPath to get the index of. +/// \param index The index component of the DerivationPath. +/// \return DerivationPathIndex or null if index is invalid. +TW_EXPORT_METHOD +struct TWDerivationPathIndex* _Nullable TWDerivationPathIndexAt(struct TWDerivationPath* _Nonnull path, uint32_t index); + +/// Returns the indices count of a DerivationPath. +/// +/// \param path DerivationPath to get the indices count of. +/// \return The indices count of the DerivationPath. +TW_EXPORT_METHOD +uint32_t TWDerivationPathIndicesCount(struct TWDerivationPath* _Nonnull path); + +/// Returns the purpose enum of a DerivationPath. +/// +/// \param path DerivationPath to get the purpose of. +/// \return DerivationPathPurpose. +TW_EXPORT_PROPERTY +enum TWPurpose TWDerivationPathPurpose(struct TWDerivationPath* _Nonnull path); + +/// Returns the coin value of a derivation path. +/// +/// \param path DerivationPath to get the coin of. +/// \return The coin part of the DerivationPath. +TW_EXPORT_PROPERTY +uint32_t TWDerivationPathCoin(struct TWDerivationPath* _Nonnull path); + +/// Returns the account value of a derivation path. +/// +/// \param path DerivationPath to get the account of. +/// \return the account part of a derivation path. +TW_EXPORT_PROPERTY +uint32_t TWDerivationPathAccount(struct TWDerivationPath* _Nonnull path); + +/// Returns the change value of a derivation path. +/// +/// \param path DerivationPath to get the change of. +/// \return The change part of a derivation path. +TW_EXPORT_PROPERTY +uint32_t TWDerivationPathChange(struct TWDerivationPath* _Nonnull path); + +/// Returns the address value of a derivation path. +/// +/// \param path DerivationPath to get the address of. +/// \return The address part of the derivation path. +TW_EXPORT_PROPERTY +uint32_t TWDerivationPathAddress(struct TWDerivationPath* _Nonnull path); + +/// Returns the string description of a derivation path. +/// +/// \param path DerivationPath to get the address of. +/// \return The string description of the derivation path. +TW_EXPORT_PROPERTY +TWString* _Nonnull TWDerivationPathDescription(struct TWDerivationPath* _Nonnull path); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWDerivationPathIndex.h b/include/TrustWalletCore/TWDerivationPathIndex.h new file mode 100644 index 00000000000..72bd2b8344e --- /dev/null +++ b/include/TrustWalletCore/TWDerivationPathIndex.h @@ -0,0 +1,53 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +/// Represents a derivation path index in C++ with value and hardened flag. +TW_EXPORT_CLASS +struct TWDerivationPathIndex; + +/// Creates a new Index with a value and hardened flag. +/// Must be deleted with TWDerivationPathIndexDelete after use. +/// +/// \param value Index value +/// \param hardened Indicates if the Index is hardened. +/// \return A new Index. +TW_EXPORT_STATIC_METHOD +struct TWDerivationPathIndex* _Nonnull TWDerivationPathIndexCreate(uint32_t value, bool hardened); + +/// Deletes an Index. +/// +/// \param index Index to delete. +TW_EXPORT_METHOD +void TWDerivationPathIndexDelete(struct TWDerivationPathIndex* _Nonnull index); + +/// Returns numeric value of an Index. +/// +/// \param index Index to get the numeric value of. +TW_EXPORT_PROPERTY +uint32_t TWDerivationPathIndexValue(struct TWDerivationPathIndex* _Nonnull index); + +/// Returns hardened flag of an Index. +/// +/// \param index Index to get hardened flag. +/// \return true if hardened, false otherwise. +TW_EXPORT_PROPERTY +bool TWDerivationPathIndexHardened(struct TWDerivationPathIndex* _Nonnull index); + +/// Returns the string description of a derivation path index. +/// +/// \param path Index to get the address of. +/// \return The string description of the derivation path index. +TW_EXPORT_PROPERTY +TWString* _Nonnull TWDerivationPathIndexDescription(struct TWDerivationPathIndex* _Nonnull index); + +TW_EXTERN_C_END diff --git a/src/DerivationPath.h b/src/DerivationPath.h index c18d90069ac..6ab0bca83ef 100644 --- a/src/DerivationPath.h +++ b/src/DerivationPath.h @@ -21,7 +21,8 @@ struct DerivationPathIndex { bool hardened = true; DerivationPathIndex() = default; - DerivationPathIndex(uint32_t value, bool hardened = true) : value(value), hardened(hardened) {} + DerivationPathIndex(uint32_t value, bool hardened = true) + : value(value), hardened(hardened) {} /// The derivation index. uint32_t derivationIndex() const { @@ -46,63 +47,85 @@ struct DerivationPath { std::vector indices; TWPurpose purpose() const { - if (indices.size() == 0) { return TWPurposeBIP44; } + if (indices.size() == 0) { + return TWPurposeBIP44; + } return static_cast(indices[0].value); } void setPurpose(TWPurpose v) { - if (indices.size() == 0) { return; } + if (indices.size() == 0) { + return; + } indices[0] = DerivationPathIndex(v, /* hardened: */ true); } uint32_t coin() const { - if (indices.size() <= 1) { return TWCoinTypeBitcoin; } + if (indices.size() <= 1) { + return TWCoinTypeBitcoin; + } return indices[1].value; } void setCoin(uint32_t v) { - if (indices.size() <= 1) { return; } + if (indices.size() <= 1) { + return; + } indices[1] = DerivationPathIndex(v, /* hardened: */ true); } uint32_t account() const { - if (indices.size() <= 2) { return 0; } + if (indices.size() <= 2) { + return 0; + } return indices[2].value; } void setAccount(uint32_t v) { - if (indices.size() <= 2) { return; } + if (indices.size() <= 2) { + return; + } indices[2] = DerivationPathIndex(v, /* hardened: */ true); } uint32_t change() const { - if (indices.size() <= 3) { return 0; } + if (indices.size() <= 3) { + return 0; + } return indices[3].value; } void setChange(uint32_t v) { - if (indices.size() <= 3) { return; } + if (indices.size() <= 3) { + return; + } indices[3] = DerivationPathIndex(v, /* hardened: */ false); } uint32_t address() const { - if (indices.size() <= 4) { return 0; } + if (indices.size() <= 4) { + return 0; + } return indices[4].value; } void setAddress(uint32_t v) { - if (indices.size() <= 4) { return; } + if (indices.size() <= 4) { + return; + } indices[4] = DerivationPathIndex(v, /* hardened: */ false); } DerivationPath() = default; - explicit DerivationPath(std::initializer_list l) : indices(l) {} - explicit DerivationPath(std::vector indices) : indices(std::move(indices)) {} + explicit DerivationPath(std::initializer_list l) + : indices(l) {} + explicit DerivationPath(std::vector indices) + : indices(std::move(indices)) {} /// Creates a `DerivationPath` by BIP44 components. DerivationPath(TWPurpose purpose, uint32_t coin, uint32_t account, uint32_t change, - uint32_t address) - : indices(std::vector(5)) { + uint32_t address) + : indices(std::vector(5)) { setPurpose(purpose); setCoin(coin); setAccount(account); @@ -130,3 +153,12 @@ inline bool operator==(const DerivationPath& lhs, const DerivationPath& rhs) { } } // namespace TW + +/// Wrapper for C interface. +struct TWDerivationPath { + TW::DerivationPath impl; +}; + +struct TWDerivationPathIndex { + TW::DerivationPathIndex impl; +}; diff --git a/src/interface/TWDerivationPath.cpp b/src/interface/TWDerivationPath.cpp new file mode 100644 index 00000000000..f48bc051d77 --- /dev/null +++ b/src/interface/TWDerivationPath.cpp @@ -0,0 +1,65 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include +#include + +#include "../DerivationPath.h" + +using namespace TW; + +struct TWDerivationPath* _Nonnull TWDerivationPathCreate(enum TWPurpose purpose, uint32_t coin, uint32_t account, uint32_t change, uint32_t address) { + return new TWDerivationPath{DerivationPath(purpose, coin, account, change, address)}; +} + +struct TWDerivationPath* _Nullable TWDerivationPathCreateWithString(TWString* _Nonnull string) { + auto& str = *reinterpret_cast(string); + try { + return new TWDerivationPath{DerivationPath(str)}; + } catch (...) { + return nullptr; + } +} + +void TWDerivationPathDelete(struct TWDerivationPath* _Nonnull path) { + delete path; +} + +uint32_t TWDerivationPathIndicesCount(struct TWDerivationPath* _Nonnull path) { + return static_cast(path->impl.indices.size()); +} + +struct TWDerivationPathIndex* _Nullable TWDerivationPathIndexAt(struct TWDerivationPath* _Nonnull path, uint32_t index) { + if (index >= path->impl.indices.size()) { + return nullptr; + } + return new TWDerivationPathIndex{path->impl.indices[index]}; +} + +enum TWPurpose TWDerivationPathPurpose(struct TWDerivationPath* _Nonnull path) { + return path->impl.purpose(); +} + +uint32_t TWDerivationPathCoin(struct TWDerivationPath* _Nonnull path) { + return path->impl.coin(); +} + +uint32_t TWDerivationPathAccount(struct TWDerivationPath* _Nonnull path) { + return path->impl.account(); +} + +uint32_t TWDerivationPathChange(struct TWDerivationPath* _Nonnull path) { + return path->impl.change(); +} + +uint32_t TWDerivationPathAddress(struct TWDerivationPath* _Nonnull path) { + return path->impl.address(); +} + +TWString* _Nonnull TWDerivationPathDescription(struct TWDerivationPath* _Nonnull path) { + return TWStringCreateWithUTF8Bytes(path->impl.string().c_str()); +} diff --git a/src/interface/TWDerivationPathIndex.cpp b/src/interface/TWDerivationPathIndex.cpp new file mode 100644 index 00000000000..f443955191e --- /dev/null +++ b/src/interface/TWDerivationPathIndex.cpp @@ -0,0 +1,32 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include + +#include "../DerivationPath.h" + +using namespace TW; + +struct TWDerivationPathIndex* _Nonnull TWDerivationPathIndexCreate(uint32_t value, bool hardened) { + return new TWDerivationPathIndex{DerivationPathIndex(value, hardened)}; +} + +void TWDerivationPathIndexDelete(struct TWDerivationPathIndex* _Nonnull index) { + delete index; +} + +uint32_t TWDerivationPathIndexValue(struct TWDerivationPathIndex* _Nonnull index) { + return index->impl.value; +} + +bool TWDerivationPathIndexHardened(struct TWDerivationPathIndex* _Nonnull index) { + return index->impl.hardened; +} + +TWString* _Nonnull TWDerivationPathIndexDescription(struct TWDerivationPathIndex* _Nonnull index) { + return TWStringCreateWithUTF8Bytes(index->impl.string().c_str()); +} diff --git a/swift/Sources/DerivationPath.Index.swift b/swift/Sources/DerivationPath.Index.swift deleted file mode 100644 index 09a43cc45c3..00000000000 --- a/swift/Sources/DerivationPath.Index.swift +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright © 2017-2020 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -import Foundation - -extension DerivationPath { - /// Derivation path index. - public struct Index: Codable, Hashable, CustomStringConvertible { - /// Index value. - public var value: UInt32 - - /// Whether the index is hardened. - public var hardened: Bool - - /// The derivation index. - public var derivationIndex: UInt32 { - if hardened { - return UInt32(value) | 0x80000000 - } else { - return UInt32(value) - } - } - - public init(_ value: UInt32, hardened: Bool = true) { - self.value = value - self.hardened = hardened - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(value) - hasher.combine(hardened) - } - - public static func == (lhs: Index, rhs: Index) -> Bool { - return lhs.value == rhs.value && lhs.hardened == rhs.hardened - } - - public var description: String { - if hardened { - return "\(value)'" - } else { - return value.description - } - } - } -} diff --git a/swift/Sources/DerivationPath.swift b/swift/Sources/DerivationPath.swift deleted file mode 100644 index 5e15395d7f6..00000000000 --- a/swift/Sources/DerivationPath.swift +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright © 2017-2020 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -import Foundation - -/// Represents a hierarchical deterministic derivation path. -public struct DerivationPath: Codable, Hashable, CustomStringConvertible { - var indexCount = 5 - - /// List of indices in the derivation path. - public private(set) var indices = [Index]() - - /// Address purpose, each coin will have a different value. - public var purpose: Purpose { - get { - return Purpose(rawValue: indices[0].value)! - } - set { - indices[0] = Index(newValue.rawValue, hardened: true) - } - } - - /// Coin type distinguishes between main net, test net, and forks. - public var coinType: UInt32 { - get { - return indices[1].value - } - set { - indices[1] = Index(newValue, hardened: true) - } - } - - /// Account number. - public var account: UInt32 { - get { - return indices[2].value - } - set { - indices[2] = Index(newValue, hardened: true) - } - } - - /// Change or private addresses will set this to 1. - public var change: UInt32 { - get { - return indices[3].value - } - set { - indices[3] = Index(newValue, hardened: false) - } - } - - /// Address number - public var address: UInt32 { - get { - return indices[4].value - } - set { - indices[4] = Index(newValue, hardened: false) - } - } - - init(indices: [Index]) { - precondition(indices.count == indexCount, "Not enough indices") - self.indices = indices - } - - /// Creates a `DerivationPath` by components. - public init(purpose: Purpose, coin: UInt32, account: UInt32 = 0, change: UInt32 = 0, address: UInt32 = 0) { - self.indices = [Index](repeating: Index(0), count: indexCount) - self.purpose = purpose - self.coinType = coin - self.account = account - self.change = change - self.address = address - } - - /// Creates a derivation path with a string description like `m/10/0/2'/3` - public init?(_ string: String) { - let components = string.split(separator: "/") - for component in components { - if component == "m" { - continue - } - if component.hasSuffix("'") { - guard let index = UInt32(component.dropLast()) else { - return nil - } - indices.append(Index(index, hardened: true)) - } else { - guard let index = UInt32(component) else { - return nil - } - indices.append(Index(index, hardened: false)) - } - } - guard indices.count == indexCount else { - return nil - } - } - - /// String representation. - public var description: String { - return "m/" + indices.map({ $0.description }).joined(separator: "/") - } - - public func hash(into hasher: inout Hasher) { - indices.forEach { hasher.combine($0) } - } - - public static func == (lhs: DerivationPath, rhs: DerivationPath) -> Bool { - return lhs.indices == rhs.indices - } -} diff --git a/swift/Sources/Extensions/DerivationPath+Extension.swift b/swift/Sources/Extensions/DerivationPath+Extension.swift new file mode 100644 index 00000000000..09678360e85 --- /dev/null +++ b/swift/Sources/Extensions/DerivationPath+Extension.swift @@ -0,0 +1,119 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import Foundation + +extension DerivationPath: Equatable, Hashable, CustomStringConvertible { + + public typealias Index = DerivationPathIndex + + public static func == (lhs: DerivationPath, rhs: DerivationPath) -> Bool { + return lhs.description == rhs.description + } + + public var coinType: UInt32 { + coin + } + + public var indices: [Index] { + var result = [Index]() + for i in 0.. DerivationPathIndex? { + return self.indexAt(index: UInt32(index)) + } + + public func hash(into hasher: inout Hasher) { + let count = indicesCount() + for i in 0.. Bool { + return lhs.value == rhs.value && lhs.hardened == rhs.hardened + } + + public convenience init(_ value: UInt32, hardened: Bool) { + self.init(value: value, hardened: hardened) + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(value) + hasher.combine(hardened) + } +} + +extension DerivationPathIndex: Codable { + private enum CodingKeys: String, CodingKey { + case value + case hardened + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(value, forKey: .value) + try container.encode(hardened, forKey: .hardened) + } + + public convenience init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + let value = try container.decode(UInt32.self, forKey: .value) + let hardened = try container.decode(Bool.self, forKey: .hardened) + self.init(value: value, hardened: hardened) + } +} diff --git a/swift/Tests/DerivationPathTests.swift b/swift/Tests/DerivationPathTests.swift index e24ab38190a..3867d434847 100644 --- a/swift/Tests/DerivationPathTests.swift +++ b/swift/Tests/DerivationPathTests.swift @@ -10,6 +10,7 @@ import XCTest class DerivationPathTests: XCTestCase { func testInitWithIndices() { let path = DerivationPath(purpose: .bip44, coin: CoinType.ethereum.slip44Id, account: 0, change: 0, address: 0) + XCTAssertEqual(path.indices[0], DerivationPath.Index(44, hardened: true)) XCTAssertEqual(path.indices[1], DerivationPath.Index(60, hardened: true)) XCTAssertEqual(path.indices[2], DerivationPath.Index(0, hardened: true)) @@ -18,20 +19,20 @@ class DerivationPathTests: XCTestCase { } func testInitWithString() { - let path = DerivationPath("m/44'/60'/0'/0/0") - - XCTAssertNotNil(path) - XCTAssertEqual(path?.indices[0], DerivationPath.Index(44, hardened: true)) - XCTAssertEqual(path?.indices[1], DerivationPath.Index(60, hardened: true)) - XCTAssertEqual(path?.indices[2], DerivationPath.Index(0, hardened: true)) - XCTAssertEqual(path?.indices[3], DerivationPath.Index(0, hardened: false)) - XCTAssertEqual(path?.indices[4], DerivationPath.Index(0, hardened: false)) - - XCTAssertEqual(path?.purpose, Purpose(rawValue: 44)!) - XCTAssertEqual(path?.coinType, 60) - XCTAssertEqual(path?.account, 0) - XCTAssertEqual(path?.change, 0) - XCTAssertEqual(path?.address, 0) + let path = DerivationPath(string: "m/44'/60'/0'/0/0")! + let indices = path.indices + + XCTAssertEqual(indices[0], DerivationPath.Index(value: 44, hardened: true)) + XCTAssertEqual(indices[1], DerivationPath.Index(value: 60, hardened: true)) + XCTAssertEqual(indices[2], DerivationPath.Index(value: 0, hardened: true)) + XCTAssertEqual(indices[3], DerivationPath.Index(value: 0, hardened: false)) + XCTAssertEqual(indices[4], DerivationPath.Index(value: 0, hardened: false)) + + XCTAssertEqual(path.purpose, Purpose(rawValue: 44)!) + XCTAssertEqual(path.coinType, 60) + XCTAssertEqual(path.account, 0) + XCTAssertEqual(path.change, 0) + XCTAssertEqual(path.address, 0) } func testInitInvalid() { @@ -41,12 +42,14 @@ class DerivationPathTests: XCTestCase { func testDescription() { let path = DerivationPath("m/44'/60'/0'/0/0") + XCTAssertEqual(path?.description, "m/44'/60'/0'/0/0") } func testEqual() { let path1 = DerivationPath("m/44'/60'/0'/0/0") let path2 = DerivationPath("44'/60'/0'/0/0") + XCTAssertNotNil(path1) XCTAssertNotNil(path2) XCTAssertEqual(path1, path2) diff --git a/tests/DerivationPathTests.cpp b/tests/Keystore/DerivationPathTests.cpp similarity index 95% rename from tests/DerivationPathTests.cpp rename to tests/Keystore/DerivationPathTests.cpp index 563d247add2..62d21aab939 100644 --- a/tests/DerivationPathTests.cpp +++ b/tests/Keystore/DerivationPathTests.cpp @@ -1,11 +1,11 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "DerivationPath.h" #include "Coin.h" +#include "DerivationPath.h" #include #include @@ -14,22 +14,22 @@ namespace TW { TEST(DerivationPath, InitWithIndices) { const auto path = DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeEthereum), 0, 0, 0); - ASSERT_EQ(path.indices[0], DerivationPathIndex(44, /* hardened: */true)); - ASSERT_EQ(path.indices[1], DerivationPathIndex(60, /* hardened: */true)); - ASSERT_EQ(path.indices[2], DerivationPathIndex(0, /* hardened: */true)); - ASSERT_EQ(path.indices[3], DerivationPathIndex(0, /* hardened: */false)); - ASSERT_EQ(path.indices[4], DerivationPathIndex(0, /* hardened: */false)); + ASSERT_EQ(path.indices[0], DerivationPathIndex(44, /* hardened: */ true)); + ASSERT_EQ(path.indices[1], DerivationPathIndex(60, /* hardened: */ true)); + ASSERT_EQ(path.indices[2], DerivationPathIndex(0, /* hardened: */ true)); + ASSERT_EQ(path.indices[3], DerivationPathIndex(0, /* hardened: */ false)); + ASSERT_EQ(path.indices[4], DerivationPathIndex(0, /* hardened: */ false)); } TEST(DerivationPath, InitWithString) { ASSERT_NO_THROW(DerivationPath("m/44'/60'/0'/0/0")); const auto path = DerivationPath("m/44'/60'/0'/0/0"); - ASSERT_EQ(path.indices[0], DerivationPathIndex(44, /* hardened: */true)); - ASSERT_EQ(path.indices[1], DerivationPathIndex(60, /* hardened: */true)); - ASSERT_EQ(path.indices[2], DerivationPathIndex(0, /* hardened: */true)); - ASSERT_EQ(path.indices[3], DerivationPathIndex(0, /* hardened: */false)); - ASSERT_EQ(path.indices[4], DerivationPathIndex(0, /* hardened: */false)); + ASSERT_EQ(path.indices[0], DerivationPathIndex(44, /* hardened: */ true)); + ASSERT_EQ(path.indices[1], DerivationPathIndex(60, /* hardened: */ true)); + ASSERT_EQ(path.indices[2], DerivationPathIndex(0, /* hardened: */ true)); + ASSERT_EQ(path.indices[3], DerivationPathIndex(0, /* hardened: */ false)); + ASSERT_EQ(path.indices[4], DerivationPathIndex(0, /* hardened: */ false)); ASSERT_EQ(path.purpose(), 44); ASSERT_EQ(path.coin(), 60ul); @@ -94,4 +94,4 @@ TEST(Derivation, alternativeDerivation) { EXPECT_EQ(std::string(TW::derivationName(TWCoinTypeSolana, TWDerivationSolanaSolana)), "solana"); } -} // namespace +} // namespace TW diff --git a/tests/Nervos/TWNervosAddressTests.cpp b/tests/Nervos/TWNervosAddressTests.cpp index 2ba8dc05a0c..1fa5924000c 100644 --- a/tests/Nervos/TWNervosAddressTests.cpp +++ b/tests/Nervos/TWNervosAddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -13,20 +13,18 @@ namespace TW::Nervos::tests { -const auto ckbAddress = "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8furras980hksatlslfaktks7epf25"; +TEST(TWNervosAddress, Create) { + const auto ckbAddress = "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqwyk5x9erg8furras980hksatlslfaktks7epf25"; + const auto addr = WRAP(TWNervosAddress, TWNervosAddressCreateWithString(STRING(ckbAddress).get())); -TEST(TWBitcoinAddress, Create) { - TWNervosAddress* addr = TWNervosAddressCreateWithString(STRING(ckbAddress).get()); - - const auto codeCash = WRAPD(TWNervosAddressCodeHash(addr)); - const auto args = WRAPD(TWNervosAddressArgs(addr)); - const auto hashType = WRAPS(TWNervosAddressHashType(addr)); + const auto codeCash = WRAPD(TWNervosAddressCodeHash(addr.get())); + const auto args = WRAPD(TWNervosAddressArgs(addr.get())); + const auto hashType = WRAPS(TWNervosAddressHashType(addr.get())); + EXPECT_TRUE(TWNervosAddressIsValidString(STRING(ckbAddress).get())); assertHexEqual(codeCash, "9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8"); assertHexEqual(args, "c4b50c5c8d074f063ec0a77ded0eaff0fa7b65da"); assertStringsEqual(hashType, "type"); - - TWNervosAddressDelete(addr); } } // namespace TW::Nervos::tests diff --git a/tests/Ripple/TWRippleAddressTests.cpp b/tests/Ripple/TWRippleAddressTests.cpp index 7fd89c52c43..36e738592c1 100644 --- a/tests/Ripple/TWRippleAddressTests.cpp +++ b/tests/Ripple/TWRippleAddressTests.cpp @@ -7,14 +7,14 @@ #include "../interface/TWTestUtilities.h" #include +#include #include TEST(TWRipple, ExtendedKeys) { auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic( - STRING("ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal").get(), - STRING("TREZOR").get() - )); + STRING("ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal").get(), + STRING("TREZOR").get())); auto xpub = WRAPS(TWHDWalletGetExtendedPublicKey(wallet.get(), TWPurposeBIP44, TWCoinTypeXRP, TWHDVersionXPUB)); auto xprv = WRAPS(TWHDWalletGetExtendedPrivateKey(wallet.get(), TWPurposeBIP44, TWCoinTypeXRP, TWHDVersionXPRV)); @@ -22,3 +22,12 @@ TEST(TWRipple, ExtendedKeys) { assertStringsEqual(xpub, "xpub6D9oDY4gqFBtsFEonh5GTDiUm6nmij373YWzmYdshcnM4AFzdhUf55iZD33vNU2ZqfQJU5wiCJUgisMt2RHKDzhi1PbZfh5Y2NiiYJAQqUn"); assertStringsEqual(xprv, "xprv9zASp2XnzsdbemALgfYG65mkD4xHKGKFgKbPyAEG9HFNBMvr6AAQXHQ5MmqM66EnbJfe9TvYMy1bucz7hSQjG43NVizRZwJJYfLmeKo4nVB"); } + +TEST(TWRipple, XAddress) { + const auto string = STRING("XVfvixWZQKkcenFRYApCjpTUyJ4BePTe3jJv7beatUZvQYh"); + const auto xAddress = WRAP(TWRippleXAddress, TWRippleXAddressCreateWithString(string.get())); + + EXPECT_TRUE(TWRippleXAddressIsValidString(string.get())); + EXPECT_EQ(TWRippleXAddressTag(xAddress.get()), 12345ul); + assertStringsEqual(WRAPS(TWRippleXAddressDescription(xAddress.get())), "XVfvixWZQKkcenFRYApCjpTUyJ4BePTe3jJv7beatUZvQYh"); +} diff --git a/tests/Ronin/TWAnySignerTests.cpp b/tests/Ronin/TWAnySignerTests.cpp index e469380d2d2..3f852a1dab2 100644 --- a/tests/Ronin/TWAnySignerTests.cpp +++ b/tests/Ronin/TWAnySignerTests.cpp @@ -38,9 +38,11 @@ TEST(TWAnySignerRonin, Sign) { // sign test Ethereum::Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeRonin); ASSERT_EQ(hex(output.encoded()), expected); + EXPECT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeRonin)); } } // namespace TW::Ronin::tests diff --git a/tests/Solana/TWSolanaAddressTests.cpp b/tests/Solana/TWSolanaAddressTests.cpp index 0ce32caf5db..2ad4f854fcd 100644 --- a/tests/Solana/TWSolanaAddressTests.cpp +++ b/tests/Solana/TWSolanaAddressTests.cpp @@ -28,8 +28,13 @@ TEST(TWSolanaAddress, HDWallet) { } TEST(TWSolanaProgram, defaultTokenAddress) { - const char* serumToken = "SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"; - auto solanaAddress = WRAP(TWSolanaAddress, TWSolanaAddressCreateWithString(WRAPS(TWStringCreateWithUTF8Bytes("B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V")).get())); - auto address1 = WRAPS(TWSolanaAddressDefaultTokenAddress(solanaAddress.get(), WRAPS(TWStringCreateWithUTF8Bytes(serumToken)).get())); - EXPECT_EQ(std::string(TWStringUTF8Bytes(address1.get())), "EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); + const auto solAddress = STRING("B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); + const auto serumToken = STRING("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"); + + auto solanaAddress = WRAP(TWSolanaAddress, TWSolanaAddressCreateWithString(solAddress.get())); + auto description = WRAPS(TWSolanaAddressDescription(solanaAddress.get())); + auto tokenAddress = WRAPS(TWSolanaAddressDefaultTokenAddress(solanaAddress.get(), serumToken.get())); + + assertStringsEqual(tokenAddress, "EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); + assertStringsEqual(description, "B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); } diff --git a/tests/interface/TWDerivationPathTests.cpp b/tests/interface/TWDerivationPathTests.cpp new file mode 100644 index 00000000000..22cef1e8b32 --- /dev/null +++ b/tests/interface/TWDerivationPathTests.cpp @@ -0,0 +1,64 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "TWTestUtilities.h" +#include "TrustWalletCore/TWDerivation.h" +#include "TrustWalletCore/TWPurpose.h" +#include +#include + +#include + +TEST(TWDerivationPath, CreateWithString) { + const auto derivationPath = STRING("m/84'/1'/2'/3/4"); + + const auto path = WRAP(TWDerivationPath, TWDerivationPathCreateWithString(derivationPath.get())); + + EXPECT_EQ(5u, TWDerivationPathIndicesCount(path.get())); + EXPECT_EQ(TWPurposeBIP84, TWDerivationPathPurpose(path.get())); + EXPECT_EQ(1u, TWDerivationPathCoin(path.get())); + EXPECT_EQ(2u, TWDerivationPathAccount(path.get())); + EXPECT_EQ(3u, TWDerivationPathChange(path.get())); + EXPECT_EQ(4u, TWDerivationPathAddress(path.get())); + assertStringsEqual(WRAPS(TWDerivationPathDescription(path.get())), "m/84'/1'/2'/3/4"); + + const auto index0 = WRAP(TWDerivationPathIndex, TWDerivationPathIndexAt(path.get(), 0)); + const auto index3 = WRAP(TWDerivationPathIndex, TWDerivationPathIndexAt(path.get(), 3)); + + EXPECT_EQ(NULL, TWDerivationPathIndexAt(path.get(), 10)); + EXPECT_EQ(TWPurposeBIP84, TWDerivationPathIndexValue(index0.get())); + EXPECT_TRUE(TWDerivationPathIndexHardened(index0.get())); + + EXPECT_EQ(3u, TWDerivationPathIndexValue(index3.get())); + EXPECT_FALSE(TWDerivationPathIndexHardened(index3.get())); + assertStringsEqual(WRAPS(TWDerivationPathIndexDescription(index0.get())), "84'"); + + const auto path2 = WRAP(TWDerivationPath, TWDerivationPathCreateWithString(STRING("m/44'/501'").get())); + + EXPECT_EQ(2u, TWDerivationPathIndicesCount(path2.get())); + EXPECT_EQ(TWPurposeBIP44, TWDerivationPathPurpose(path2.get())); + EXPECT_EQ(501u, TWDerivationPathCoin(path2.get())); + EXPECT_EQ(0u, TWDerivationPathAccount(path2.get())); + EXPECT_EQ(0u, TWDerivationPathChange(path2.get())); + EXPECT_EQ(0u, TWDerivationPathAddress(path2.get())); +} + +TEST(TWDerivationPath, CreateWithCoin) { + + const auto path = WRAP(TWDerivationPath, TWDerivationPathCreate(TWPurposeBIP44, 60, 0, 0, 0)); + + EXPECT_EQ(5u, TWDerivationPathIndicesCount(path.get())); + EXPECT_EQ(TWPurposeBIP44, TWDerivationPathPurpose(path.get())); + EXPECT_EQ(60u, TWDerivationPathCoin(path.get())); + EXPECT_EQ(0u, TWDerivationPathAccount(path.get())); + EXPECT_EQ(0u, TWDerivationPathChange(path.get())); + EXPECT_EQ(0u, TWDerivationPathAddress(path.get())); + assertStringsEqual(WRAPS(TWDerivationPathDescription(path.get())), "m/44'/60'/0'/0/0"); + + const auto index = WRAP(TWDerivationPathIndex, TWDerivationPathIndexCreate(44, true)); + const auto description = WRAPS(TWDerivationPathIndexDescription(index.get())); + assertStringsEqual(description, "44'"); +} diff --git a/wasm/index.ts b/wasm/index.ts index 550165e7ca0..2e298c52d53 100644 --- a/wasm/index.ts +++ b/wasm/index.ts @@ -6,9 +6,10 @@ import * as Loader from "./lib/wallet-core"; import { TW } from "./generated/core_proto"; -import { WalletCore } from "./wallet-core"; +import { WalletCore } from "./src/wallet-core"; +import * as KeyStore from "./src/keystore"; declare function load(): Promise; export const initWasm: typeof load = Loader; -export { TW, WalletCore }; +export { TW, WalletCore, KeyStore }; diff --git a/wasm/package-lock.json b/wasm/package-lock.json index 55c9781bd2a..8697fe149e1 100644 --- a/wasm/package-lock.json +++ b/wasm/package-lock.json @@ -1,8 +1,1383 @@ { "name": "@trustwallet/wallet-core", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "@trustwallet/wallet-core", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "protobufjs": ">=6.11.3" + }, + "devDependencies": { + "@types/chai": "^4.3.0", + "@types/mocha": "^9.1.0", + "@types/node": "^18.7.18", + "@types/webextension-polyfill": "^0.9.0", + "buffer": "^6.0.3", + "chai": "^4.3.6", + "mocha": "^9.2.2", + "ts-node": "^10.7.0", + "typescript": "^4.6.3" + } + }, + "node_modules/@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", + "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-consumer": "0.8.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, + "node_modules/@types/chai": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", + "integrity": "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==", + "dev": true + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, + "node_modules/@types/mocha": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", + "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.7.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", + "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==" + }, + "node_modules/@types/webextension-polyfill": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.9.0.tgz", + "integrity": "sha512-HG1y1o2hK8ag6Y7dfkrAbfKmMIP+B0E6SwAzUfmQ1dDxEIdLTtMyrStY26suHBPrAL7Xw/chlDW02ugc3uXWtQ==", + "dev": true + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/loupe": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", + "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-node": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", + "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "0.7.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.0", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", + "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", + "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, "dependencies": { "@cspotcode/source-map-consumer": { "version": "0.8.0", @@ -115,9 +1490,15 @@ "dev": true }, "@types/node": { - "version": "17.0.38", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.38.tgz", - "integrity": "sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==" + "version": "18.7.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", + "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==" + }, + "@types/webextension-polyfill": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.9.0.tgz", + "integrity": "sha512-HG1y1o2hK8ag6Y7dfkrAbfKmMIP+B0E6SwAzUfmQ1dDxEIdLTtMyrStY26suHBPrAL7Xw/chlDW02ugc3uXWtQ==", + "dev": true }, "@ungap/promise-all-settled": { "version": "1.1.2", diff --git a/wasm/package.json b/wasm/package.json index 2b7fd5c5361..8ae7e3f0b3b 100644 --- a/wasm/package.json +++ b/wasm/package.json @@ -11,7 +11,7 @@ "codegen:js-browser": "pbjs -t static-module '../src/proto/*.proto' -w closure --no-delimited --force-long -o ../samples/wasm/core_proto.js", "codegen:ts": "pbts -o generated/core_proto.d.ts generated/core_proto.js", "clean": "rm -rf dist generated && mkdir -p dist/generated generated", - "build": "npm run clean && npm run generate && cp -R generated lib dist && tsc && cp wallet-core.d.ts dist", + "build": "npm run clean && npm run generate && cp -R generated lib dist && tsc && cp src/wallet-core.d.ts dist/src", "build-and-test": "npm run copy:wasm && npm run build && npm test", "copy:wasm": "mkdir -p lib && cp ../wasm-build/wasm/wallet-core.* lib", "copy:wasm-sample": "cp ../wasm-build/wasm/wallet-core.* ../samples/wasm/" @@ -35,6 +35,8 @@ "devDependencies": { "@types/chai": "^4.3.0", "@types/mocha": "^9.1.0", + "@types/node": "^18.7.18", + "@types/webextension-polyfill": "^0.9.0", "buffer": "^6.0.3", "chai": "^4.3.6", "mocha": "^9.2.2", diff --git a/wasm/src/keystore/default-impl.ts b/wasm/src/keystore/default-impl.ts new file mode 100644 index 00000000000..91da9b40f16 --- /dev/null +++ b/wasm/src/keystore/default-impl.ts @@ -0,0 +1,159 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import { WalletCore, CoinType, PrivateKey, StoredKey } from "../wallet-core"; +import * as Types from "./types"; + +export class Default implements Types.IKeyStore { + private readonly core: WalletCore; + private readonly storage: Types.IStorage; + + constructor(core: WalletCore, storage: Types.IStorage) { + this.core = core; + this.storage = storage; + } + + hasWallet(id: string): Promise { + return this.storage + .get(id) + .then((wallet) => true) + .catch((error) => false); + } + + load(id: string): Promise { + return this.storage.get(id); + } + + loadAll(): Promise { + return this.storage.loadAll(); + } + + delete(id: string, password: string): Promise { + return this.storage.delete(id, password); + } + + mapWallet(storedKey: StoredKey): Types.Wallet { + const json = storedKey.exportJSON(); + return JSON.parse(Buffer.from(json).toString()) as Types.Wallet; + } + + mapStoredKey(wallet: Types.Wallet): StoredKey { + const json = Buffer.from(JSON.stringify(wallet)); + return this.core.StoredKey.importJSON(json); + } + + importWallet(wallet: Types.Wallet): Promise { + return this.storage.set(wallet.id, wallet); + } + + import( + mnemonic: string, + name: string, + password: string, + coins: CoinType[] + ): Promise { + return new Promise((resolve, reject) => { + const { Mnemonic, StoredKey, HDWallet } = this.core; + + if (!Mnemonic.isValid(mnemonic)) { + throw Types.Error.InvalidMnemonic; + } + let pass = Buffer.from(password); + let storedKey = StoredKey.importHDWallet(mnemonic, name, pass, coins[0]); + let hdWallet = HDWallet.createWithMnemonic(mnemonic, ""); + coins.forEach((coin) => { + storedKey.accountForCoin(coin, hdWallet); + }); + let wallet = this.mapWallet(storedKey); + + storedKey.delete(); + hdWallet.delete(); + + this.importWallet(wallet) + .then(() => resolve(wallet)) + .catch((error) => reject(error)); + }); + } + + importKey( + key: Uint8Array, + name: string, + password: string, + coin: CoinType + ): Promise { + return new Promise((resolve, reject) => { + const { StoredKey, PrivateKey, Curve } = this.core; + + // FIXME: get curve from coin + if ( + !PrivateKey.isValid(key, Curve.secp256k1) || + !PrivateKey.isValid(key, Curve.ed25519) + ) { + throw Types.Error.InvalidKey; + } + let pass = Buffer.from(password); + let storedKey = StoredKey.importPrivateKey(key, name, pass, coin); + let wallet = this.mapWallet(storedKey); + storedKey.delete(); + this.importWallet(wallet) + .then(() => resolve(wallet)) + .catch((error) => reject(error)); + }); + } + + addAccounts( + id: string, + password: string, + coins: CoinType[] + ): Promise { + return this.load(id).then((wallet) => { + let storedKey = this.mapStoredKey(wallet); + let hdWallet = storedKey.wallet(Buffer.from(password)); + coins.forEach((coin) => { + storedKey.accountForCoin(coin, hdWallet); + }); + let newWallet = this.mapWallet(storedKey); + storedKey.delete(); + hdWallet.delete(); + return this.importWallet(newWallet).then(() => newWallet); + }); + } + + getKey( + id: string, + password: string, + account: Types.ActiveAccount + ): Promise { + return this.load(id).then((wallet) => { + let storedKey = this.mapStoredKey(wallet); + let hdWallet = storedKey.wallet(Buffer.from(password)); + let coin = (this.core.CoinType as any).values["" + account.coin]; + let privateKey = hdWallet.getKey(coin, account.derivationPath); + storedKey.delete(); + hdWallet.delete(); + return privateKey; + }); + } + + export(id: string, password: string): Promise { + return this.load(id).then((wallet) => { + let storedKey = this.mapStoredKey(wallet); + let value: string | Uint8Array; + switch (wallet.type) { + case Types.WalletType.Mnemonic: + value = storedKey.decryptMnemonic(Buffer.from(password)); + break; + case Types.WalletType.PrivateKey: + value = storedKey.decryptPrivateKey(Buffer.from(password)); + break; + default: + throw Types.Error.InvalidJSON; + } + storedKey.delete(); + return value; + }); + } +} diff --git a/wasm/src/keystore/extension-storage.ts b/wasm/src/keystore/extension-storage.ts new file mode 100644 index 00000000000..3056a4b8681 --- /dev/null +++ b/wasm/src/keystore/extension-storage.ts @@ -0,0 +1,72 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import { Storage } from "webextension-polyfill"; +import * as Types from "./types"; + +// Extension KeyStore +export class ExtensionStorage implements Types.IStorage { + readonly storage: Storage.StorageArea; + readonly walletIdsKey: string; + + constructor(walletIdsKey: string, storage: Storage.StorageArea) { + this.walletIdsKey = walletIdsKey; + this.storage = storage; + } + + get(id: string): Promise { + return this.storage.get(id).then((object) => { + let wallet = object[id]; + if (wallet === undefined) { + throw Types.Error.WalletNotFound; + } + return wallet as Types.Wallet; + }); + } + + set(id: string, wallet: Types.Wallet): Promise { + return this.getWalletIds().then((ids) => { + if (ids.indexOf(id) === -1) { + ids.push(id); + } + return this.storage.set({ + [id]: wallet, + [this.walletIdsKey]: ids, + }); + }); + } + + loadAll(): Promise { + return this.getWalletIds().then((ids) => { + if (ids.length === 0) { + return []; + } + return this.storage + .get(ids) + .then((wallets) => Object.keys(wallets).map((key) => wallets[key])); + }); + } + + delete(id: string, password: string): Promise { + return this.getWalletIds().then((ids) => { + let index = ids.indexOf(id); + if (index === -1) { + return; + } + ids.splice(index, 1); + return this.storage + .remove(id) + .then(() => this.storage.set({ [this.walletIdsKey]: ids })); + }); + } + + private getWalletIds(): Promise { + return this.storage.get(this.walletIdsKey).then((object) => { + let ids = object[this.walletIdsKey] as string[]; + return ids === undefined ? [] : ids; + }); + } +} diff --git a/wasm/src/keystore/fs-storage.ts b/wasm/src/keystore/fs-storage.ts new file mode 100644 index 00000000000..3689be747e3 --- /dev/null +++ b/wasm/src/keystore/fs-storage.ts @@ -0,0 +1,45 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import * as Types from "./types"; +import * as fs from "fs/promises"; + +// FileSystem Storage +export class FileSystemStorage implements Types.IStorage { + private readonly directory: string; + + constructor(directory: string) { + this.directory = directory.endsWith("/") ? directory : directory + "/"; + } + + getFilename(id): string { + return this.directory + id + ".json"; + } + + get(id: string): Promise { + return fs + .readFile(this.getFilename(id)) + .then((data) => JSON.parse(data.toString()) as Types.Wallet); + } + + set(id: string, wallet: Types.Wallet): Promise { + return fs.writeFile(this.getFilename(id), JSON.stringify(wallet)); + } + + loadAll(): Promise { + return fs.readdir(this.directory).then((files) => { + return Promise.all( + files + .filter((file) => file.endsWith(".json")) + .map((file) => this.get(file.replace(".json", ""))) + ); + }); + } + + delete(id: string, password: string): Promise { + return fs.unlink(this.getFilename(id)); + } +} diff --git a/wasm/src/keystore/index.ts b/wasm/src/keystore/index.ts new file mode 100644 index 00000000000..68931378db0 --- /dev/null +++ b/wasm/src/keystore/index.ts @@ -0,0 +1,10 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +export { Default } from "./default-impl"; +export * from "./types"; +export { FileSystemStorage } from "./fs-storage"; +export { ExtensionStorage } from "./extension-storage"; diff --git a/wasm/src/keystore/types.ts b/wasm/src/keystore/types.ts new file mode 100644 index 00000000000..cc0ce8a21fd --- /dev/null +++ b/wasm/src/keystore/types.ts @@ -0,0 +1,93 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import { CoinType, PrivateKey } from "../wallet-core"; + +export enum WalletType { + Mnemonic = "mnemonic", + PrivateKey = "privateKey", + WatchOnly = "watchOnly", + Hardware = "hardware", +} + +export enum Error { + WalletNotFound = "wallet not found", + AccountNotFound = "account not found", + InvalidPassword = "invalid password", + InvalidMnemonic = "invalid mnemonic", + InvalidJSON = "invalid JSON", + InvalidKey = "invalid key", +} + +export interface ActiveAccount { + address: string; + coin: number; + publicKey: string; + derivationPath: string; + extendedPublicKey?: string; +} + +export interface Wallet { + id: string; + + type: WalletType; + name: string; + version: number; + activeAccounts: ActiveAccount[]; +} + +export interface IKeyStore { + // Check if wallet id exists + hasWallet(id: string): Promise; + + // Load a wallet by wallet id + load(id: string): Promise; + + // Load all wallets + loadAll(): Promise; + + // Import a wallet by mnemonic, name, password and initial active accounts (from coinTypes) + import( + mnemonic: string, + name: string, + password: string, + coins: CoinType[] + ): Promise; + + // Import a wallet by private key, name and password + importKey( + key: Uint8Array, + name: string, + password: string, + coin: CoinType + ): Promise; + + // Import a Wallet object directly + importWallet(wallet: Wallet): Promise; + + // Add active accounts to a wallet by wallet id, password, coin + addAccounts(id: string, password: string, coins: CoinType[]): Promise; + + // Get private key of an account by wallet id, password, coin and derivation path + getKey( + id: string, + password: string, + account: ActiveAccount + ): Promise; + + // Delete a wallet by wallet id and password.aq1aq + delete(id: string, password: string): Promise; + + // Export a wallet by wallet id and password, returns mnemonic or private key + export(id: string, password: string): Promise; +} + +export interface IStorage { + get(id: string): Promise; + set(id: string, wallet: Wallet): Promise; + loadAll(): Promise; + delete(id: string, password: string): Promise; +} diff --git a/wasm/tests/KeyStore+extension.test.ts b/wasm/tests/KeyStore+extension.test.ts new file mode 100644 index 00000000000..fe22c5b7091 --- /dev/null +++ b/wasm/tests/KeyStore+extension.test.ts @@ -0,0 +1,68 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import "mocha"; +import { assert } from "chai"; +import { KeyStore } from "../dist"; +import { ChromeStorageMock } from "./mock"; + +describe("KeyStore", async () => { + it("test ExtensionStorage", async () => { + const { CoinType, HexCoding } = globalThis.core; + const mnemonic = globalThis.mnemonic as string; + const password = globalThis.password as string; + + const walletIdsKey = "all-wallet-ids"; + const storage = new KeyStore.ExtensionStorage( + walletIdsKey, + new ChromeStorageMock() + ); + const keystore = new KeyStore.Default(globalThis.core, storage); + + var wallet = await keystore.import(mnemonic, "Coolw", password, [ + CoinType.bitcoin, + ]); + + assert.equal(wallet.name, "Coolw"); + assert.equal(wallet.type, "mnemonic"); + assert.equal(wallet.version, 3); + + const account = wallet.activeAccounts[0]; + const key = await keystore.getKey(wallet.id, password, account); + + assert.equal( + HexCoding.encode(key.data()), + "0xd2568511baea8dc347f14c4e0479eb8ebe29eb5f664ed796e755896250ffd11f" + ); + assert.equal(account.address, "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"); + assert.equal( + account.extendedPublicKey, + "zpub6qbsWdbcKW9sC6shTKK4VEhfWvDCoWpfLnnVfYKHLHt31wKYUwH3aFDz4WLjZvjHZ5W4qVEyk37cRwzTbfrrT1Gnu8SgXawASnkdQ994atn" + ); + assert.equal( + account.publicKey, + "02df6fc590ab3101bbe0bb5765cbaeab9b5dcfe09ac9315d707047cbd13bc7e006" + ); + + wallet = await keystore.addAccounts(wallet.id, password, [ + CoinType.ethereum, + CoinType.binance, + ]); + + assert.equal(wallet.activeAccounts.length, 3); + assert.isTrue(await keystore.hasWallet(wallet.id)); + assert.isFalse(await keystore.hasWallet("invalid-id")); + + const exported = await keystore.export(wallet.id, password); + assert.equal(exported, mnemonic); + + const wallets = await keystore.loadAll(); + + await wallets.forEach((w) => { + keystore.delete(w.id, password); + }); + }).timeout(10000); +}); diff --git a/wasm/tests/KeyStore+fs.test.ts b/wasm/tests/KeyStore+fs.test.ts new file mode 100644 index 00000000000..743a9a8e4b4 --- /dev/null +++ b/wasm/tests/KeyStore+fs.test.ts @@ -0,0 +1,70 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import "mocha"; +import { assert } from "chai"; +import * as fs from "fs"; +import { KeyStore } from "../dist"; + +describe("KeyStore", async () => { + it("test FileSystemStorage", async () => { + const { CoinType, HexCoding } = globalThis.core; + const mnemonic = globalThis.mnemonic as string; + const password = globalThis.password as string; + const testDir = "/tmp/wasm-test"; + + fs.mkdirSync(testDir, { recursive: true }); + + const storage = new KeyStore.FileSystemStorage(testDir); + const keystore = new KeyStore.Default(globalThis.core, storage); + + var wallet = await keystore.import(mnemonic, "Coolw", password, [ + CoinType.bitcoin, + ]); + const stats = fs.statSync(storage.getFilename(wallet.id)); + + assert.isTrue(stats.isFile()); + assert.isTrue(stats.size > 0); + assert.equal(wallet.name, "Coolw"); + assert.equal(wallet.type, "mnemonic"); + assert.equal(wallet.version, 3); + + const account = wallet.activeAccounts[0]; + const key = await keystore.getKey(wallet.id, password, account); + + assert.equal( + HexCoding.encode(key.data()), + "0xd2568511baea8dc347f14c4e0479eb8ebe29eb5f664ed796e755896250ffd11f" + ); + assert.equal(account.address, "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"); + assert.equal( + account.extendedPublicKey, + "zpub6qbsWdbcKW9sC6shTKK4VEhfWvDCoWpfLnnVfYKHLHt31wKYUwH3aFDz4WLjZvjHZ5W4qVEyk37cRwzTbfrrT1Gnu8SgXawASnkdQ994atn" + ); + assert.equal( + account.publicKey, + "02df6fc590ab3101bbe0bb5765cbaeab9b5dcfe09ac9315d707047cbd13bc7e006" + ); + + wallet = await keystore.addAccounts(wallet.id, password, [ + CoinType.ethereum, + CoinType.binance, + ]); + + assert.equal(wallet.activeAccounts.length, 3); + assert.isTrue(await keystore.hasWallet(wallet.id)); + assert.isFalse(await keystore.hasWallet("invalid-id")); + + const exported = await keystore.export(wallet.id, password); + assert.equal(exported, mnemonic); + + const wallets = await keystore.loadAll(); + + await wallets.forEach((w) => { + keystore.delete(w.id, password); + }); + }).timeout(10000); +}); diff --git a/wasm/tests/mock.ts b/wasm/tests/mock.ts new file mode 100644 index 00000000000..99451f70d76 --- /dev/null +++ b/wasm/tests/mock.ts @@ -0,0 +1,53 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import { Events, Storage } from "webextension-polyfill"; + +export class ChromeStorageMock implements Storage.StorageArea { + object = {}; + + get( + keys?: string | string[] | Record | null | undefined + ): Promise> { + var ids: string[] = []; + if (typeof keys === "string") { + ids.push(keys); + } else if (keys instanceof Array) { + ids = ids.concat(keys); + } + + var result: Record = {}; + ids.forEach((id) => { + result[id] = this.object[id]; + }); + return Promise.resolve(result); + } + + set(items: Record): Promise { + Object.keys(items).forEach((key) => { + this.object[key] = items[key]; + }); + return Promise.resolve(); + } + + remove(keys: string | string[]): Promise { + var ids: string[] = []; + if (typeof keys === "string") { + ids.push(keys); + } + ids = ids.concat(keys); + ids.forEach((id) => delete this.object[id]); + return Promise.resolve(); + } + + clear(): Promise { + throw new Error("Method not implemented."); + } + + onChanged: Events.Event< + (changes: Storage.StorageAreaOnChangedChangesType) => void + > = {} as any; +} diff --git a/wasm/tests/setup.test.ts b/wasm/tests/setup.test.ts index 80215470759..54d6664beee 100644 --- a/wasm/tests/setup.test.ts +++ b/wasm/tests/setup.test.ts @@ -2,5 +2,8 @@ import "mocha"; import { initWasm } from "../dist"; before(async () => { + globalThis.mnemonic = + "team engine square letter hero song dizzy scrub tornado fabric divert saddle"; + globalThis.password = "password"; globalThis.core = await initWasm(); }); From 05fc16adf7d4f5c22975dda82fb368ec02992a31 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 19 Sep 2022 12:33:21 +0200 Subject: [PATCH 079/497] chore: update CODEOWNERS for review assignments (#2577) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 33536958aad..707fa9c11ea 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,4 +3,4 @@ # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @hewigovens @catenocrypt +* @hewigovens @catenocrypt @milerius @miloserdow From ea6704f38bb3a46feaf64fea0f05924ca9e7907b Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Tue, 20 Sep 2022 03:51:34 +0200 Subject: [PATCH 080/497] Cardano Staking (#2547) * Register and Delegate messages * Handle deposit (& un-) in plan amounts * Improve Certificate classes * Deregister message * Clarify deposit/undeposit handling * Add AddressV3.getStakingKeyHash() to derive from address * Improved key handling for staking key signature * Add Delegate swift test * Support Withdrawal message * Add Staking test * Handle signature for withdraw, real-world Withdraw test * Rename in proto * Use stakingAddress everywhere for consistency (instead of key hash) * Expose getStakingKey over C interface * Language nuances, review, emplace, empty() * Review findings; use constant, more comments in proto & tests --- .../blockchains/cardano/TestCardanoSigning.kt | 113 +++++- include/TrustWalletCore/TWCardano.h | 8 + src/Cardano/AddressV3.cpp | 21 +- src/Cardano/AddressV3.h | 7 +- src/Cardano/Signer.cpp | 149 ++++++-- src/Cardano/Transaction.cpp | 62 +++- src/Cardano/Transaction.h | 39 +- src/interface/TWCardano.cpp | 10 + src/proto/Cardano.proto | 58 +++ swift/Tests/Blockchains/CardanoTests.swift | 89 +++++ tests/Cardano/AddressTests.cpp | 44 +++ tests/Cardano/SigningTests.cpp | 2 +- tests/Cardano/StakingTests.cpp | 351 ++++++++++++++++++ tests/Cardano/TWCardanoAddressTests.cpp | 15 + 14 files changed, 926 insertions(+), 42 deletions(-) create mode 100644 tests/Cardano/StakingTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigning.kt index 0917f91f828..e76aa67b785 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigning.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/cardano/TestCardanoSigning.kt @@ -15,6 +15,7 @@ import org.junit.Assert.assertEquals import org.junit.Test import wallet.core.java.AnySigner import wallet.core.jni.* +import wallet.core.jni.Cardano.getStakingAddress import wallet.core.jni.CoinType.CARDANO import wallet.core.jni.proto.Cardano import wallet.core.jni.proto.Cardano.SigningInput @@ -39,7 +40,7 @@ class TestCardanoSigning { .setTransferMessage(message) .setTtl(53333333) - val privKey = (Numeric.hexStringToByteArray("089b68e458861be0c44bf9f7967f05cc91e51ede86dc679448a3566990b7785bd48c330875b1e0d03caaed0e67cecc42075dce1c7a13b1c49240508848ac82f603391c68824881ae3fc23a56a1a75ada3b96382db502e37564e84a5413cfaf1290dbd508e5ec71afaea98da2df1533c22ef02a26bb87b31907d0b2738fb7785b38d53aa68fc01230784c9209b2b2a2faf28491b3b1f1d221e63e704bbd0403c4154425dfbb01a2c5c042da411703603f89af89e57faae2946e2a5c18b1c5ca0e")) + val privKey = Numeric.hexStringToByteArray("089b68e458861be0c44bf9f7967f05cc91e51ede86dc679448a3566990b7785bd48c330875b1e0d03caaed0e67cecc42075dce1c7a13b1c49240508848ac82f603391c68824881ae3fc23a56a1a75ada3b96382db502e37564e84a5413cfaf1290dbd508e5ec71afaea98da2df1533c22ef02a26bb87b31907d0b2738fb7785b38d53aa68fc01230784c9209b2b2a2faf28491b3b1f1d221e63e704bbd0403c4154425dfbb01a2c5c042da411703603f89af89e57faae2946e2a5c18b1c5ca0e") input.addPrivateKey(ByteString.copyFrom(privKey)) val outpoint1 = Cardano.OutPoint.newBuilder() @@ -101,7 +102,7 @@ class TestCardanoSigning { .setTransferMessage(message) .setTtl(53333333) - val privKey = (Numeric.hexStringToByteArray("089b68e458861be0c44bf9f7967f05cc91e51ede86dc679448a3566990b7785bd48c330875b1e0d03caaed0e67cecc42075dce1c7a13b1c49240508848ac82f603391c68824881ae3fc23a56a1a75ada3b96382db502e37564e84a5413cfaf1290dbd508e5ec71afaea98da2df1533c22ef02a26bb87b31907d0b2738fb7785b38d53aa68fc01230784c9209b2b2a2faf28491b3b1f1d221e63e704bbd0403c4154425dfbb01a2c5c042da411703603f89af89e57faae2946e2a5c18b1c5ca0e")) + val privKey = Numeric.hexStringToByteArray("089b68e458861be0c44bf9f7967f05cc91e51ede86dc679448a3566990b7785bd48c330875b1e0d03caaed0e67cecc42075dce1c7a13b1c49240508848ac82f603391c68824881ae3fc23a56a1a75ada3b96382db502e37564e84a5413cfaf1290dbd508e5ec71afaea98da2df1533c22ef02a26bb87b31907d0b2738fb7785b38d53aa68fc01230784c9209b2b2a2faf28491b3b1f1d221e63e704bbd0403c4154425dfbb01a2c5c042da411703603f89af89e57faae2946e2a5c18b1c5ca0e") input.addPrivateKey(ByteString.copyFrom(privKey)) val outpoint1 = Cardano.OutPoint.newBuilder() @@ -152,4 +153,112 @@ class TestCardanoSigning { val txid = output.txId assertEquals(Numeric.toHexString(txid.toByteArray()), "0x201c537693b005b64a0f0528e366ec67a84be0119ed4363b547f141f2a7770c2"); } + + @Test + fun testSignStakingRegisterAndDelegate() { + val ownAddress = "addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23" + val stakingAddress = getStakingAddress(ownAddress) + val poolIdNufi = Numeric.hexStringToByteArray("7d7ac07a2f2a25b7a4db868a40720621c4939cf6aefbb9a11464f1a6") + + val message = Cardano.Transfer.newBuilder() + .setToAddress(ownAddress) + .setChangeAddress(ownAddress) + .setAmount(4_000_000) // not relevant if we use MaxAmount + .setUseMaxAmount(true) + .build() + // Register staking key, 2 ADA desposit + val register = Cardano.RegisterStakingKey.newBuilder() + .setStakingAddress(stakingAddress) + .setDepositAmount(2_000_000) + // Delegate + val delegate = Cardano.Delegate.newBuilder() + .setStakingAddress(stakingAddress) + .setPoolId(ByteString.copyFrom(poolIdNufi)) + .setDepositAmount(0) + val input = Cardano.SigningInput.newBuilder() + .setTransferMessage(message) + .setRegisterStakingKey(register) + .setDelegate(delegate) + .setTtl(69885081) + + val privKey = Numeric.hexStringToByteArray("089b68e458861be0c44bf9f7967f05cc91e51ede86dc679448a3566990b7785bd48c330875b1e0d03caaed0e67cecc42075dce1c7a13b1c49240508848ac82f603391c68824881ae3fc23a56a1a75ada3b96382db502e37564e84a5413cfaf1290dbd508e5ec71afaea98da2df1533c22ef02a26bb87b31907d0b2738fb7785b38d53aa68fc01230784c9209b2b2a2faf28491b3b1f1d221e63e704bbd0403c4154425dfbb01a2c5c042da411703603f89af89e57faae2946e2a5c18b1c5ca0e") + input.addPrivateKey(ByteString.copyFrom(privKey)) + + val outpoint1 = Cardano.OutPoint.newBuilder() + .setTxHash(ByteString.copyFrom(Numeric.hexStringToByteArray("9b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e"))) + .setOutputIndex(0) + .build() + val utxo1 = Cardano.TxInput.newBuilder() + .setOutPoint(outpoint1) + .setAddress(ownAddress) + .setAmount(4_000_000) + .build() + input.addUtxos(utxo1) + + val outpoint2 = Cardano.OutPoint.newBuilder() + .setTxHash(ByteString.copyFrom(Numeric.hexStringToByteArray("9b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e"))) + .setOutputIndex(1) + .build() + val utxo2 = Cardano.TxInput.newBuilder() + .setOutPoint(outpoint2) + .setAddress(ownAddress) + .setAmount(26651312) + .build() + input.addUtxos(utxo2) + + val output = AnySigner.sign(input.build(), CARDANO, SigningOutput.parser()) + assertEquals(output.error, SigningError.OK) + + val encoded = output.encoded + assertEquals(Numeric.toHexString(encoded.toByteArray()), + "0x83a500828258209b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e008258209b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e01018182583901df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b1a01b27ef5021a0002b03b031a042a5c99048282008200581cdf22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b83028200581cdf22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b581c7d7ac07a2f2a25b7a4db868a40720621c4939cf6aefbb9a11464f1a6a100828258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df2905840677c901704be027d9a1734e8aa06f0700009476fa252baaae0de280331746a320a61456d842d948ea5c0e204fc36f3bd04c88ca7ee3d657d5a38014243c37c07825820e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e0693258401fa21bdc62b85ca217bf08cbacdeba2fadaf33dc09ee3af9cc25b40f24822a1a42cfbc03585cc31a370ef75aaec4d25db6edcf329e40a4e725ec8718c94f220af6"); + + val txid = output.txId + assertEquals(Numeric.toHexString(txid.toByteArray()), "0x96a781fd6481b6a7fd3926da110265e8c44b53947b81daa84da5b148825d02aa"); + } + + @Test + fun testSignStakingWithdraw() { + val ownAddress = "addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23" + val stakingAddress = getStakingAddress(ownAddress) + + val message = Cardano.Transfer.newBuilder() + .setToAddress(ownAddress) + .setChangeAddress(ownAddress) + .setAmount(6_000_000) // not relevant if we use MaxAmount + .setUseMaxAmount(true) + .build() + // Withdraw available amount + val withdraw = Cardano.Withdraw.newBuilder() + .setStakingAddress(stakingAddress) + .setWithdrawAmount(3468) + val input = Cardano.SigningInput.newBuilder() + .setTransferMessage(message) + .setWithdraw(withdraw) + .setTtl(71678326) + + val privKey = Numeric.hexStringToByteArray("089b68e458861be0c44bf9f7967f05cc91e51ede86dc679448a3566990b7785bd48c330875b1e0d03caaed0e67cecc42075dce1c7a13b1c49240508848ac82f603391c68824881ae3fc23a56a1a75ada3b96382db502e37564e84a5413cfaf1290dbd508e5ec71afaea98da2df1533c22ef02a26bb87b31907d0b2738fb7785b38d53aa68fc01230784c9209b2b2a2faf28491b3b1f1d221e63e704bbd0403c4154425dfbb01a2c5c042da411703603f89af89e57faae2946e2a5c18b1c5ca0e") + input.addPrivateKey(ByteString.copyFrom(privKey)) + + val outpoint1 = Cardano.OutPoint.newBuilder() + .setTxHash(ByteString.copyFrom(Numeric.hexStringToByteArray("7dfd2c579794314b1f84efc9db932a098e440ccefb874945591f1d4e85a9152a"))) + .setOutputIndex(0) + .build() + val utxo1 = Cardano.TxInput.newBuilder() + .setOutPoint(outpoint1) + .setAddress(ownAddress) + .setAmount(6_305_913) + .build() + input.addUtxos(utxo1) + + val output = AnySigner.sign(input.build(), CARDANO, SigningOutput.parser()) + assertEquals(output.error, SigningError.OK) + + val encoded = output.encoded + assertEquals(Numeric.toHexString(encoded.toByteArray()), + "0x83a500818258207dfd2c579794314b1f84efc9db932a098e440ccefb874945591f1d4e85a9152a00018182583901df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b1a005da6ff021a00029f06031a0445b97605a1581de1df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b190d8ca100828258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df29058401ebaca2876fd17122404912a2558a98109cdf0f990a938d2917fa2c3b8c4e55e18a2cbabfa82fff03fa0d7ab8b88ca01ed18e42af3bfc4cda7f423a3aa30c00b825820e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e069325840777f04fa8f083fe562aecf78898aaaaac36e2cc6ca962f6ffb01e84a421cae1860496db79b2c5fb2879524c3d5121060b9ea1e693336230c6e5338e14c4c3303f6"); + + val txid = output.txId + assertEquals(Numeric.toHexString(txid.toByteArray()), "0x6dcf3956232953fc25b8355fb1ded1e912b5802090fd21434d789087d6329683"); + } } diff --git a/include/TrustWalletCore/TWCardano.h b/include/TrustWalletCore/TWCardano.h index 74d9c7a4e43..0def3db33b6 100644 --- a/include/TrustWalletCore/TWCardano.h +++ b/include/TrustWalletCore/TWCardano.h @@ -8,6 +8,7 @@ #include "TWBase.h" #include "TWData.h" +#include "TWString.h" TW_EXTERN_C_BEGIN @@ -23,4 +24,11 @@ struct TWCardano; TW_EXPORT_STATIC_METHOD uint64_t TWCardanoMinAdaAmount(TWData *_Nonnull tokenBundle) TW_VISIBILITY_DEFAULT; +/// Return the staking address associated to (contained in) this address. Must be a Base address. +/// Empty string is returned on error. Result must be freed. +/// \param baseAddress A valid base address, as string. +/// \return the associated staking (reward) address, as string, or empty string on error. +TW_EXPORT_STATIC_METHOD +TWString *_Nonnull TWCardanoGetStakingAddress(TWString *_Nonnull baseAddress) TW_VISIBILITY_DEFAULT; + TW_EXTERN_C_END diff --git a/src/Cardano/AddressV3.cpp b/src/Cardano/AddressV3.cpp index 2a0b67ec25a..43b12442774 100644 --- a/src/Cardano/AddressV3.cpp +++ b/src/Cardano/AddressV3.cpp @@ -127,6 +127,17 @@ AddressV3 AddressV3::createBase(NetworkId networkId, const PublicKey& spendingKe return createBase(networkId, hash1, hash2); } +AddressV3 AddressV3::createReward(NetworkId networkId, const TW::Data& stakingKeyHash) { + if (stakingKeyHash.size() != HashSize) { + throw std::invalid_argument("Wrong spending key hash size"); + } + auto addr = AddressV3(); + addr.networkId = networkId; + addr.kind = Kind_Reward; + addr.bytes = stakingKeyHash; + return addr; +} + AddressV3::AddressV3(const std::string& addr) { if (parseAndCheckV3(addr, networkId, kind, bytes)) { // values stored @@ -201,7 +212,7 @@ std::string AddressV3::string(const std::string& hrp) const { return Bech32::encode(hrp, bech, Bech32::ChecksumVariant::Bech32); } -Data AddressV3::data() const { +Data AddressV3::data() const noexcept { if (legacyAddressV2.has_value()) { return legacyAddressV2->getCborData(); } @@ -213,4 +224,12 @@ Data AddressV3::data() const { return raw; } +std::string AddressV3::getStakingAddress() const noexcept { + if (kind != Kind_Base || bytes.size() != (2 * HashSize)) { + return ""; + } + const auto& stakingKeyHash = TW::subData(bytes, HashSize, HashSize); + return createReward(this->networkId, stakingKeyHash).string(); +} + } // namespace TW::Cardano diff --git a/src/Cardano/AddressV3.h b/src/Cardano/AddressV3.h index b8cbc615933..bee61121ffd 100644 --- a/src/Cardano/AddressV3.h +++ b/src/Cardano/AddressV3.h @@ -65,6 +65,9 @@ class AddressV3 { /// Create a base address, given public keys static AddressV3 createBase(NetworkId networkId, const PublicKey& spendingKey, const PublicKey& stakingKey); + /// Create a staking (reward) address, given a staking key + static AddressV3 createReward(NetworkId networkId, const TW::Data& stakingKeyHash); + /// Initializes a Cardano address with a string representation. Throws if invalid. explicit AddressV3(const std::string& addr); @@ -94,7 +97,9 @@ class AddressV3 { static bool parseAndCheckV3(const std::string& addr, NetworkId& networkId, Kind& kind, TW::Data& bytes) noexcept; /// Return the binary data representation (keys appended, internal format) - Data data() const; + Data data() const noexcept; + /// Return the staking address associated to (contained in) this address. Must be a Base address. Empty string is returned on error. + std::string getStakingAddress() const noexcept; // First encoded byte, from networkId and Kind static uint8_t firstByte(NetworkId networkId, Kind kind); diff --git a/src/Cardano/Signer.cpp b/src/Cardano/Signer.cpp index ca1c14c3fd6..67063685d25 100644 --- a/src/Cardano/Signer.cpp +++ b/src/Cardano/Signer.cpp @@ -59,9 +59,46 @@ Common::Proto::SigningError Signer::buildTransactionAux(Transaction& tx, const P tx.fee = plan.fee; tx.ttl = input.ttl(); + if (input.has_register_staking_key()) { + const auto stakingAddress = AddressV3(input.register_staking_key().staking_address()); + // here we need the bare staking key + const auto key = stakingAddress.bytes; + tx.certificates.emplace_back(Certificate{Certificate::SkatingKeyRegistration, {CertificateKey{CertificateKey::AddressKeyHash, key}}, Data()}); + } + if (input.has_delegate()) { + const auto stakingAddress = AddressV3(input.delegate().staking_address()); + // here we need the bare staking key + const auto key = stakingAddress.bytes; + const auto poolId = data(input.delegate().pool_id()); + tx.certificates.emplace_back(Certificate{Certificate::Delegation, {CertificateKey{CertificateKey::AddressKeyHash, key}}, poolId}); + } + if (input.has_withdraw()) { + const auto stakingAddress = AddressV3(input.withdraw().staking_address()); + const auto key = stakingAddress.data(); + const auto amount = input.withdraw().withdraw_amount(); + tx.withdrawals.emplace_back(Withdrawal{key, amount}); + } + if (input.has_deregister_staking_key()) { + const auto stakingAddress = AddressV3(input.deregister_staking_key().staking_address()); + // here we need the bare staking key + const auto key = stakingAddress.bytes; + tx.certificates.emplace_back(Certificate{Certificate::StakingKeyDeregistration, {CertificateKey{CertificateKey::AddressKeyHash, key}}, Data()}); + } + return Common::Proto::OK; } +Data deriveStakingPrivateKey(const Data& privateKeyData) { + if (privateKeyData.size() != PrivateKey::cardanoKeySize) { + return Data(); + } + assert(privateKeyData.size() == PrivateKey::cardanoKeySize); + const auto halfSize = PrivateKey::cardanoKeySize / 2; + auto stakingPrivKeyData = TW::subData(privateKeyData, halfSize); + TW::append(stakingPrivKeyData, TW::Data(halfSize)); + return stakingPrivKeyData; +} + Common::Proto::SigningError Signer::assembleSignatures(std::vector>& signatures, const Proto::SigningInput& input, const TransactionPlan& plan, const Data& txId, bool sizeEstimationOnly) { signatures.clear(); // Private keys and corresponding addresses @@ -71,25 +108,51 @@ Common::Proto::SigningError Signer::assembleSignatures(std::vector addresses; for (auto& u : plan.utxos) { if (!AddressV3::isValid(u.address)) { return Common::Proto::Error_invalid_address; } - if (find(addresses.begin(), addresses.end(), u.address) == addresses.end()) { - addresses.push_back(u.address); + addresses.emplace_back(u.address); + } + // Staking key is also an address that needs signature + if (input.has_register_staking_key()) { + addresses.emplace_back(input.register_staking_key().staking_address()); + } + if (input.has_deregister_staking_key()) { + addresses.emplace_back(input.deregister_staking_key().staking_address()); + } + if (input.has_delegate()) { + addresses.emplace_back(input.delegate().staking_address()); + } + if (input.has_withdraw()) { + addresses.emplace_back(input.withdraw().staking_address()); + } + // discard duplicates (std::set, std::copy_if, std::unique does not work well here) + std::vector addressesUnique; + for (auto& a: addresses) { + if (find(addressesUnique.begin(), addressesUnique.end(), a) == addressesUnique.end()) { + addressesUnique.emplace_back(a); } } // create signature for each address - for (auto& a : addresses) { + for (auto& a : addressesUnique) { const auto privKeyFind = privateKeys.find(a); Data privateKeyData; if (privKeyFind != privateKeys.end()) { @@ -198,7 +261,7 @@ std::vector selectInputsSimpleNative(const std::vector& inputs Amount selectedAmount = 0; for (const auto& i : ii) { - selected.push_back(i); + selected.emplace_back(i); selectedAmount += i.amount; if (selectedAmount >= amount) { break; @@ -221,7 +284,7 @@ void selectInputsSimpleToken(const std::vector& inputs, std::string key // already selected continue; } - selectedInputs.push_back(i); + selectedInputs.emplace_back(i); selectedAmount += i.amount; if (selectedAmount >= amount) { return; @@ -241,10 +304,8 @@ std::vector Signer::selectInputsWithTokens(const std::vector& } // Create a simple plan, used for estimation -TransactionPlan simplePlan(Amount amount, const TokenBundle& requestedTokens, const std::vector& selectedInputs, bool maxAmount) { - TransactionPlan plan; - plan.amount = amount; - plan.utxos = selectedInputs; +TransactionPlan simplePlan(Amount amount, const TokenBundle& requestedTokens, const std::vector& selectedInputs, bool maxAmount, uint64_t deposit, uint64_t undeposit) { + TransactionPlan plan{.amount = amount, .utxos = selectedInputs, .deposit = deposit, .undeposit = undeposit}; // Sum availableAmount plan.availableAmount = 0; for (auto& u : plan.utxos) { @@ -254,19 +315,20 @@ TransactionPlan simplePlan(Amount amount, const TokenBundle& requestedTokens, co } } plan.fee = PlaceholderFee; // placeholder value + const auto availAfterDeposit = plan.availableAmount + plan.undeposit - plan.deposit; // adjust/compute output amount and output tokens if (!maxAmount) { // reduce amount if needed - plan.amount = std::max(Amount(0), std::min(plan.amount, plan.availableAmount - plan.fee)); + plan.amount = std::max(Amount(0), std::min(plan.amount, availAfterDeposit - plan.fee)); plan.outputTokens = requestedTokens; } else { // max available amount - plan.amount = std::max(Amount(0), plan.availableAmount - plan.fee); + plan.amount = std::max(Amount(0), availAfterDeposit - plan.fee); plan.outputTokens = plan.availableTokens; // use all } // compute change - plan.change = plan.availableAmount - (plan.amount + plan.fee); + plan.change = availAfterDeposit - (plan.amount + plan.fee); for (auto iter = plan.availableTokens.bundle.begin(); iter != plan.availableTokens.bundle.end(); ++iter) { const auto key = iter->second.key(); const auto changeAmount = iter->second.amount - plan.outputTokens.getAmount(key); @@ -277,13 +339,37 @@ TransactionPlan simplePlan(Amount amount, const TokenBundle& requestedTokens, co return plan; } +uint64_t sumDeposits(const Proto::SigningInput& input) { + uint64_t sum = 0; + if (input.has_register_staking_key()) { + sum += input.register_staking_key().deposit_amount(); + } + if (input.has_delegate()) { + sum += input.delegate().deposit_amount(); + } + return sum; +} + +uint64_t sumUndeposits(const Proto::SigningInput& input) { + uint64_t sum = 0; + if (input.has_deregister_staking_key()) { + sum += input.deregister_staking_key().undeposit_amount(); + } + if (input.has_withdraw()) { + sum += input.withdraw().withdraw_amount(); + } + return sum; +} + // Estimates size of transaction in bytes. uint64_t estimateTxSize(const Proto::SigningInput& input, Amount amount, const TokenBundle& requestedTokens, const std::vector& selectedInputs) { auto inputs = std::vector(); for (auto i = 0; i < input.utxos_size(); ++i) { inputs.emplace_back(TxInput::fromProto(input.utxos(i))); } - const auto _simplePlan = simplePlan(amount, requestedTokens, selectedInputs, input.transfer_message().use_max_amount()); + const auto deposits = sumDeposits(input); + const uint64_t undeposits = sumUndeposits(input); + const auto _simplePlan = simplePlan(amount, requestedTokens, selectedInputs, input.transfer_message().use_max_amount(), deposits, undeposits); Data encoded; Data txId; @@ -329,6 +415,10 @@ TransactionPlan Signer::doPlan() const { return plan; } assert(inputSum > 0); + // adjust inputSum with deposited/undeposited amount + plan.deposit = sumDeposits(input); + plan.undeposit = sumUndeposits(input); + const auto inputSumAfterDeposit = inputSum + plan.undeposit - plan.deposit; // Amounts requested plan.amount = input.transfer_message().amount(); @@ -346,14 +436,14 @@ TransactionPlan Signer::doPlan() const { // if amount requested is the same or more than available amount, it cannot be satisifed, but // treat this case as MaxAmount, and send maximum available (which will be less) - if (!maxAmount && input.transfer_message().amount() >= inputSum) { + if (!maxAmount && input.transfer_message().amount() >= inputSumAfterDeposit) { maxAmount = true; } // select UTXOs if (!maxAmount) { // aim for larger total input, enough for 4/3 of the target amount plus typical fee plus minimal ADA for change plus some extra - auto targetInputAmount = (plan.amount * 4) / 3 + PlaceholderFee + requestedTokens.minAdaAmount() + ExtraInputAmount; + auto targetInputAmount = (plan.amount * 4) / 3 + plan.deposit - plan.undeposit + PlaceholderFee + requestedTokens.minAdaAmount() + ExtraInputAmount; plan.utxos = selectInputsWithTokens(utxos, targetInputAmount, requestedTokens); } else { // maxAmount, select all @@ -374,13 +464,15 @@ TransactionPlan Signer::doPlan() const { return plan; } assert(plan.availableAmount > 0); + // adjust availableAmount with deposited/undeposited amount + const auto availableAmountAfterDeposit = plan.availableAmount + plan.undeposit - plan.deposit; // check that there are enough coins in the inputs - if (plan.amount > plan.availableAmount) { + if (plan.amount > availableAmountAfterDeposit) { plan.error = Common::Proto::Error_low_balance; return plan; } - assert(plan.amount <= plan.availableAmount); + assert(plan.amount <= availableAmountAfterDeposit); // check that there are enough tokens in the inputs for (auto iter = requestedTokens.bundle.begin(); iter != requestedTokens.bundle.end(); ++iter) { if (iter->second.amount > plan.availableTokens.getAmount(iter->second.key())) { @@ -394,25 +486,25 @@ TransactionPlan Signer::doPlan() const { plan.fee = estimateFee(input, plan.amount, requestedTokens, plan.utxos); } else { // fee provided, use it (capped) - plan.fee = std::max(Amount(0), std::min(plan.availableAmount - plan.amount, input.transfer_message().force_fee())); + plan.fee = std::max(Amount(0), std::min(availableAmountAfterDeposit - plan.amount, input.transfer_message().force_fee())); } - assert(plan.fee >= 0 && plan.fee < plan.availableAmount); + assert(plan.fee >= 0 && plan.fee < availableAmountAfterDeposit); // adjust/compute output amount if (!maxAmount) { // reduce amount if needed - plan.amount = std::max(Amount(0), std::min(plan.amount, plan.availableAmount - plan.fee)); + plan.amount = std::max(Amount(0), std::min(plan.amount, availableAmountAfterDeposit - plan.fee)); } else { // max available amount - plan.amount = std::max(Amount(0), plan.availableAmount - plan.fee); + plan.amount = std::max(Amount(0), availableAmountAfterDeposit - plan.fee); } - assert(plan.amount >= 0 && plan.amount <= plan.availableAmount); + assert(plan.amount >= 0 && plan.amount <= availableAmountAfterDeposit); - if (plan.amount + plan.fee > plan.availableAmount) { + if (plan.amount + plan.fee > availableAmountAfterDeposit) { plan.error = Common::Proto::Error_low_balance; return plan; } - assert(plan.amount + plan.fee <= plan.availableAmount); + assert(plan.amount + plan.fee <= availableAmountAfterDeposit); // compute output token amounts if (!maxAmount) { @@ -422,7 +514,7 @@ TransactionPlan Signer::doPlan() const { } // compute change - plan.change = plan.availableAmount - (plan.amount + plan.fee); + plan.change = availableAmountAfterDeposit - (plan.amount + plan.fee); for (auto iter = plan.availableTokens.bundle.begin(); iter != plan.availableTokens.bundle.end(); ++iter) { const auto key = iter->second.key(); const auto changeAmount = iter->second.amount - plan.outputTokens.getAmount(key); @@ -432,9 +524,10 @@ TransactionPlan Signer::doPlan() const { } } - assert(plan.change >= 0 && plan.change <= plan.availableAmount); + assert(plan.change >= 0 && plan.change <= availableAmountAfterDeposit); assert(!maxAmount || plan.change == 0); // change is 0 in max amount case - assert(plan.amount + plan.change + plan.fee == plan.availableAmount); + assert(plan.amount + plan.change + plan.fee == availableAmountAfterDeposit); + assert(plan.amount + plan.change + plan.fee + plan.deposit == plan.availableAmount + plan.undeposit); return plan; } diff --git a/src/Cardano/Transaction.cpp b/src/Cardano/Transaction.cpp index 8abd2f89799..71ef9c68787 100644 --- a/src/Cardano/Transaction.cpp +++ b/src/Cardano/Transaction.cpp @@ -76,7 +76,7 @@ std::vector TokenBundle::getByPolicyId(const std::string& policyId) std::vector filtered; for (const auto& t : bundle) { if (t.second.policyId == policyId) { - filtered.push_back(t.second); + filtered.emplace_back(t.second); } } return filtered; @@ -160,6 +160,8 @@ TransactionPlan TransactionPlan::fromProto(const Proto::TransactionPlan& proto) ret.amount = proto.amount(); ret.fee = proto.fee(); ret.change = proto.change(); + ret.deposit = proto.deposit(); + ret.undeposit = proto.undeposit(); for (auto i = 0; i < proto.available_tokens_size(); ++i) { ret.availableTokens.add(TokenAmount::fromProto(proto.available_tokens(i))); } @@ -170,7 +172,7 @@ TransactionPlan TransactionPlan::fromProto(const Proto::TransactionPlan& proto) ret.changeTokens.add(TokenAmount::fromProto(proto.change_tokens(i))); } for (auto i = 0; i < proto.utxos_size(); ++i) { - ret.utxos.push_back(TxInput::fromProto(proto.utxos(i))); + ret.utxos.emplace_back(TxInput::fromProto(proto.utxos(i))); } ret.error = proto.error(); return ret; @@ -182,6 +184,8 @@ Proto::TransactionPlan TransactionPlan::toProto() const { plan.set_amount(amount); plan.set_fee(fee); plan.set_change(change); + plan.set_deposit(deposit); + plan.set_undeposit(undeposit); for (const auto& token : availableTokens.bundle) { *plan.add_available_tokens() = token.second.toProto(); } @@ -202,7 +206,7 @@ Cbor::Encode cborizeInputs(const std::vector& inputs) { // clang-format off std::vector ii; for (const auto& i : inputs) { - ii.push_back(Cbor::Encode::array({ + ii.emplace_back(Cbor::Encode::array({ Cbor::Encode::bytes(i.txHash), Cbor::Encode::uint(i.outputIndex) })); @@ -253,26 +257,68 @@ Cbor::Encode cborizeOutput(const TxOutput& output) { Cbor::Encode cborizeOutputs(const std::vector& outputs) { std::vector oo; for (const auto& o : outputs) { - oo.push_back(cborizeOutput(o)); + oo.emplace_back(cborizeOutput(o)); } return Cbor::Encode::array(oo); } +Cbor::Encode cborizeCertificateKey(const CertificateKey& certKey) { + std::vector c; + c.emplace_back(Cbor::Encode::uint(static_cast(certKey.type))); + c.emplace_back(Cbor::Encode::bytes(certKey.key)); + return Cbor::Encode::array(c); +} + +Cbor::Encode cborizeCert(const Certificate& cert) { + std::vector c; + c.emplace_back(Cbor::Encode::uint(static_cast(cert.type))); + c.emplace_back(cborizeCertificateKey(cert.certKey)); + if (!cert.poolId.empty()) { + c.emplace_back(Cbor::Encode::bytes(cert.poolId)); + } + return Cbor::Encode::array(c); +} + +Cbor::Encode cborizeCerts(const std::vector& certs) { + std::vector c; + for (const auto& i: certs) { + c.emplace_back(cborizeCert(i)); + } + return Cbor::Encode::array(c); +} + +Cbor::Encode cborizeWithdrawals(const std::vector& withdrawals) { + std::map mapElems; + for (const auto& w: withdrawals) { + mapElems.emplace(Cbor::Encode::bytes(w.stakingKey), Cbor::Encode::uint(w.amount)); + } + return Cbor::Encode::map(mapElems); +} + Data Transaction::encode() const { const auto ii = cborizeInputs(inputs); const auto oo = cborizeOutputs(outputs); // Encode elements in a map, with fixed numbers as keys - Cbor::Encode encode = Cbor::Encode::map({ + std::map mapElems = { std::make_pair(Cbor::Encode::uint(0), ii), std::make_pair(Cbor::Encode::uint(1), oo), std::make_pair(Cbor::Encode::uint(2), Cbor::Encode::uint(fee)), std::make_pair(Cbor::Encode::uint(3), Cbor::Encode::uint(ttl)), - }); - // Note: following fields are not included: - // 4 certificates, 5 withdrawals, 7 AUXILIARY_DATA_HASH, 8 VALIDITY_INTERVAL_START + }; + if (!certificates.empty()) { + mapElems.emplace(Cbor::Encode::uint(4), cborizeCerts(certificates)); + } + if (!withdrawals.empty()) { + mapElems.emplace(Cbor::Encode::uint(5), cborizeWithdrawals(withdrawals)); + } + + Cbor::Encode encode = Cbor::Encode::map(mapElems); return encode.encoded(); + + // Note: following fields are not included: + // 7 AUXILIARY_DATA_HASH, 8 VALIDITY_INTERVAL_START } Data Transaction::getId() const { diff --git a/src/Cardano/Transaction.h b/src/Cardano/Transaction.h index 1a090932a45..0bdab1c70bf 100644 --- a/src/Cardano/Transaction.h +++ b/src/Cardano/Transaction.h @@ -105,10 +105,12 @@ class TxOutput { class TransactionPlan { public: std::vector utxos; - Amount availableAmount = 0; // total coins in the utxos + Amount availableAmount = 0; // total coins in the input utxos Amount amount = 0; // coins in the output UTXO Amount fee = 0; // coin amount deducted as fee Amount change = 0; // coins in the change UTXO + Amount deposit = 0; // coins deposited (going to deposit) in this TX + Amount undeposit = 0; // coins undeposited (returned from deposit) in this TX TokenBundle availableTokens; // total tokens in the utxos (optional) TokenBundle outputTokens; // tokens in the output (optional) TokenBundle changeTokens; // tokens in the change (optional) @@ -118,12 +120,47 @@ class TransactionPlan { Proto::TransactionPlan toProto() const; }; +/// A key with a type, used in a Certificate +class CertificateKey { +public: + enum KeyType: uint8_t { + AddressKeyHash = 0, + //ScriptHash = 1, + }; + KeyType type; + Data key; +}; + +/// Certificate, mainly used for staking +class Certificate { +public: + enum CertificateType: uint8_t { + SkatingKeyRegistration = 0, + StakingKeyDeregistration = 1, + Delegation = 2, + //StakePoolRegistration = 3, // not supported + }; + CertificateType type; + CertificateKey certKey; + /// Optional PoolId, used in delegation + Data poolId; +}; + +/// Staking withdrawal +class Withdrawal { +public: + Data stakingKey; + Amount amount; +}; + class Transaction { public: std::vector inputs; std::vector outputs; Amount fee; uint64_t ttl; + std::vector certificates; + std::vector withdrawals; // Encode into CBOR binary format Data encode() const; diff --git a/src/interface/TWCardano.cpp b/src/interface/TWCardano.cpp index 07ed706207a..9c1c43ed16d 100644 --- a/src/interface/TWCardano.cpp +++ b/src/interface/TWCardano.cpp @@ -7,6 +7,7 @@ #include #include "Cardano/Transaction.h" +#include "Cardano/AddressV3.h" #include "proto/Cardano.pb.h" using namespace TW; @@ -19,3 +20,12 @@ uint64_t TWCardanoMinAdaAmount(TWData *_Nonnull tokenBundle) { } return 0; } + +TWString *_Nonnull TWCardanoGetStakingAddress(TWString *_Nonnull baseAddress) { + const auto& address = *reinterpret_cast(baseAddress); + try { + return TWStringCreateWithUTF8Bytes(TW::Cardano::AddressV3(address).getStakingAddress().c_str()); + } catch (...) { + return TWStringCreateWithUTF8Bytes(""); + } +} diff --git a/src/proto/Cardano.proto b/src/proto/Cardano.proto index 398242090b4..c3ceaa27df9 100644 --- a/src/proto/Cardano.proto +++ b/src/proto/Cardano.proto @@ -66,6 +66,46 @@ message Transfer { uint64 force_fee = 6; } +// Register a staking key for the account, preprequisite for Staking. +// Note: staking messages are typically used with a 1-output-to-self transaction. +message RegisterStakingKey { + // Staking address (as string) + string staking_address = 1; + + // Amount deposited in this TX. Should be 2 ADA (2000000). If not set correctly, TX will be rejected. See also Delegate.deposit_amount. + uint64 deposit_amount = 2; +} + +// Deregister staking key. can be done when staking is stopped completely. The Staking deposit is returned at this time. +message DeregisterStakingKey { + // Staking address (as string) + string staking_address = 1; + + // Amount undeposited in this TX. Should be 2 ADA (2000000). If not set correctly, TX will be rejected. See also RegisterStakingKey.deposit_amount. + uint64 undeposit_amount = 2; +} + +// Delegate funds in this account to a specified staking pool. +message Delegate { + // Staking address (as string) + string staking_address = 1; + + // PoolID of staking pool + bytes pool_id = 2; + + // Amount deposited in this TX. Should be 0. If not set correctly, TX will be rejected. See also RegisterStakingKey.deposit_amount. + uint64 deposit_amount = 3; +} + +// Withdraw earned staking reward. +message Withdraw { + // Staking address (as string) + string staking_address = 1; + + // Withdrawal amount. Should match the real value of the earned reward. + uint64 withdraw_amount = 2; +} + message TransactionPlan { // total coins in the utxos uint64 available_amount = 1; @@ -79,6 +119,12 @@ message TransactionPlan { // coins in the change UTXO uint64 change = 4; + // coins deposited (going to deposit) in this TX + uint64 deposit = 10; + + // coins undeposited (coming from deposit) in this TX + uint64 undeposit = 11; + // total tokens in the utxos (optional) repeated TokenAmount available_tokens = 5; @@ -104,6 +150,18 @@ message SigningInput { // Later this can be made oneof if more message types are supported Transfer transfer_message = 3; + // Optional, used in case of Staking Key registration (prerequisite for Staking) + RegisterStakingKey register_staking_key = 6; + + // Optional, used in case of (re)delegation + Delegate delegate = 7; + + // Optional, used in case of withdraw + Withdraw withdraw = 8; + + // Optional + DeregisterStakingKey deregister_staking_key = 9; + uint64 ttl = 4; // Optional plan diff --git a/swift/Tests/Blockchains/CardanoTests.swift b/swift/Tests/Blockchains/CardanoTests.swift index 4a2b6103949..32561ab157d 100644 --- a/swift/Tests/Blockchains/CardanoTests.swift +++ b/swift/Tests/Blockchains/CardanoTests.swift @@ -132,4 +132,93 @@ class CardanoTests: XCTestCase { let txid = output.txID XCTAssertEqual(txid.hexString, "201c537693b005b64a0f0528e366ec67a84be0119ed4363b547f141f2a7770c2") } + + func testGetStakingAddress() throws { + let stakingAddress = Cardano.getStakingAddress(baseAddress: "addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23") + XCTAssertEqual(stakingAddress, "stake1u80jysjtdzqt88jt4jx93h5lumfr67d273r4vwyasfa2pxcwxllmx") + } + + func testSignStakingRegisterAndDelegate() throws { + let ownAddress = "addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23" + let stakingAddress = Cardano.getStakingAddress(baseAddress: ownAddress) + let poolIdNufi = "7d7ac07a2f2a25b7a4db868a40720621c4939cf6aefbb9a11464f1a6" + + var input = CardanoSigningInput.with { + $0.transferMessage.toAddress = ownAddress + $0.transferMessage.changeAddress = ownAddress + $0.transferMessage.amount = 4000000 // not relevant as we use MaxAmount + $0.transferMessage.useMaxAmount = true + $0.ttl = 69885081 + // Register staking key, 2 ADA desposit + $0.registerStakingKey.stakingAddress = stakingAddress + $0.registerStakingKey.depositAmount = 2000000 + // Delegate + $0.delegate.stakingAddress = stakingAddress + $0.delegate.poolID = Data(hexString: poolIdNufi)! + $0.delegate.depositAmount = 0 + } + input.privateKey.append(Data(hexString: "089b68e458861be0c44bf9f7967f05cc91e51ede86dc679448a3566990b7785bd48c330875b1e0d03caaed0e67cecc42075dce1c7a13b1c49240508848ac82f603391c68824881ae3fc23a56a1a75ada3b96382db502e37564e84a5413cfaf1290dbd508e5ec71afaea98da2df1533c22ef02a26bb87b31907d0b2738fb7785b38d53aa68fc01230784c9209b2b2a2faf28491b3b1f1d221e63e704bbd0403c4154425dfbb01a2c5c042da411703603f89af89e57faae2946e2a5c18b1c5ca0e")!) + + let utxo1 = CardanoTxInput.with { + $0.outPoint.txHash = Data(hexString: "9b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e")! + $0.outPoint.outputIndex = 0 + $0.address = ownAddress + $0.amount = 4000000 + } + let utxo2 = CardanoTxInput.with { + $0.outPoint.txHash = Data(hexString: "9b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e")! + $0.outPoint.outputIndex = 1 + $0.address = ownAddress + $0.amount = 26651312 + } + input.utxos.append(utxo1) + input.utxos.append(utxo2) + + // Sign + let output: CardanoSigningOutput = AnySigner.sign(input: input, coin: .cardano) + XCTAssertEqual(output.error, TW_Common_Proto_SigningError.ok) + + let encoded = output.encoded + XCTAssertEqual(encoded.hexString, + "83a500828258209b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e008258209b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e01018182583901df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b1a01b27ef5021a0002b03b031a042a5c99048282008200581cdf22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b83028200581cdf22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b581c7d7ac07a2f2a25b7a4db868a40720621c4939cf6aefbb9a11464f1a6a100828258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df2905840677c901704be027d9a1734e8aa06f0700009476fa252baaae0de280331746a320a61456d842d948ea5c0e204fc36f3bd04c88ca7ee3d657d5a38014243c37c07825820e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e0693258401fa21bdc62b85ca217bf08cbacdeba2fadaf33dc09ee3af9cc25b40f24822a1a42cfbc03585cc31a370ef75aaec4d25db6edcf329e40a4e725ec8718c94f220af6") + + let txid = output.txID + XCTAssertEqual(txid.hexString, "96a781fd6481b6a7fd3926da110265e8c44b53947b81daa84da5b148825d02aa") + } + + func testSignStakingWithdraw() throws { + let ownAddress = "addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23" + let stakingAddress = Cardano.getStakingAddress(baseAddress: "addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23") + + var input = CardanoSigningInput.with { + $0.transferMessage.toAddress = ownAddress + $0.transferMessage.changeAddress = ownAddress + $0.transferMessage.amount = 6000000 // not relevant as we use MaxAmount + $0.transferMessage.useMaxAmount = true + $0.ttl = 71678326 + // Withdraw available amount + $0.withdraw.stakingAddress = stakingAddress + $0.withdraw.withdrawAmount = 3468 + } + input.privateKey.append(Data(hexString: "089b68e458861be0c44bf9f7967f05cc91e51ede86dc679448a3566990b7785bd48c330875b1e0d03caaed0e67cecc42075dce1c7a13b1c49240508848ac82f603391c68824881ae3fc23a56a1a75ada3b96382db502e37564e84a5413cfaf1290dbd508e5ec71afaea98da2df1533c22ef02a26bb87b31907d0b2738fb7785b38d53aa68fc01230784c9209b2b2a2faf28491b3b1f1d221e63e704bbd0403c4154425dfbb01a2c5c042da411703603f89af89e57faae2946e2a5c18b1c5ca0e")!) + + let utxo1 = CardanoTxInput.with { + $0.outPoint.txHash = Data(hexString: "7dfd2c579794314b1f84efc9db932a098e440ccefb874945591f1d4e85a9152a")! + $0.outPoint.outputIndex = 0 + $0.address = ownAddress + $0.amount = 6305913 + } + input.utxos.append(utxo1) + + // Sign + let output: CardanoSigningOutput = AnySigner.sign(input: input, coin: .cardano) + XCTAssertEqual(output.error, TW_Common_Proto_SigningError.ok) + + let encoded = output.encoded + XCTAssertEqual(encoded.hexString, + "83a500818258207dfd2c579794314b1f84efc9db932a098e440ccefb874945591f1d4e85a9152a00018182583901df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b1a005da6ff021a00029f06031a0445b97605a1581de1df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b190d8ca100828258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df29058401ebaca2876fd17122404912a2558a98109cdf0f990a938d2917fa2c3b8c4e55e18a2cbabfa82fff03fa0d7ab8b88ca01ed18e42af3bfc4cda7f423a3aa30c00b825820e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e069325840777f04fa8f083fe562aecf78898aaaaac36e2cc6ca962f6ffb01e84a421cae1860496db79b2c5fb2879524c3d5121060b9ea1e693336230c6e5338e14c4c3303f6") + + let txid = output.txID + XCTAssertEqual(txid.hexString, "6dcf3956232953fc25b8355fb1ded1e912b5802090fd21434d789087d6329683") + } } diff --git a/tests/Cardano/AddressTests.cpp b/tests/Cardano/AddressTests.cpp index 0b4a24218f5..8a8918fe6c9 100644 --- a/tests/Cardano/AddressTests.cpp +++ b/tests/Cardano/AddressTests.cpp @@ -72,6 +72,21 @@ TEST(CardanoAddress, Validation) { } TEST(CardanoAddress, FromStringV2) { + { + auto address = AddressV3("addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq"); + EXPECT_EQ(address.kind, AddressV3::Kind_Base); + EXPECT_EQ(hex(address.data()), "01" "8d98bea0414243dc84070f96265577e7e6cf702d62e871016885034e" "cc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468"); + } + { + auto address = AddressV3("addr1qxteqxsgxrs4he9d28lh70qu7qfz7saj6dmxwsqyle2yp3xvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35quehtx3"); + EXPECT_EQ(address.kind, AddressV3::Kind_Base); + EXPECT_EQ(hex(address.data()), "01" "97901a0830e15be4ad51ff7f3c1cf0122f43b2d376674004fe5440c4" "cc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468"); + } + { + auto address = AddressV3("addr1q8sfzcwce0fqll3symd7f0amayxqq68nxt2u8pgen9y00tkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35q40ytea"); + EXPECT_EQ(address.kind, AddressV3::Kind_Base); + EXPECT_EQ(hex(address.data()), "01" "e09161d8cbd20ffe3026dbe4bfbbe90c0068f332d5c385199948f7ae" "cc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468"); + } { auto address = AddressV3("Ae2tdPwUPEZ18ZjTLnLVr9CEvUEUX4eW1LBHbxxxJgxdAYHrDeSCSbCxrvx"); ASSERT_EQ(address.string(), "Ae2tdPwUPEZ18ZjTLnLVr9CEvUEUX4eW1LBHbxxxJgxdAYHrDeSCSbCxrvx"); @@ -463,4 +478,33 @@ TEST(CardanoAddress, AssignmentOperatorLegacy) { EXPECT_TRUE(*address.legacyAddressV2 == *addr3leg.legacyAddressV2); } +TEST(CardanoAddress, StakingKey) { + { + auto address = AddressV3("addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23"); + EXPECT_EQ(hex(address.data()), "01df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b"); + EXPECT_EQ(address.getStakingAddress(), "stake1u80jysjtdzqt88jt4jx93h5lumfr67d273r4vwyasfa2pxcwxllmx"); + EXPECT_EQ(hex(AddressV3(address.getStakingAddress()).data()), "e1df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b"); + EXPECT_EQ(hex(AddressV3(address.getStakingAddress()).bytes), "df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b"); + } + { + auto address = AddressV3("addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq"); + EXPECT_EQ(hex(address.data()), "018d98bea0414243dc84070f96265577e7e6cf702d62e871016885034ecc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468"); + EXPECT_EQ(address.getStakingAddress(), "stake1u8xxf0e93w8rxr8sehvlmvp7zz6wftqg7hdplhkxyg4rg6qwgxzhc"); + EXPECT_EQ(hex(AddressV3(address.getStakingAddress()).data()), "e1cc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468"); + EXPECT_EQ(hex(AddressV3(address.getStakingAddress()).bytes), "cc64bf258b8e330cf0cdd9fdb03e10b4e4ac08f5da1fdec6222a3468"); + } + { + auto address = AddressV3("addr1q8lcljuzfg8yvpuv94x02sytmwd8jsalzf6u0j8muhq69wng9ejcvpyczmw0zx7wguq2dml4xdl2wj3k7uexsfnxep2q9ja352"); + EXPECT_EQ(hex(address.data()), "01ff8fcb824a0e46078c2d4cf5408bdb9a7943bf1275c7c8fbe5c1a2ba682e6586049816dcf11bce4700a6eff5337ea74a36f732682666c854"); + EXPECT_EQ(address.getStakingAddress(), "stake1u95zuevxqjvpdh83r08ywq9xal6nxl48fgm0wvngyenvs4qh0hqf9"); + EXPECT_EQ(hex(AddressV3(address.getStakingAddress()).data()), "e1682e6586049816dcf11bce4700a6eff5337ea74a36f732682666c854"); + EXPECT_EQ(hex(AddressV3(address.getStakingAddress()).bytes), "682e6586049816dcf11bce4700a6eff5337ea74a36f732682666c854"); + } + { // negative case: cannot get staking address from non-base address + auto address = AddressV3("stake1u95zuevxqjvpdh83r08ywq9xal6nxl48fgm0wvngyenvs4qh0hqf9"); + EXPECT_EQ(hex(address.data()), "e1682e6586049816dcf11bce4700a6eff5337ea74a36f732682666c854"); + EXPECT_EQ(address.getStakingAddress(), ""); + } +} + } // namespace TW::Cardano::tests diff --git a/tests/Cardano/SigningTests.cpp b/tests/Cardano/SigningTests.cpp index d731747b081..d0fb95a5a95 100644 --- a/tests/Cardano/SigningTests.cpp +++ b/tests/Cardano/SigningTests.cpp @@ -22,7 +22,7 @@ using namespace TW; using namespace std; -namespace TW::Cardano::tests { +namespace TW::Cardano::SigningTests { const auto privateKeyTest1 = "089b68e458861be0c44bf9f7967f05cc91e51ede86dc679448a3566990b7785bd48c330875b1e0d03caaed0e67cecc42075dce1c7a13b1c49240508848ac82f603391c68824881ae3fc23a56a1a75ada3b96382db502e37564e84a5413cfaf1290dbd508e5ec71afaea98da2df1533c22ef02a26bb87b31907d0b2738fb7785b38d53aa68fc01230784c9209b2b2a2faf28491b3b1f1d221e63e704bbd0403c4154425dfbb01a2c5c042da411703603f89af89e57faae2946e2a5c18b1c5ca0e"; const auto ownAddress1 = "addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23"; diff --git a/tests/Cardano/StakingTests.cpp b/tests/Cardano/StakingTests.cpp new file mode 100644 index 00000000000..a1cc13e71f1 --- /dev/null +++ b/tests/Cardano/StakingTests.cpp @@ -0,0 +1,351 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Cardano/AddressV3.h" +#include "Cardano/Signer.h" +#include "proto/Cardano.pb.h" +#include + +#include "Cbor.h" +#include "HexCoding.h" +#include "PrivateKey.h" +#include "uint256.h" +#include "../interface/TWTestUtilities.h" +#include + +#include +#include + +using namespace TW; +using namespace std; + +namespace TW::Cardano::StakingTests { + +const auto privateKeyTest1 = "089b68e458861be0c44bf9f7967f05cc91e51ede86dc679448a3566990b7785bd48c330875b1e0d03caaed0e67cecc42075dce1c7a13b1c49240508848ac82f603391c68824881ae3fc23a56a1a75ada3b96382db502e37564e84a5413cfaf1290dbd508e5ec71afaea98da2df1533c22ef02a26bb87b31907d0b2738fb7785b38d53aa68fc01230784c9209b2b2a2faf28491b3b1f1d221e63e704bbd0403c4154425dfbb01a2c5c042da411703603f89af89e57faae2946e2a5c18b1c5ca0e"; +const auto ownAddress1 = "addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23"; +const auto stakingAddress1 = "stake1u80jysjtdzqt88jt4jx93h5lumfr67d273r4vwyasfa2pxcwxllmx"; +const auto poolIdNufi = "7d7ac07a2f2a25b7a4db868a40720621c4939cf6aefbb9a11464f1a6"; + +TEST(CardanoStaking, RegisterStakingKey) { + const auto privateKeyData = parse_hex(privateKeyTest1); + const auto publicKey = PrivateKey(privateKeyData).getPublicKey(TWPublicKeyTypeED25519Cardano); + const auto ownAddress = AddressV3(publicKey).string(); + EXPECT_EQ(ownAddress, ownAddress1); + const auto stakingAddress = AddressV3(publicKey).getStakingAddress(); + EXPECT_EQ(stakingAddress, stakingAddress1); + const auto poolId = parse_hex(poolIdNufi); + + Proto::SigningInput input; + auto* utxo1 = input.add_utxos(); + const auto txHash1 = parse_hex("cba84549f07f2128410c0a22731f2c57f2a617746e8edc61b295cd8792638dca"); + utxo1->mutable_out_point()->set_tx_hash(txHash1.data(), txHash1.size()); + utxo1->mutable_out_point()->set_output_index(1); + utxo1->set_address(ownAddress); + utxo1->set_amount(10000000ul); + + input.add_private_key(privateKeyData.data(), privateKeyData.size()); + + input.mutable_transfer_message()->set_to_address(ownAddress); + input.mutable_transfer_message()->set_change_address(ownAddress); + input.mutable_transfer_message()->set_amount(5000000ul); // not relevant if we use MaxAmount + input.mutable_transfer_message()->set_use_max_amount(true); + input.set_ttl(69986091ul); + + // Register staking key, 2 ADA deposit + input.mutable_register_staking_key()->set_staking_address(stakingAddress); + input.mutable_register_staking_key()->set_deposit_amount(2000000ul); + + auto signer = Signer(input); + const auto output = signer.sign(); + + EXPECT_EQ(output.error(), Common::Proto::OK); + + const auto encoded = data(output.encoded()); + EXPECT_EQ(hex(encoded), "83a50081825820cba84549f07f2128410c0a22731f2c57f2a617746e8edc61b295cd8792638dca01018182583901df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b1a007772fa021a00029f06031a042be72b048182008200581cdf22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09ba100828258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df2905840d08ed71da87d0928090edd9e226496ab109f2eee7926ac2ce51e7abe89a4f513c4afe2b85b71595e862e7f6fc992d14d2416a6e53a1961da7d26d3cf3f823400825820e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e06932584079ed55400cebc70c56ca87ba09009dfc298c64768f90a9139bf2e7f134250927c614ee846253fac33e652f1b50373d349fdfe13c207968c2a10991824fe2a10ef6"); + const auto txid = data(output.tx_id()); + EXPECT_EQ(hex(txid), "6a206fe4df76e12499b4fd9722f33429f4d93f8a996f9f523fa6c02a8301386b"); + + { + const auto decode = Cbor::Decode(encoded); + ASSERT_TRUE(decode.isValid()); + EXPECT_EQ(decode.dumpToString(), "[{0: [[h\"cba84549f07f2128410c0a22731f2c57f2a617746e8edc61b295cd8792638dca\", 1]], 1: [[h\"01df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\", 7828218]], 2: 171782, 3: 69986091, 4: [[0, [0, h\"df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\"]]]}, {0: [[h\"6d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df290\", h\"d08ed71da87d0928090edd9e226496ab109f2eee7926ac2ce51e7abe89a4f513c4afe2b85b71595e862e7f6fc992d14d2416a6e53a1961da7d26d3cf3f823400\"], [h\"e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e06932\", h\"79ed55400cebc70c56ca87ba09009dfc298c64768f90a9139bf2e7f134250927c614ee846253fac33e652f1b50373d349fdfe13c207968c2a10991824fe2a10e\"]]}, null]"); + EXPECT_EQ(decode.getArrayElements().size(), 3ul); + } +} + +TEST(CardanoStaking, DeregisterStakingKey) { + const auto privateKeyData = parse_hex(privateKeyTest1); + const auto publicKey = PrivateKey(privateKeyData).getPublicKey(TWPublicKeyTypeED25519Cardano); + const auto ownAddress = AddressV3(publicKey).string(); + EXPECT_EQ(ownAddress, ownAddress1); + const auto stakingAddress = AddressV3(publicKey).getStakingAddress(); + EXPECT_EQ(stakingAddress, stakingAddress1); + const auto poolId = parse_hex(poolIdNufi); + + Proto::SigningInput input; + auto* utxo1 = input.add_utxos(); + const auto txHash1 = parse_hex("cba84549f07f2128410c0a22731f2c57f2a617746e8edc61b295cd8792638dca"); + utxo1->mutable_out_point()->set_tx_hash(txHash1.data(), txHash1.size()); + utxo1->mutable_out_point()->set_output_index(1); + utxo1->set_address(ownAddress); + utxo1->set_amount(10000000ul); + + input.add_private_key(privateKeyData.data(), privateKeyData.size()); + + input.mutable_transfer_message()->set_to_address(ownAddress); + input.mutable_transfer_message()->set_change_address(ownAddress); + input.mutable_transfer_message()->set_amount(5000000ul); // not relevant if we use MaxAmount + input.mutable_transfer_message()->set_use_max_amount(true); + input.set_ttl(69986091ul); + + // Deregister staking key, get back 2 ADA deposit + input.mutable_deregister_staking_key()->set_staking_address(stakingAddress); + input.mutable_deregister_staking_key()->set_undeposit_amount(2000000ul); + + auto signer = Signer(input); + const auto output = signer.sign(); + + EXPECT_EQ(output.error(), Common::Proto::OK); + + const auto encoded = data(output.encoded()); + EXPECT_EQ(hex(encoded), "83a50081825820cba84549f07f2128410c0a22731f2c57f2a617746e8edc61b295cd8792638dca01018182583901df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b1a00b47bfa021a00029f06031a042be72b048182018200581cdf22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09ba100828258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df290584056619a7d6192b6f68c31a43e927c893161fd994d5c1bcc16f3710cf5e5e652e01f118d55f0110e9de34edc050d509748bea637db5c34f4fe342ae262ccb5520d825820e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e069325840d23680fdd8aa63e10efccc550eb726743b653008952f9d731d076d1df8106b0401823ebb195127b211389f1bc2c3f6ededbcec04bc8f0de93607a2409421e006f6"); + const auto txid = data(output.tx_id()); + EXPECT_EQ(hex(txid), "1caae2456e5471cc77e73410da475fb0a23874c18c1ea55f9267c59767caef0a"); + + { + const auto decode = Cbor::Decode(encoded); + ASSERT_TRUE(decode.isValid()); + EXPECT_EQ(decode.dumpToString(), "[{0: [[h\"cba84549f07f2128410c0a22731f2c57f2a617746e8edc61b295cd8792638dca\", 1]], 1: [[h\"01df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\", 11828218]], 2: 171782, 3: 69986091, 4: [[1, [0, h\"df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\"]]]}, {0: [[h\"6d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df290\", h\"56619a7d6192b6f68c31a43e927c893161fd994d5c1bcc16f3710cf5e5e652e01f118d55f0110e9de34edc050d509748bea637db5c34f4fe342ae262ccb5520d\"], [h\"e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e06932\", h\"d23680fdd8aa63e10efccc550eb726743b653008952f9d731d076d1df8106b0401823ebb195127b211389f1bc2c3f6ededbcec04bc8f0de93607a2409421e006\"]]}, null]"); + EXPECT_EQ(decode.getArrayElements().size(), 3ul); + } +} + +TEST(CardanoStaking, Redelegate) { + const auto privateKeyData = parse_hex(privateKeyTest1); + const auto publicKey = PrivateKey(privateKeyData).getPublicKey(TWPublicKeyTypeED25519Cardano); + const auto ownAddress = AddressV3(publicKey).string(); + EXPECT_EQ(ownAddress, ownAddress1); + const auto stakingAddress = AddressV3(publicKey).getStakingAddress(); + EXPECT_EQ(stakingAddress, stakingAddress1); + const auto poolId = parse_hex(poolIdNufi); + + Proto::SigningInput input; + auto* utxo1 = input.add_utxos(); + const auto txHash1 = parse_hex("cba84549f07f2128410c0a22731f2c57f2a617746e8edc61b295cd8792638dca"); + utxo1->mutable_out_point()->set_tx_hash(txHash1.data(), txHash1.size()); + utxo1->mutable_out_point()->set_output_index(1); + utxo1->set_address(ownAddress); + utxo1->set_amount(10000000ul); + + input.add_private_key(privateKeyData.data(), privateKeyData.size()); + + input.mutable_transfer_message()->set_to_address(ownAddress); + input.mutable_transfer_message()->set_change_address(ownAddress); + input.mutable_transfer_message()->set_amount(5000000ul); // not relevant if we use MaxAmount + input.mutable_transfer_message()->set_use_max_amount(true); + input.set_ttl(69986091ul); + + // Delegate, no deposit + input.mutable_delegate()->set_staking_address(stakingAddress); + input.mutable_delegate()->set_pool_id(poolId.data(), poolId.size()); + input.mutable_delegate()->set_deposit_amount(0ul); + + auto signer = Signer(input); + const auto output = signer.sign(); + + EXPECT_EQ(output.error(), Common::Proto::OK); + + const auto encoded = data(output.encoded()); + EXPECT_EQ(hex(encoded), "83a50081825820cba84549f07f2128410c0a22731f2c57f2a617746e8edc61b295cd8792638dca01018182583901df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b1a0095f251021a0002a42f031a042be72b048183028200581cdf22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b581c7d7ac07a2f2a25b7a4db868a40720621c4939cf6aefbb9a11464f1a6a100828258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df2905840fb48f3ddbfc2d4ca231a0581c5b456019aa4215ed5a2447ba89a4860569f9e7296afd3a0a81506882d8bda33683e623e6d8033786275369f7e247d866e017c06825820e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e069325840e26f696a6cd1c34101623568c9efe3796ff5855ada0e2e0cf557c7fc2148f6b2af176aff40a1f9c13fb29d9636c49f774d4a967c71f052f865cfaf0d02d5bb05f6"); + const auto txid = data(output.tx_id()); + EXPECT_EQ(hex(txid), "985f613fb8b86dad35f075599099776e50fc2a6aa74ee4b37c14fd9f2c0f0891"); + + { + const auto decode = Cbor::Decode(encoded); + ASSERT_TRUE(decode.isValid()); + EXPECT_EQ(decode.dumpToString(), "[{0: [[h\"cba84549f07f2128410c0a22731f2c57f2a617746e8edc61b295cd8792638dca\", 1]], 1: [[h\"01df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\", 9826897]], 2: 173103, 3: 69986091, 4: [[2, [0, h\"df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\"], h\"7d7ac07a2f2a25b7a4db868a40720621c4939cf6aefbb9a11464f1a6\"]]}, {0: [[h\"6d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df290\", h\"fb48f3ddbfc2d4ca231a0581c5b456019aa4215ed5a2447ba89a4860569f9e7296afd3a0a81506882d8bda33683e623e6d8033786275369f7e247d866e017c06\"], [h\"e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e06932\", h\"e26f696a6cd1c34101623568c9efe3796ff5855ada0e2e0cf557c7fc2148f6b2af176aff40a1f9c13fb29d9636c49f774d4a967c71f052f865cfaf0d02d5bb05\"]]}, null]"); + EXPECT_EQ(decode.getArrayElements().size(), 3ul); + } +} + +TEST(CardanoStaking, RegisterAndDelegate_similar53339b) { + const auto privateKeyData = parse_hex(privateKeyTest1); + const auto publicKey = PrivateKey(privateKeyData).getPublicKey(TWPublicKeyTypeED25519Cardano); + const auto ownAddress = AddressV3(publicKey).string(); + EXPECT_EQ(ownAddress, ownAddress1); + const auto stakingAddress = AddressV3(publicKey).getStakingAddress(); + EXPECT_EQ(stakingAddress, stakingAddress1); + const auto poolId = parse_hex(poolIdNufi); + + Proto::SigningInput input; + auto* utxo1 = input.add_utxos(); + const auto txHash1 = parse_hex("9b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e"); + utxo1->mutable_out_point()->set_tx_hash(txHash1.data(), txHash1.size()); + utxo1->mutable_out_point()->set_output_index(0); + utxo1->set_address(ownAddress); + utxo1->set_amount(4000000ul); + auto* utxo2 = input.add_utxos(); + const auto txHash2 = parse_hex("9b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e"); + utxo2->mutable_out_point()->set_tx_hash(txHash2.data(), txHash2.size()); + utxo2->mutable_out_point()->set_output_index(1); + utxo2->set_address(ownAddress); + utxo2->set_amount(26651312ul); + + input.add_private_key(privateKeyData.data(), privateKeyData.size()); + + input.mutable_transfer_message()->set_to_address(ownAddress); + input.mutable_transfer_message()->set_change_address(ownAddress); + input.mutable_transfer_message()->set_amount(4000000ul); // not relevant if we use MaxAmount + input.mutable_transfer_message()->set_use_max_amount(true); + input.set_ttl(69885081ul); + + // Register staking key, 2 ADA desposit + input.mutable_register_staking_key()->set_staking_address(stakingAddress); + input.mutable_register_staking_key()->set_deposit_amount(2000000ul); + + // Delegate + input.mutable_delegate()->set_staking_address(stakingAddress); + input.mutable_delegate()->set_pool_id(poolId.data(), poolId.size()); + input.mutable_delegate()->set_deposit_amount(0ul); + + { + // run plan and check result + auto signer = Signer(input); + const auto plan = signer.doPlan(); + + const auto amount = 28475125ul; + const auto availAmount = 30651312ul; + EXPECT_EQ(plan.availableAmount, availAmount); + EXPECT_EQ(plan.amount, amount); + const auto fee = 176187ul; + EXPECT_EQ(plan.fee, fee); + EXPECT_EQ(plan.change, availAmount - 2000000ul - amount - fee); + EXPECT_EQ(plan.change, 0ul); + + // perform sign with default plan + const auto output = signer.sign(); + + EXPECT_EQ(output.error(), Common::Proto::OK); + + const auto encoded = data(output.encoded()); + EXPECT_EQ(hex(encoded), "83a500828258209b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e008258209b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e01018182583901df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b1a01b27ef5021a0002b03b031a042a5c99048282008200581cdf22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b83028200581cdf22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b581c7d7ac07a2f2a25b7a4db868a40720621c4939cf6aefbb9a11464f1a6a100828258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df2905840677c901704be027d9a1734e8aa06f0700009476fa252baaae0de280331746a320a61456d842d948ea5c0e204fc36f3bd04c88ca7ee3d657d5a38014243c37c07825820e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e0693258401fa21bdc62b85ca217bf08cbacdeba2fadaf33dc09ee3af9cc25b40f24822a1a42cfbc03585cc31a370ef75aaec4d25db6edcf329e40a4e725ec8718c94f220af6"); + const auto txid = data(output.tx_id()); + EXPECT_EQ(hex(txid), "96a781fd6481b6a7fd3926da110265e8c44b53947b81daa84da5b148825d02aa"); + } + + // set different plan, with exact fee + const auto amount = 28467322ul; + input.mutable_plan()->set_amount(amount); + input.mutable_plan()->set_available_amount(28651312ul); + input.mutable_plan()->set_fee(183990); + input.mutable_plan()->set_change(0); + *(input.mutable_plan()->add_utxos()) = input.utxos(0); + *(input.mutable_plan()->add_utxos()) = input.utxos(1); + input.mutable_plan()->set_error(Common::Proto::OK); + + auto signer = Signer(input); + const auto output = signer.sign(); + + EXPECT_EQ(output.error(), Common::Proto::OK); + + // Similar to (but with different key): https://cardanoscan.io/transaction/53339b758009a0896a87e9569cadcdb5a095ffe0c100cc7483d72e817e81b60b + const auto encoded = data(output.encoded()); + EXPECT_EQ(hex(encoded), "83a500828258209b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e008258209b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e01018182583901df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b1a01b2607a021a0002ceb6031a042a5c99048282008200581cdf22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b83028200581cdf22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b581c7d7ac07a2f2a25b7a4db868a40720621c4939cf6aefbb9a11464f1a6a100828258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df29058405d8b21c993aec7a7bdf0c832e5688920b64b665e1e36a2e6040d6dd8ad195e7774df3c1377047737d8b676fa4115e38fbf6ef854904db6d9c8ee3e26e8561408825820e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e06932584088a3f6387693f9077d11a6e245e024b791074bcaa26c034e687d67f3324b6f90a437d33d0343e11c7dee1a28270c223e02080e452fe97cdc93d26c720ab6b805f6"); + const auto txid = data(output.tx_id()); + EXPECT_EQ(hex(txid), "23e1d1bc27f6de57e323d232d44c909fb41ee2ebfff28b82ca8cae6947866ea7"); + + { + const auto decode = Cbor::Decode(encoded); + ASSERT_TRUE(decode.isValid()); + EXPECT_EQ(decode.dumpToString(), "[{0: [[h\"9b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e\", 0], [h\"9b06de86b253549b99f6a050b61217d8824085ca5ed4eb107a5e7cce4f93802e\", 1]], 1: [[h\"01df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\", 28467322]], 2: 183990, 3: 69885081, 4: [[0, [0, h\"df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\"]], [2, [0, h\"df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\"], h\"7d7ac07a2f2a25b7a4db868a40720621c4939cf6aefbb9a11464f1a6\"]]}, {0: [[h\"6d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df290\", h\"5d8b21c993aec7a7bdf0c832e5688920b64b665e1e36a2e6040d6dd8ad195e7774df3c1377047737d8b676fa4115e38fbf6ef854904db6d9c8ee3e26e8561408\"], [h\"e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e06932\", h\"88a3f6387693f9077d11a6e245e024b791074bcaa26c034e687d67f3324b6f90a437d33d0343e11c7dee1a28270c223e02080e452fe97cdc93d26c720ab6b805\"]]}, null]"); + EXPECT_EQ(decode.getArrayElements().size(), 3ul); + } +} + +TEST(CardanoStaking, Withdraw_similarf48098) { + const auto privateKeyData = parse_hex(privateKeyTest1); + const auto publicKey = PrivateKey(privateKeyData).getPublicKey(TWPublicKeyTypeED25519Cardano); + const auto ownAddress = AddressV3(publicKey).string(); + EXPECT_EQ(ownAddress, ownAddress1); + const auto stakingAddress = AddressV3(publicKey).getStakingAddress(); + EXPECT_EQ(stakingAddress, stakingAddress1); + + Proto::SigningInput input; + auto* utxo1 = input.add_utxos(); + const auto txHash1 = parse_hex("7dfd2c579794314b1f84efc9db932a098e440ccefb874945591f1d4e85a9152a"); + utxo1->mutable_out_point()->set_tx_hash(txHash1.data(), txHash1.size()); + utxo1->mutable_out_point()->set_output_index(0); + utxo1->set_address(ownAddress); + utxo1->set_amount(6305913ul); + + input.add_private_key(privateKeyData.data(), privateKeyData.size()); + + input.mutable_transfer_message()->set_to_address(ownAddress); + input.mutable_transfer_message()->set_change_address(ownAddress); + input.mutable_transfer_message()->set_amount(6000000ul); // not relevant if we use MaxAmount + input.mutable_transfer_message()->set_use_max_amount(true); + input.set_ttl(71678326ul); + + // Withdraw available amount + const auto withdrawAmount = 3468ul; + input.mutable_withdraw()->set_staking_address(stakingAddress); + input.mutable_withdraw()->set_withdraw_amount(withdrawAmount); + + { + // run plan and check result + auto signer = Signer(input); + const auto plan = signer.doPlan(); + + const auto amount = 6137599ul; + const auto availAmount = 6305913ul; + EXPECT_EQ(plan.availableAmount, availAmount); + EXPECT_EQ(plan.amount, amount); + const auto fee = 171782ul; + EXPECT_EQ(plan.fee, fee); + EXPECT_EQ(plan.change, availAmount + withdrawAmount - amount - fee); + EXPECT_EQ(plan.change, 0ul); + + // perform sign with default plan + const auto output = signer.sign(); + + EXPECT_EQ(output.error(), Common::Proto::OK); + + const auto encoded = data(output.encoded()); + EXPECT_EQ(hex(encoded), "83a500818258207dfd2c579794314b1f84efc9db932a098e440ccefb874945591f1d4e85a9152a00018182583901df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b1a005da6ff021a00029f06031a0445b97605a1581de1df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b190d8ca100828258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df29058401ebaca2876fd17122404912a2558a98109cdf0f990a938d2917fa2c3b8c4e55e18a2cbabfa82fff03fa0d7ab8b88ca01ed18e42af3bfc4cda7f423a3aa30c00b825820e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e069325840777f04fa8f083fe562aecf78898aaaaac36e2cc6ca962f6ffb01e84a421cae1860496db79b2c5fb2879524c3d5121060b9ea1e693336230c6e5338e14c4c3303f6"); + const auto txid = data(output.tx_id()); + EXPECT_EQ(hex(txid), "6dcf3956232953fc25b8355fb1ded1e912b5802090fd21434d789087d6329683"); + } + + // set different plan, with exact fee + const auto amount = 6137599ul; + input.mutable_plan()->set_amount(amount); + input.mutable_plan()->set_available_amount(6305913ul); + input.mutable_plan()->set_fee(171782ul); + input.mutable_plan()->set_change(0); + *(input.mutable_plan()->add_utxos()) = input.utxos(0); + input.mutable_plan()->set_error(Common::Proto::OK); + + auto signer = Signer(input); + const auto output = signer.sign(); + + EXPECT_EQ(output.error(), Common::Proto::OK); + + // Similar to (but with different key): https://cardanoscan.io/transaction/f480985662886e419a22673d31944455ab8891a80940bf392a37d9288ea9cf01?tab=withdrawals + const auto encoded = data(output.encoded()); + EXPECT_EQ(hex(encoded), "83a500818258207dfd2c579794314b1f84efc9db932a098e440ccefb874945591f1d4e85a9152a00018182583901df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b1a005da6ff021a00029f06031a0445b97605a1581de1df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b190d8ca100828258206d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df29058401ebaca2876fd17122404912a2558a98109cdf0f990a938d2917fa2c3b8c4e55e18a2cbabfa82fff03fa0d7ab8b88ca01ed18e42af3bfc4cda7f423a3aa30c00b825820e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e069325840777f04fa8f083fe562aecf78898aaaaac36e2cc6ca962f6ffb01e84a421cae1860496db79b2c5fb2879524c3d5121060b9ea1e693336230c6e5338e14c4c3303f6"); + const auto txid = data(output.tx_id()); + EXPECT_EQ(hex(txid), "6dcf3956232953fc25b8355fb1ded1e912b5802090fd21434d789087d6329683"); + + { + const auto decode = Cbor::Decode(encoded); + ASSERT_TRUE(decode.isValid()); + EXPECT_EQ(decode.dumpToString(), "[{0: [[h\"7dfd2c579794314b1f84efc9db932a098e440ccefb874945591f1d4e85a9152a\", 0]], 1: [[h\"01df58ee97ce7a46cd8bdeec4e5f3a03297eb197825ed5681191110804df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\", 6137599]], 2: 171782, 3: 71678326, 5: {h\"e1df22424b6880b39e4bac8c58de9fe6d23d79aaf44756389d827aa09b\": 3468}}, {0: [[h\"6d8a0b425bd2ec9692af39b1c0cf0e51caa07a603550e22f54091e872c7df290\", h\"1ebaca2876fd17122404912a2558a98109cdf0f990a938d2917fa2c3b8c4e55e18a2cbabfa82fff03fa0d7ab8b88ca01ed18e42af3bfc4cda7f423a3aa30c00b\"], [h\"e554163344aafc2bbefe778a6953ddce0583c2f8e0a0686929c020ca33e06932\", h\"777f04fa8f083fe562aecf78898aaaaac36e2cc6ca962f6ffb01e84a421cae1860496db79b2c5fb2879524c3d5121060b9ea1e693336230c6e5338e14c4c3303\"]]}, null]"); + + EXPECT_EQ(decode.getArrayElements().size(), 3ul); + } +} + +} // namespace TW::Cardano::tests diff --git a/tests/Cardano/TWCardanoAddressTests.cpp b/tests/Cardano/TWCardanoAddressTests.cpp index ab2d7689807..33af5be338b 100644 --- a/tests/Cardano/TWCardanoAddressTests.cpp +++ b/tests/Cardano/TWCardanoAddressTests.cpp @@ -53,3 +53,18 @@ TEST(TWCardano, AddressFromWallet) { auto address = WRAPS(TWCoinTypeDeriveAddress(TWCoinTypeCardano, privateKey.get())); assertStringsEqual(address, "addr1qxxe304qg9py8hyyqu8evfj4wln7dnms943wsugpdzzsxnkvvjljtzuwxvx0pnwelkcruy95ujkq3aw6rl0vvg32x35qc92xkq"); } + +TEST(TWCardano, GetStakingKey) { + { + auto stakingAddress = WRAPS(TWCardanoGetStakingAddress(STRING("addr1q8043m5heeaydnvtmmkyuhe6qv5havvhsf0d26q3jygsspxlyfpyk6yqkw0yhtyvtr0flekj84u64az82cufmqn65zdsylzk23").get())); + EXPECT_EQ(std::string(TWStringUTF8Bytes(stakingAddress.get())), "stake1u80jysjtdzqt88jt4jx93h5lumfr67d273r4vwyasfa2pxcwxllmx"); + } + { // negative case: cannot get staking address from non-base address + auto stakingAddress = WRAPS(TWCardanoGetStakingAddress(STRING("stake1u95zuevxqjvpdh83r08ywq9xal6nxl48fgm0wvngyenvs4qh0hqf9").get())); + EXPECT_EQ(std::string(TWStringUTF8Bytes(stakingAddress.get())), ""); + } + { // negative case: cannot get staking address from invalid address, should not throw + auto stakingAddress = WRAPS(TWCardanoGetStakingAddress(STRING("__THIS_IS_NOT_A_VALID_CARDANO_ADDRESS__").get())); + EXPECT_EQ(std::string(TWStringUTF8Bytes(stakingAddress.get())), ""); + } +} From e89ad9ee7695feb7685c1dd23ce1bddba7a8165b Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 20 Sep 2022 03:52:22 +0200 Subject: [PATCH 081/497] feat(clang-tidy): update entry.h to use final/override (#2576) --- src/Aeternity/Entry.h | 8 ++++---- src/Aion/Entry.h | 10 +++++----- src/Algorand/Entry.h | 12 ++++++------ src/Binance/Entry.h | 20 ++++++++++---------- src/Bitcoin/Entry.h | 18 +++++++++--------- src/Cardano/Entry.h | 12 ++++++------ src/Cosmos/Entry.h | 14 +++++++------- src/Decred/Entry.h | 12 ++++++------ src/EOS/Entry.h | 8 ++++---- src/Elrond/Entry.h | 14 +++++++------- src/Ethereum/Entry.h | 22 +++++++++++----------- src/Everscale/Entry.h | 10 +++++----- src/FIO/Entry.h | 8 ++++---- src/Filecoin/Entry.h | 12 ++++++------ src/Groestlcoin/Entry.h | 10 +++++----- src/Harmony/Entry.h | 14 +++++++------- src/Icon/Entry.h | 8 ++++---- src/IoTeX/Entry.h | 8 ++++---- src/Kusama/Entry.h | 10 +++++----- src/NEAR/Entry.h | 12 ++++++------ src/NEO/Entry.h | 12 ++++++------ src/NULS/Entry.h | 8 ++++---- src/Nano/Entry.h | 14 +++++++------- src/Nebulas/Entry.h | 8 ++++---- src/Nervos/Entry.h | 10 +++++----- src/Nimiq/Entry.h | 8 ++++---- src/Oasis/Entry.h | 8 ++++---- src/Ontology/Entry.h | 8 ++++---- src/Polkadot/Entry.h | 10 +++++----- src/Ripple/Entry.h | 8 ++++---- src/Ronin/Entry.h | 16 ++++++++-------- src/Solana/Entry.h | 14 +++++++------- src/Stellar/Entry.h | 8 ++++---- src/THORChain/Entry.h | 6 +++--- src/Tezos/Entry.h | 12 ++++++------ src/Theta/Entry.h | 4 ++-- src/Tron/Entry.h | 8 ++++---- src/VeChain/Entry.h | 4 ++-- src/Waves/Entry.h | 8 ++++---- src/Zcash/Entry.h | 12 ++++++------ src/Zilliqa/Entry.h | 14 +++++++------- 41 files changed, 221 insertions(+), 221 deletions(-) diff --git a/src/Aeternity/Entry.h b/src/Aeternity/Entry.h index 5fe072fc4bb..b344b0ebb1f 100644 --- a/src/Aeternity/Entry.h +++ b/src/Aeternity/Entry.h @@ -12,11 +12,11 @@ namespace TW::Aeternity { /// Entry point for implementation of Aeternity coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Aeternity diff --git a/src/Aion/Entry.h b/src/Aion/Entry.h index dcf26bda380..1ff2ed22dc1 100644 --- a/src/Aion/Entry.h +++ b/src/Aion/Entry.h @@ -12,12 +12,12 @@ namespace TW::Aion { /// Entry point for implementation of Aion coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Aion diff --git a/src/Algorand/Entry.h b/src/Algorand/Entry.h index 73e79334356..a2e2548839b 100644 --- a/src/Algorand/Entry.h +++ b/src/Algorand/Entry.h @@ -12,13 +12,13 @@ namespace TW::Algorand { /// Entry point for implementation of Algorand coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual bool supportsJSONSigning() const { return true; } - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool supportsJSONSigning() const { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; } // namespace TW::Algorand diff --git a/src/Binance/Entry.h b/src/Binance/Entry.h index 150dc15a6b8..da927b68166 100644 --- a/src/Binance/Entry.h +++ b/src/Binance/Entry.h @@ -12,18 +12,18 @@ namespace TW::Binance { /// Binance entry dispatcher. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual bool supportsJSONSigning() const { return true; } - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool supportsJSONSigning() const { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; - virtual Data preImageHashes(TWCoinType coin, const Data& txInputData) const; - virtual void compile(TWCoinType coin, const Data& txInputData, const std::vector& signatures, const std::vector& publicKeys, Data& dataOut) const; - virtual Data buildTransactionInput(TWCoinType coinType, const std::string& from, const std::string& to, const uint256_t& amount, const std::string& asset, const std::string& memo, const std::string& chainId) const; + Data preImageHashes(TWCoinType coin, const Data& txInputData) const; + void compile(TWCoinType coin, const Data& txInputData, const std::vector& signatures, const std::vector& publicKeys, Data& dataOut) const; + Data buildTransactionInput(TWCoinType coinType, const std::string& from, const std::string& to, const uint256_t& amount, const std::string& asset, const std::string& memo, const std::string& chainId) const; }; } // namespace TW::Binance diff --git a/src/Bitcoin/Entry.h b/src/Bitcoin/Entry.h index cdffd5e221d..713f97685d2 100644 --- a/src/Bitcoin/Entry.h +++ b/src/Bitcoin/Entry.h @@ -13,24 +13,24 @@ namespace TW::Bitcoin { /// Bitcoin entry dispatcher. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific /// includes in this file -class Entry : public CoinEntry { +class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, - const char* hrp) const final; - std::string normalizeAddress(TWCoinType coin, const std::string& address) const final; + const char* hrp) const; + std::string normalizeAddress(TWCoinType coin, const std::string& address) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, - const char* hrp) const final { + const char* hrp) const { return deriveAddress(coin, TWDerivationDefault, publicKey, p2pkh, hrp); } std::string deriveAddress(TWCoinType coin, TWDerivation derivation, const PublicKey& publicKey, - TW::byte p2pkh, const char* hrp) const final; + TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; - void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const final; - void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const final; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - Data preImageHashes(TWCoinType coin, const Data& txInputData) const final; + Data preImageHashes(TWCoinType coin, const Data& txInputData) const; void compile(TWCoinType coin, const Data& txInputData, const std::vector& signatures, - const std::vector& publicKeys, Data& dataOut) const final; + const std::vector& publicKeys, Data& dataOut) const; // Note: buildTransactionInput is not implemented for Binance chain with UTXOs }; diff --git a/src/Cardano/Entry.h b/src/Cardano/Entry.h index 10998d90b6c..94766b32303 100644 --- a/src/Cardano/Entry.h +++ b/src/Cardano/Entry.h @@ -12,13 +12,13 @@ namespace TW::Cardano { /// Entry point for implementation of Cardano coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Cardano diff --git a/src/Cosmos/Entry.h b/src/Cosmos/Entry.h index f31825ca167..e5be0796622 100644 --- a/src/Cosmos/Entry.h +++ b/src/Cosmos/Entry.h @@ -12,14 +12,14 @@ namespace TW::Cosmos { /// Entry point for implementation of Cosmos coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual bool supportsJSONSigning() const { return true; } - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const final; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const final; + Data addressToData(TWCoinType coin, const std::string& address) const final; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const override; + bool supportsJSONSigning() const final { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const override; }; } // namespace TW::Cosmos diff --git a/src/Decred/Entry.h b/src/Decred/Entry.h index a744a63021d..0d21789afa8 100644 --- a/src/Decred/Entry.h +++ b/src/Decred/Entry.h @@ -12,13 +12,13 @@ namespace TW::Decred { /// Decred entry dispatcher. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Decred diff --git a/src/EOS/Entry.h b/src/EOS/Entry.h index 586ec9526a3..63823c8c020 100644 --- a/src/EOS/Entry.h +++ b/src/EOS/Entry.h @@ -12,11 +12,11 @@ namespace TW::EOS { /// Entry point for implementation of EOS coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::EOS diff --git a/src/Elrond/Entry.h b/src/Elrond/Entry.h index 8723a972bcb..e0c4ed7b0a1 100644 --- a/src/Elrond/Entry.h +++ b/src/Elrond/Entry.h @@ -12,14 +12,14 @@ namespace TW::Elrond { /// Entry point for implementation of Elrond coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final: public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual bool supportsJSONSigning() const { return true; } - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool supportsJSONSigning() const { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; } // namespace TW::Elrond diff --git a/src/Ethereum/Entry.h b/src/Ethereum/Entry.h index 110a7ed1671..23a31b2c8d1 100644 --- a/src/Ethereum/Entry.h +++ b/src/Ethereum/Entry.h @@ -12,19 +12,19 @@ namespace TW::Ethereum { /// Entry point for Ethereum and Ethereum-fork coins. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string normalizeAddress(TWCoinType coin, const std::string& address) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual bool supportsJSONSigning() const { return true; } - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const final; + std::string normalizeAddress(TWCoinType coin, const std::string& address) const final; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const final; + Data addressToData(TWCoinType coin, const std::string& address) const final; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const override; + bool supportsJSONSigning() const final { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const final; - virtual Data preImageHashes(TWCoinType coin, const Data& txInputData) const; - virtual void compile(TWCoinType coin, const Data& txInputData, const std::vector& signatures, const std::vector& publicKeys, Data& dataOut) const; - virtual Data buildTransactionInput(TWCoinType coinType, const std::string& from, const std::string& to, const uint256_t& amount, const std::string& asset, const std::string& memo, const std::string& chainId) const; + Data preImageHashes(TWCoinType coin, const Data& txInputData) const final; + void compile(TWCoinType coin, const Data& txInputData, const std::vector& signatures, const std::vector& publicKeys, Data& dataOut) const final; + Data buildTransactionInput(TWCoinType coinType, const std::string& from, const std::string& to, const uint256_t& amount, const std::string& asset, const std::string& memo, const std::string& chainId) const final; }; } // namespace TW::Ethereum diff --git a/src/Everscale/Entry.h b/src/Everscale/Entry.h index 12daffaa0e9..c83a0d133ad 100644 --- a/src/Everscale/Entry.h +++ b/src/Everscale/Entry.h @@ -12,12 +12,12 @@ namespace TW::Everscale { /// Entry point for implementation of Everscale coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry : public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string normalizeAddress(TWCoinType coin, const std::string& address) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* d) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string normalizeAddress(TWCoinType coin, const std::string& address) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* d) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Everscale diff --git a/src/FIO/Entry.h b/src/FIO/Entry.h index 1d7abb7386b..cb9ab8c38a2 100644 --- a/src/FIO/Entry.h +++ b/src/FIO/Entry.h @@ -12,11 +12,11 @@ namespace TW::FIO { /// Entry point for implementation of FIO coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::FIO diff --git a/src/Filecoin/Entry.h b/src/Filecoin/Entry.h index de38cf654dd..a989db0676e 100644 --- a/src/Filecoin/Entry.h +++ b/src/Filecoin/Entry.h @@ -13,15 +13,15 @@ namespace TW::Filecoin { /// Entry point for implementation of Filecoin coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific /// includes in this file -class Entry : public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual bool supportsJSONSigning() const { return true; } - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool supportsJSONSigning() const { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; } // namespace TW::Filecoin diff --git a/src/Groestlcoin/Entry.h b/src/Groestlcoin/Entry.h index 96eb4d83a4e..069cc75074e 100644 --- a/src/Groestlcoin/Entry.h +++ b/src/Groestlcoin/Entry.h @@ -12,12 +12,12 @@ namespace TW::Groestlcoin { /// Groestlcoin entry dispatcher. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Groestlcoin diff --git a/src/Harmony/Entry.h b/src/Harmony/Entry.h index e39eaf82d84..1feefb3ca70 100644 --- a/src/Harmony/Entry.h +++ b/src/Harmony/Entry.h @@ -12,14 +12,14 @@ namespace TW::Harmony { /// Entry point for implementation of Harmony coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual bool supportsJSONSigning() const { return true; } - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool supportsJSONSigning() const { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; } // namespace TW::Harmony diff --git a/src/Icon/Entry.h b/src/Icon/Entry.h index 79ad0bd89f8..9547997f419 100644 --- a/src/Icon/Entry.h +++ b/src/Icon/Entry.h @@ -12,11 +12,11 @@ namespace TW::Icon { /// Entry point for implementation of ICON coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Icon diff --git a/src/IoTeX/Entry.h b/src/IoTeX/Entry.h index f5a5453fb7f..ecf04236fc7 100644 --- a/src/IoTeX/Entry.h +++ b/src/IoTeX/Entry.h @@ -12,11 +12,11 @@ namespace TW::IoTeX { /// Entry point for implementation of IoTeX coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::IoTeX diff --git a/src/Kusama/Entry.h b/src/Kusama/Entry.h index 9bdacd9be53..f9d566239a1 100644 --- a/src/Kusama/Entry.h +++ b/src/Kusama/Entry.h @@ -12,12 +12,12 @@ namespace TW::Kusama { /// Entry point for implementation of Kusama coin. See also Polkadot. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Kusama diff --git a/src/NEAR/Entry.h b/src/NEAR/Entry.h index b54a934db47..20a0870762c 100644 --- a/src/NEAR/Entry.h +++ b/src/NEAR/Entry.h @@ -12,13 +12,13 @@ namespace TW::NEAR { /// Entry point for implementation of NEAR coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string normalizeAddress(TWCoinType coin, const std::string& address) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string normalizeAddress(TWCoinType coin, const std::string& address) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::NEAR diff --git a/src/NEO/Entry.h b/src/NEO/Entry.h index d6e1b12e607..6a396f753c2 100644 --- a/src/NEO/Entry.h +++ b/src/NEO/Entry.h @@ -12,13 +12,13 @@ namespace TW::NEO { /// NEO entry dispatcher. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::NEO diff --git a/src/NULS/Entry.h b/src/NULS/Entry.h index ef0b9e61ccc..b11bcc629bb 100644 --- a/src/NULS/Entry.h +++ b/src/NULS/Entry.h @@ -12,11 +12,11 @@ namespace TW::NULS { /// Entry point for implementation of NULS coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::NULS diff --git a/src/Nano/Entry.h b/src/Nano/Entry.h index d81621a0209..1a27f029e23 100644 --- a/src/Nano/Entry.h +++ b/src/Nano/Entry.h @@ -12,14 +12,14 @@ namespace TW::Nano { /// Entry point for implementation of Nano coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual bool supportsJSONSigning() const { return true; } - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool supportsJSONSigning() const { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; } // namespace TW::Nano diff --git a/src/Nebulas/Entry.h b/src/Nebulas/Entry.h index ac3aeece572..0bdcaded71c 100644 --- a/src/Nebulas/Entry.h +++ b/src/Nebulas/Entry.h @@ -12,11 +12,11 @@ namespace TW::Nebulas { /// Entry point for implementation of Nebulas coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Nebulas diff --git a/src/Nervos/Entry.h b/src/Nervos/Entry.h index a7ea1a5376a..0d3919dcefb 100644 --- a/src/Nervos/Entry.h +++ b/src/Nervos/Entry.h @@ -15,14 +15,14 @@ namespace TW::Nervos { /// Entry point for implementation of Nervos coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific /// includes in this file -class Entry : public CoinEntry { +class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, byte p2pkh, byte p2sh, - const char* hrp) const final; + const char* hrp) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, byte p2pkh, - const char* hrp) const final; - void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const final; - void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const final; + const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Nervos diff --git a/src/Nimiq/Entry.h b/src/Nimiq/Entry.h index 60e184573d1..cad09e0fc65 100644 --- a/src/Nimiq/Entry.h +++ b/src/Nimiq/Entry.h @@ -12,11 +12,11 @@ namespace TW::Nimiq { /// Entry point for implementation of Nimiq coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Nimiq diff --git a/src/Oasis/Entry.h b/src/Oasis/Entry.h index d2d765d7fba..c4b3fb6240f 100644 --- a/src/Oasis/Entry.h +++ b/src/Oasis/Entry.h @@ -12,11 +12,11 @@ namespace TW::Oasis { /// Entry point for implementation of Oasis coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Oasis diff --git a/src/Ontology/Entry.h b/src/Ontology/Entry.h index db8ae468192..68df17b8baf 100644 --- a/src/Ontology/Entry.h +++ b/src/Ontology/Entry.h @@ -12,11 +12,11 @@ namespace TW::Ontology { /// Entry point for implementation of Ontology coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Ontology diff --git a/src/Polkadot/Entry.h b/src/Polkadot/Entry.h index fff44b3798d..d36ac8845af 100644 --- a/src/Polkadot/Entry.h +++ b/src/Polkadot/Entry.h @@ -12,12 +12,12 @@ namespace TW::Polkadot { /// Entry point for implementation of Polkadot coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Polkadot diff --git a/src/Ripple/Entry.h b/src/Ripple/Entry.h index 445f108d3f9..6736133286e 100644 --- a/src/Ripple/Entry.h +++ b/src/Ripple/Entry.h @@ -12,11 +12,11 @@ namespace TW::Ripple { /// Entry point for implementation of Ripple (XRP) coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Ripple diff --git a/src/Ronin/Entry.h b/src/Ronin/Entry.h index 83488df897f..9bb7f96aa40 100644 --- a/src/Ronin/Entry.h +++ b/src/Ronin/Entry.h @@ -11,15 +11,15 @@ namespace TW::Ronin { /// Entry point for Ronin (EVM side chain) -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string normalizeAddress(TWCoinType coin, const std::string& address) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual bool supportsJSONSigning() const { return true; } - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string normalizeAddress(TWCoinType coin, const std::string& address) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool supportsJSONSigning() const { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; } // namespace TW::Ronin diff --git a/src/Solana/Entry.h b/src/Solana/Entry.h index 745e2f67f6b..b6bc8b4f1d4 100644 --- a/src/Solana/Entry.h +++ b/src/Solana/Entry.h @@ -12,14 +12,14 @@ namespace TW::Solana { /// Entry point for implementation of Solana coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual bool supportsJSONSigning() const { return true; } - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool supportsJSONSigning() const { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; } // namespace TW::Solana diff --git a/src/Stellar/Entry.h b/src/Stellar/Entry.h index 0d7aa434950..f4236c325df 100644 --- a/src/Stellar/Entry.h +++ b/src/Stellar/Entry.h @@ -12,11 +12,11 @@ namespace TW::Stellar { /// Entry point for implementation of Stellar coin, and Kin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Stellar diff --git a/src/THORChain/Entry.h b/src/THORChain/Entry.h index c5a2d8ea776..a5650e5b94a 100644 --- a/src/THORChain/Entry.h +++ b/src/THORChain/Entry.h @@ -13,10 +13,10 @@ namespace TW::THORChain { /// Entry point for implementation of THORChain coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public Cosmos::Entry { +class Entry final : public Cosmos::Entry { public: - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; } // namespace TW::THORChain diff --git a/src/Tezos/Entry.h b/src/Tezos/Entry.h index 96bca2e2144..bea87ca0aa3 100644 --- a/src/Tezos/Entry.h +++ b/src/Tezos/Entry.h @@ -12,13 +12,13 @@ namespace TW::Tezos { /// Entry point for implementation of Tezos coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual bool supportsJSONSigning() const { return true; } - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool supportsJSONSigning() const { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; } // namespace TW::Tezos diff --git a/src/Theta/Entry.h b/src/Theta/Entry.h index a75766f0fc0..429190dee81 100644 --- a/src/Theta/Entry.h +++ b/src/Theta/Entry.h @@ -13,9 +13,9 @@ namespace TW::Theta { /// Entry point for Theta. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public Ethereum::Entry { +class Entry final : public Ethereum::Entry { public: - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Theta diff --git a/src/Tron/Entry.h b/src/Tron/Entry.h index 96dfa6a5c9f..0d25c65da8b 100644 --- a/src/Tron/Entry.h +++ b/src/Tron/Entry.h @@ -12,11 +12,11 @@ namespace TW::Tron { /// Entry point for implementation of Tron coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Tron diff --git a/src/VeChain/Entry.h b/src/VeChain/Entry.h index 0320bb90f19..48ec8b5db78 100644 --- a/src/VeChain/Entry.h +++ b/src/VeChain/Entry.h @@ -13,9 +13,9 @@ namespace TW::VeChain { /// Entry point for VeChain. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public Ethereum::Entry { +class Entry final : public Ethereum::Entry { public: - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::VeChain diff --git a/src/Waves/Entry.h b/src/Waves/Entry.h index 344e4971e20..ea114e04c45 100644 --- a/src/Waves/Entry.h +++ b/src/Waves/Entry.h @@ -12,11 +12,11 @@ namespace TW::Waves { /// Entry point for implementation of Waves coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Waves diff --git a/src/Zcash/Entry.h b/src/Zcash/Entry.h index 54a5f652aad..626f8105131 100644 --- a/src/Zcash/Entry.h +++ b/src/Zcash/Entry.h @@ -12,13 +12,13 @@ namespace TW::Zcash { /// Zcash entry dispatcher. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Zcash diff --git a/src/Zilliqa/Entry.h b/src/Zilliqa/Entry.h index 69747dfc8f8..fa1335f5838 100644 --- a/src/Zilliqa/Entry.h +++ b/src/Zilliqa/Entry.h @@ -12,14 +12,14 @@ namespace TW::Zilliqa { /// Entry point for implementation of Zilliqa coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry: public CoinEntry { +class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual Data addressToData(TWCoinType coin, const std::string& address) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - virtual bool supportsJSONSigning() const { return true; } - virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool supportsJSONSigning() const { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; } // namespace TW::Zilliqa From 551ad7466d78d6ff2ba8c0594e29902e25dcd5e3 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Tue, 20 Sep 2022 04:22:24 +0200 Subject: [PATCH 082/497] Add Devconsole.ts, typescript based utility console (#2572) * Devconsole.ts: a typescript interactive dev console * Move it under typescript * Add warning * Update README, desc, sample * Add building to sample app CI, some more namespaces * Enable unity build (for lib) for sample app * Update running command * Fix newlines in running command * Fix newlines for bash too * Add simple running test * Use test in CI * Build, run and test * Devconsole.ts: Expose all WC namespaces * Example with protobuf usage, examples --- .github/workflows/linux-sampleapp-ci.yml | 11 +- samples/typescript/devconsole.ts/.gitignore | 3 + samples/typescript/devconsole.ts/README.md | 34 + .../devconsole.ts/package-lock.json | 1491 +++++++++++++++++ samples/typescript/devconsole.ts/package.json | 28 + .../samplescripts/privkeysign.sampleinput.txt | 12 + .../samplescripts/protoeth.sampleinput.txt | 26 + .../solanaaddress.sampleinput.txt | 13 + samples/typescript/devconsole.ts/src/index.ts | 207 +++ .../test/data/privpubkey.testinput.txt | 26 + .../typescript/devconsole.ts/tsconfig.json | 20 + 11 files changed, 1869 insertions(+), 2 deletions(-) create mode 100644 samples/typescript/devconsole.ts/.gitignore create mode 100644 samples/typescript/devconsole.ts/README.md create mode 100644 samples/typescript/devconsole.ts/package-lock.json create mode 100644 samples/typescript/devconsole.ts/package.json create mode 100644 samples/typescript/devconsole.ts/samplescripts/privkeysign.sampleinput.txt create mode 100644 samples/typescript/devconsole.ts/samplescripts/protoeth.sampleinput.txt create mode 100644 samples/typescript/devconsole.ts/samplescripts/solanaaddress.sampleinput.txt create mode 100644 samples/typescript/devconsole.ts/src/index.ts create mode 100644 samples/typescript/devconsole.ts/test/data/privpubkey.testinput.txt create mode 100644 samples/typescript/devconsole.ts/tsconfig.json diff --git a/.github/workflows/linux-sampleapp-ci.yml b/.github/workflows/linux-sampleapp-ci.yml index a5654b096a7..acedbeeb32b 100644 --- a/.github/workflows/linux-sampleapp-ci.yml +++ b/.github/workflows/linux-sampleapp-ci.yml @@ -1,4 +1,4 @@ -name: Linux SampleApp CI +name: Linux SampleApps CI on: push: @@ -35,7 +35,7 @@ jobs: CXX: /usr/bin/clang++ - name: CMake run: | - cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug + cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DTW_UNITY_BUILD=ON env: CC: /usr/bin/clang CXX: /usr/bin/clang++ @@ -55,6 +55,13 @@ jobs: env: CC: /usr/bin/clang CXX: /usr/bin/clang++ + - name: Build, run, and test devconsole.ts + run: | + cd samples/typescript/devconsole.ts + npm install + npm run build + echo -e "help() \n .exit" | npm run start + npm run test - name: Install Go env: GO_VERSION: 1.16.12 diff --git a/samples/typescript/devconsole.ts/.gitignore b/samples/typescript/devconsole.ts/.gitignore new file mode 100644 index 00000000000..83dbaee65a8 --- /dev/null +++ b/samples/typescript/devconsole.ts/.gitignore @@ -0,0 +1,3 @@ +node_modules +lib + diff --git a/samples/typescript/devconsole.ts/README.md b/samples/typescript/devconsole.ts/README.md new file mode 100644 index 00000000000..40ed8e5045d --- /dev/null +++ b/samples/typescript/devconsole.ts/README.md @@ -0,0 +1,34 @@ +# Devconsole.ts + +`Devconsole.ts` is a command-line utility to quickly work with `wallet-core` library. +It is based on `node` `typescript` console, and uses the WASM version of `wallet-core`. + +Type `help()` after starting it. + +Some wallet-core namespaces are exposed, and methods can be called directly. + +Note that auto-completion works in the console. + +## Build: + +``` +cd samples/typescript/devconsole.ts +npm install +npm run build +npm run start +``` + +## Sample usage: + +``` +> help() +This is an interactive typescript shell, to work with wallet-core (wasm) +You can use: +... +> w1 = HDWallet.create(256, '') +W {} +> w1.mnemonic() +'round profit immense ... sniff' +> w1.getAddressForCoin(CoinType.cosmos) +'cosmos1kgd25tvkz3jtuee4cl796trc2s0hjsfgqmhmku' +``` diff --git a/samples/typescript/devconsole.ts/package-lock.json b/samples/typescript/devconsole.ts/package-lock.json new file mode 100644 index 00000000000..81fe3f8df9d --- /dev/null +++ b/samples/typescript/devconsole.ts/package-lock.json @@ -0,0 +1,1491 @@ +{ + "name": "cli-wasm", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "cli-wasm", + "version": "0.0.1", + "license": "ISC", + "dependencies": { + "@trustwallet/wallet-core": "3.0.1", + "chalk": "^4.1.2", + "clear": "^0.1.0", + "figlet": "^1.5.2", + "inquirer": "^8.2.4" + }, + "bin": { + "cli": "index.js" + }, + "devDependencies": { + "@types/node": "^18.7.15", + "ts-node": "^10.9.1", + "typescript": "^4.8.2" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@trustwallet/wallet-core": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.1.tgz", + "integrity": "sha512-WrZwWO85ja4SKyCftJQqj/XWqcLmrP6qJ42YuU9FSzdJp68IdOICckGj5INaW0DE+3O85bPNO+zTmBTBKRZr7g==", + "dependencies": { + "protobufjs": ">=6.11.3" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.7.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz", + "integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==" + }, + "node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "node_modules/clear": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/clear/-/clear-0.1.0.tgz", + "integrity": "sha512-qMjRnoL+JDPJHeLePZJuao6+8orzHMGP04A8CdwCNsKhRbOnKRjefxONR7bwILT3MHecxKBjHkKL/tkZ8r4Uzw==", + "engines": { + "node": "*" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/figlet": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.2.tgz", + "integrity": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/long": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz", + "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==" + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protobufjs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.0.tgz", + "integrity": "sha512-rCuxKlh0UQKSMjrpIcTLbR5TtGQ52cgs1a5nUoPBAKOccdPblN67BJtjrbtudUJK6HmBvUdsmymyYOzO7lxZEA==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/rxjs": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz", + "integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", + "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + } + }, + "dependencies": { + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "@trustwallet/wallet-core": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.1.tgz", + "integrity": "sha512-WrZwWO85ja4SKyCftJQqj/XWqcLmrP6qJ42YuU9FSzdJp68IdOICckGj5INaW0DE+3O85bPNO+zTmBTBKRZr7g==", + "requires": { + "protobufjs": ">=6.11.3" + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "@types/node": { + "version": "18.7.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz", + "integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==" + }, + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + } + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "clear": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/clear/-/clear-0.1.0.tgz", + "integrity": "sha512-qMjRnoL+JDPJHeLePZJuao6+8orzHMGP04A8CdwCNsKhRbOnKRjefxONR7bwILT3MHecxKBjHkKL/tkZ8r4Uzw==" + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==" + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", + "requires": { + "clone": "^1.0.2" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "figlet": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.2.tgz", + "integrity": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==" + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "long": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz", + "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==" + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" + }, + "protobufjs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.0.tgz", + "integrity": "sha512-rCuxKlh0UQKSMjrpIcTLbR5TtGQ52cgs1a5nUoPBAKOccdPblN67BJtjrbtudUJK6HmBvUdsmymyYOzO7lxZEA==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + }, + "rxjs": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz", + "integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==", + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + }, + "typescript": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", + "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "requires": { + "defaults": "^1.0.3" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } +} diff --git a/samples/typescript/devconsole.ts/package.json b/samples/typescript/devconsole.ts/package.json new file mode 100644 index 00000000000..fcb97e2ed30 --- /dev/null +++ b/samples/typescript/devconsole.ts/package.json @@ -0,0 +1,28 @@ +{ + "name": "cli-wasm", + "version": "0.0.1", + "description": "CLI utility for Wallet Core, through WASM", + "main": "index.js", + "bin": { + "cli": "index.js" + }, + "scripts": { + "start": "ts-node src/index.ts", + "build": "tsc -p .", + "test": "cat test/data/privpubkey.testinput.txt | ts-node src/index.ts" + }, + "author": "Trust Wallet", + "license": "ISC", + "dependencies": { + "@trustwallet/wallet-core": "3.0.1", + "chalk": "^4.1.2", + "clear": "^0.1.0", + "figlet": "^1.5.2", + "inquirer": "^8.2.4" + }, + "devDependencies": { + "@types/node": "^18.7.15", + "ts-node": "^10.9.1", + "typescript": "^4.8.2" + } +} diff --git a/samples/typescript/devconsole.ts/samplescripts/privkeysign.sampleinput.txt b/samples/typescript/devconsole.ts/samplescripts/privkeysign.sampleinput.txt new file mode 100644 index 00000000000..05a6b7a776f --- /dev/null +++ b/samples/typescript/devconsole.ts/samplescripts/privkeysign.sampleinput.txt @@ -0,0 +1,12 @@ +// Create a private key, sign a message, derive public key from private key, verify signature + +privKeyData = '0xafeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5' +messageDigest = '0001020304050607080910111213141519171819202122232425262728293031' + +privkey = PrivateKey.createWithData(HexCoding.decode(privKeyData)); HexCoding.encode(privkey.data()) + +sig1 = privkey.sign(HexCoding.decode(messageDigest), Curve.secp256k1); HexCoding.encode(sig1) + +pubkey = privkey.getPublicKeySecp256k1(true); HexCoding.encode(pubkey.data()) + +verifyRes = pubkey.verify(sig1, HexCoding.decode(messageDigest)) diff --git a/samples/typescript/devconsole.ts/samplescripts/protoeth.sampleinput.txt b/samples/typescript/devconsole.ts/samplescripts/protoeth.sampleinput.txt new file mode 100644 index 00000000000..422d16881d4 --- /dev/null +++ b/samples/typescript/devconsole.ts/samplescripts/protoeth.sampleinput.txt @@ -0,0 +1,26 @@ +// test signing eip1559 erc20 transfer tx + +input = TW.Ethereum.Proto.SigningInput.create({ + toAddress: "0x6b175474e89094c44da98b954eedeac495271d0f", + chainId: Buffer.from("01", "hex"), + nonce: Buffer.from("00", "hex"), + txMode: TW.Ethereum.Proto.TransactionMode.Enveloped, + maxInclusionFeePerGas: Buffer.from("0077359400", "hex"), + maxFeePerGas: Buffer.from("00b2d05e00", "hex"), + gasLimit: Buffer.from("0130B9", "hex"), + transaction: TW.Ethereum.Proto.Transaction.create({ + erc20Transfer: TW.Ethereum.Proto.Transaction.ERC20Transfer.create({ + to: "0x5322b34c88ed0691971bf52a7047448f0f4efc84", + amount: Buffer.from("1bc16d674ec80000", "hex"), + }), + }), + privateKey: HexCoding.decode( + "0x608dcb1742bb3fb7aec002074e3420e4fab7d00cced79ccdac53ed5b27138151" + ), + }); + +encoded = TW.Ethereum.Proto.SigningInput.encode(input).finish(); HexCoding.encode(encoded) + +outputData = AnySigner.sign(encoded, CoinType.ethereum); HexCoding.encode(outputData) + +output = TW.Ethereum.Proto.SigningOutput.decode(outputData); HexCoding.encode(output.encoded) diff --git a/samples/typescript/devconsole.ts/samplescripts/solanaaddress.sampleinput.txt b/samples/typescript/devconsole.ts/samplescripts/solanaaddress.sampleinput.txt new file mode 100644 index 00000000000..c2796a598b8 --- /dev/null +++ b/samples/typescript/devconsole.ts/samplescripts/solanaaddress.sampleinput.txt @@ -0,0 +1,13 @@ +// Derive a Solana address directly and through privKey-pubKey + +coin = CoinType.solana + +wallet = HDWallet.createWithMnemonic('ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal', '') + +address = wallet.getAddressForCoin(coin) + +pk = wallet.getKeyForCoin(coin); HexCoding.encode(pk.data()) +pubkey = pk.getPublicKeyEd25519(); HexCoding.encode(pubkey.data()) +a1 = AnyAddress.createWithPublicKey(pubkey, coin); a1.description() + +address === a1.description() diff --git a/samples/typescript/devconsole.ts/src/index.ts b/samples/typescript/devconsole.ts/src/index.ts new file mode 100644 index 00000000000..636607edc17 --- /dev/null +++ b/samples/typescript/devconsole.ts/src/index.ts @@ -0,0 +1,207 @@ +#!/usr/bin/env node + +const chalk = require('chalk'); +const clear = require('clear'); +const figlet = require('figlet'); +const repl = require('node:repl'); +//const inquirer = require('inquirer'); +const { initWasm, TW } = require("@trustwallet/wallet-core"); + +function enumerateNamespaces(topLevelNamespace: any) { + const exceptions: string[] = ['AsciiToString', 'ExitStatus', 'ENV', 'ERRNO_CODES', 'ERRNO_MESSAGES', 'DNS', 'Protocols', 'Sockets', 'UNWIND_CACHE', 'PATH', 'PATH_FS', 'SYSCALLS', 'JSEvents', 'JSEvents_requestFullscreen', 'JSEvents_resizeCanvasForFullscreen', 'ExceptionInfo', 'Browser', 'FS', 'MEMFS', 'TTY', 'PIPEFS', 'SOCKFS', 'RegisteredClass', 'Emval']; + var ns : string[] = []; + for (var member in topLevelNamespace) { + if (typeof topLevelNamespace[member] == 'function' || typeof topLevelNamespace[member] == 'object') { + ns.push(member); + } + } + return ns + .filter(n => { var firstLetter = n[0]; return (firstLetter >= 'A' && firstLetter <= 'Z'); }) + .filter(n => !n.includes('Error')) + .filter(n => !n.startsWith('HEAP')) + .filter(n => !n.startsWith('UTF')) + .filter(n => !n.startsWith('FS_')) + .filter(n => !n.startsWith('ClassHandle')) + .filter(n => !n.startsWith('RegisteredPointer')) + .filter(n => !exceptions.includes(n)); +} + +(async function () { + class AddressCoin { + coin: any; + address: string; + constructor(coin: string, address: string) { + this.coin = coin; + this.address = address; + } + }; + + class TestWallet { + name: string; + wallet: any; + addresses: AddressCoin[]; + + constructor(name: string = '', wallet: any) { + this.name = name; + this.wallet = wallet; + this.addresses = []; + this.addDefaultCoins(); + } + public static createRandom(name: string = '', strength: number = 256): TestWallet { + let wallet = WC.HDWallet.create(strength, ''); + return new TestWallet(name, wallet); + } + public static createWithMnemonic(name: string = '', mnemonic: string): TestWallet { + let wallet = WC.HDWallet.createWithMnemonic(mnemonic, ''); + return new TestWallet(name, wallet); + } + addCoin(coin: string): void { + const address = this.wallet.getAddressForCoin(coin); + this.addresses.push(new AddressCoin(coin, address)); + } + addDefaultCoins(): void { + this.addCoin(WC.CoinType.bitcoin); + this.addCoin(WC.CoinType.ethereum); + this.addCoin(WC.CoinType.binance); + } + status(): string { + return `Wallet '${this.name}', with ${this.addresses.length} addresses`; + } + dump(): void { + console.error(`Wallet ${this.name}:`); + + if (this.addresses.length == 0) { + console.log('No addresses'); + } else { + console.log('Addresses:'); + this.addresses.forEach(element => { + console.log(` ${WC.CoinTypeConfiguration.getSymbol(element.coin)}: ${element.address}`); + }); + } + } + }; + + function help(): void { + console.log('This is an interactive typescript shell, to work with wallet-core (wasm)'); + console.log('You can use:'); + console.log(); + console.log("- Any typescript commands EXAMPLES"); + console.log(" 'wallet-core'.length"); + console.log(" x = 5; ++x"); + console.log(); + console.log('- Any method from Wallet-Core, through various namespaces, see full list below. Some examples:'); + console.log(" CoinType CoinType.bitcoin.value"); + console.log(" HDWallet wallet = HDWallet.create(256, ''); wallet.mnemonic()"); + console.log(" PrivateKey pk = PrivateKey.createWithData(HexCoding.decode('afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5'))"); + console.log(" PublicKey pubkey = PublicKey.createWithData(HexCoding.decode('0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1'), PublicKeyType.secp256k1)"); + console.log(" AnyAddress AnyAddress.createWithString('EQCTVra3xPXenA1wNFMba2taTsc9XMdfCWC7FJpGXjk7', CoinType.solana).description()"); + console.log(" CoinTypeConfiguration CoinTypeConfiguration.getSymbol(CoinType.bitcoin)"); + console.log(" Mnemonmic Mnemonic.isValidWord('acid')"); + console.log(" HexCoding HexCoding.encode(HexCoding.decode('01ab02'))"); + console.log(); + console.log("- Convenience methods:"); + console.log(" walletCreate([strength], [name]) walletCreate(128)"); + console.log(" walletImport(mnemonic, [name]) walletImport('ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal', 'Test1')"); + console.log(" walletDump() walletDump()"); + console.log(); + console.log("See examples in samplescripts folder, e.g.: cat samplescripts/protoeth.sampleinput.txt | npm run start"); + console.log(); + console.log("A longer example:"); + console.log(" coin = CoinType.solana"); + console.log(" wallet = HDWallet.createWithMnemonic('ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal', '')"); + console.log(" wallet.getAddressForCoin(coin)"); + console.log(" pk = wallet.getKeyForCoin(coin)"); + console.log(" HexCoding.encode(pk.data())"); + console.log(" pubkey = pk.getPublicKeyEd25519()"); + console.log(" HexCoding.encode(pubkey.data())"); + console.log(" a1 = AnyAddress.createWithPublicKey(pubkey, coin)"); + console.log(" a1.description()"); + console.log(); + console.log("Full list of exposed Wallet-core namespaces:"); + console.log(enumerateNamespaces(WC).sort().join(', ')); + console.log(enumerateNamespaces(TW).sort().map(n => 'TW.' + n).join(', ')); + console.log(); + } + + function exit(code: number): void { + process.exit(code); + } + + function walletCreate(strength: number = 256, name: string = ''): any { + wallet = TestWallet.createRandom(name, strength); + console.log(`Wallet ${wallet.name} created, mnemonic: ${wallet.wallet.mnemonic()}`); + walletStatus(); + return wallet; + } + + function walletImport(mnemonic: string, name: string = ''): any { + if (!WC.Mnemonic.isValid(mnemonic)) { + console.error(`Mnemonic is not valid ${mnemonic}`); + return null; + } + wallet = TestWallet.createWithMnemonic(name, mnemonic); + console.log(`Wallet ${wallet.name} imported, mnemonic: ${wallet.wallet.mnemonic()}`); + walletStatus(); + return wallet; + } + + function walletStatus(): void { + if (wallet === null) { + console.error('No wallet, see createWallet()'); + } else { + console.error(`Wallet loaded: ${wallet.status()}`); + } + } + + function walletDump(): void { + walletStatus(); + if (wallet) { + wallet.dump(); + } + } + + // single global TestWallet instance + let wallet: TestWallet | null = null; + + clear(); + console.log( + chalk.blue( + figlet.textSync('wallet-core', { horizontalLayout: 'full' }) + ) + ); + console.log(chalk.blue(' devconsole.ts, wasm lib')); + console.log(); + + process.stdout.write("Initializing WalletCore library ..."); + const WC = await initWasm(); + console.log(` done.`); + console.log(); + console.log(`Type 'help()' for help`); + console.log(`Press Ctrl-C twice to exit`); + console.log(chalk.red(`This is a test tool, DO NOT USE WITH REAL FUNDS!`)); + console.log(); + + const local = repl.start('> '); + + // Expose WC namespaces, as top-level + var nss = enumerateNamespaces(WC); + nss.forEach(ns => local.context[ns] = WC[ns]); + // also all under WC + local.context.WC = WC; + // Expose TW namespaces (under TW) + local.context.TW = TW; + + // Expose more stuff; utilities + local.context.help = help; + local.context.exit = exit; + local.context.walletCreate = walletCreate; + local.context.walletImport = walletImport; + local.context.walletDump = walletDump; + local.context.wallet = wallet; + local.context.coin = WC.CoinType.bitcoin; + + local.on('exit', () => { + console.log('Bye!'); + process.exit(); + }); +})(); diff --git a/samples/typescript/devconsole.ts/test/data/privpubkey.testinput.txt b/samples/typescript/devconsole.ts/test/data/privpubkey.testinput.txt new file mode 100644 index 00000000000..8431062b58b --- /dev/null +++ b/samples/typescript/devconsole.ts/test/data/privpubkey.testinput.txt @@ -0,0 +1,26 @@ +// Create a private key, sign a message, derive public key from private key, verify signature +privKeyData = '0xafeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5' +pubKeyData = '0x0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1' +messageDigest = '0001020304050607080910111213141519171819202122232425262728293031' +signature = '0x673b54a91d87cfb9389e54cc55b1a9343a6eb9f2ea1f449cb19a248a86bb904c1efb109f8cf655c4f510211053c1696e52c75843c5c803fa1b78fe0c263f468201' + +testAssert = function(expression, text) { + if (!expression) { console.log('ERROR: ', text); exit(1); } + return 'ok: ' + text; +} + +privkey = PrivateKey.createWithData(HexCoding.decode(privKeyData)) +HexCoding.encode(privkey.data()) +testAssert(HexCoding.encode(privkey.data()) == privKeyData, 'private key match') + +HexCoding.encode(sig1 = privkey.sign(HexCoding.decode(messageDigest), Curve.secp256k1)) +testAssert(HexCoding.encode(sig1) == signature, 'signature match') + +pubkey = privkey.getPublicKeySecp256k1(true) +HexCoding.encode(pubkey.data()) +testAssert(HexCoding.encode(pubkey.data()) == pubKeyData, 'pubkey match') + +verifyRes = pubkey.verify(sig1, HexCoding.decode(messageDigest)) +testAssert(verifyRes, 'signature verification') + +exit(0) diff --git a/samples/typescript/devconsole.ts/tsconfig.json b/samples/typescript/devconsole.ts/tsconfig.json new file mode 100644 index 00000000000..70198268800 --- /dev/null +++ b/samples/typescript/devconsole.ts/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "lib": [ + "es6", + "es2015", + "dom" + ], + "declaration": true, + "outDir": "lib", + "rootDir": "src", + "strict": true, + "types": [ + "node" + ], + "esModuleInterop": true, + "resolveJsonModule": true + } +} \ No newline at end of file From efc3b15622868db60b742be81bc0ea8b2ccba6ca Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 20 Sep 2022 22:18:59 +0900 Subject: [PATCH 083/497] add keystore and fs usage (#2580) --- samples/node/{index.js => index.ts} | 29 ++- samples/node/package-lock.json | 357 ++++++++++++++++++++++++++-- samples/node/package.json | 14 +- samples/node/tsconfig.json | 23 ++ 4 files changed, 396 insertions(+), 27 deletions(-) rename samples/node/{index.js => index.ts} (51%) create mode 100644 samples/node/tsconfig.json diff --git a/samples/node/index.js b/samples/node/index.ts similarity index 51% rename from samples/node/index.js rename to samples/node/index.ts index dde4541ff59..450a4bdaaa3 100755 --- a/samples/node/index.js +++ b/samples/node/index.ts @@ -1,26 +1,39 @@ -#!/usr/bin/env node +#!/usr/bin/env ts-node -const { initWasm, TW } = require("@trustwallet/wallet-core"); +const { initWasm, TW, KeyStore } = require("@trustwallet/wallet-core"); -(async function () { +async function main() { const start = new Date().getTime(); console.log(`Initializing Wasm...`); - const { CoinType, HexCoding, HDWallet, AnyAddress } = await initWasm(); + const core = await initWasm(); + const { CoinType, HexCoding, HDWallet, AnyAddress } = core; console.log(`Done in ${new Date().getTime() - start} ms`); - + const wallet = HDWallet.create(256, ""); + const mnemonic = wallet.mnemonic(); const key = wallet.getKeyForCoin(CoinType.ethereum); const pubKey = key.getPublicKeySecp256k1(false); const address = AnyAddress.createWithPublicKey(pubKey, CoinType.ethereum); - - console.log(`Create wallet: ${wallet.mnemonic()}`); + const storage = new KeyStore.FileSystemStorage("/tmp"); + const keystore = new KeyStore.Default(core, storage); + + const storedWallet = await keystore.import(mnemonic, "Coolw", "password", [ + CoinType.ethereum, + ]); + + console.log(`Create wallet: ${mnemonic}`); console.log(`Get Ethereum public key: ${HexCoding.encode(pubKey.data())}`); console.log(`Get Ethereum address: ${address.description()}`); console.log(`CoinType.ethereum.value = ${CoinType.ethereum.value}`); console.log("Ethereum protobuf models: \n", TW.Ethereum); + console.log("Keystore JSON: \n", JSON.stringify(storedWallet, null, 2)); + + await keystore.delete(storedWallet.id, "password"); wallet.delete(); key.delete(); pubKey.delete(); address.delete(); -})(); +} + +main(); diff --git a/samples/node/package-lock.json b/samples/node/package-lock.json index 54e7d733d5e..e0a6b4d8d20 100644 --- a/samples/node/package-lock.json +++ b/samples/node/package-lock.json @@ -7,9 +7,51 @@ "": { "name": "node-sample", "version": "1.0.0", - "license": "ISC", + "license": "MIT", "dependencies": { - "@trustwallet/wallet-core": "3.0.1" + "@trustwallet/wallet-core": "3.0.4" + }, + "devDependencies": { + "@types/node": "^10.9.1", + "ts-node": "^10.9.1", + "typescript": "^4.8.3" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/@protobufjs/aspromise": { @@ -67,28 +109,101 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@trustwallet/wallet-core": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.1.tgz", - "integrity": "sha512-WrZwWO85ja4SKyCftJQqj/XWqcLmrP6qJ42YuU9FSzdJp68IdOICckGj5INaW0DE+3O85bPNO+zTmBTBKRZr7g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.4.tgz", + "integrity": "sha512-FrIVEwRmUYFuwU9IoXg0J8fngeW7nlJZZAsrnOWba2g/yGWZl4FQ4z87MEQ5ROOGW9jJzsdWG4PRZffvYzhqsg==", "dependencies": { "protobufjs": ">=6.11.3" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, "node_modules/@types/long": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, "node_modules/@types/node": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", - "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==" + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } }, "node_modules/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/protobufjs": { "version": "6.11.3", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", @@ -113,9 +228,116 @@ "pbjs": "bin/pbjs", "pbts": "bin/pbts" } + }, + "node_modules/protobufjs/node_modules/@types/node": { + "version": "18.7.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", + "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==" + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } } }, "dependencies": { + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -171,28 +393,89 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "@trustwallet/wallet-core": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.1.tgz", - "integrity": "sha512-WrZwWO85ja4SKyCftJQqj/XWqcLmrP6qJ42YuU9FSzdJp68IdOICckGj5INaW0DE+3O85bPNO+zTmBTBKRZr7g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.4.tgz", + "integrity": "sha512-FrIVEwRmUYFuwU9IoXg0J8fngeW7nlJZZAsrnOWba2g/yGWZl4FQ4z87MEQ5ROOGW9jJzsdWG4PRZffvYzhqsg==", "requires": { "protobufjs": ">=6.11.3" } }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, "@types/long": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, "@types/node": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", - "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==" + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + }, + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true }, "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "protobufjs": { "version": "6.11.3", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", @@ -211,7 +494,53 @@ "@types/long": "^4.0.1", "@types/node": ">=13.7.0", "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "18.7.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", + "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==" + } + } + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" } + }, + "typescript": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", + "dev": true + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } diff --git a/samples/node/package.json b/samples/node/package.json index f0578390b78..c194836a001 100644 --- a/samples/node/package.json +++ b/samples/node/package.json @@ -2,14 +2,18 @@ "name": "node-sample", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "index.ts", "scripts": { - "start": "node index.js", - "test": "echo \"Error: no test specified\" && exit 1" + "start": "ts-node index.ts" }, "author": "", - "license": "ISC", + "license": "MIT", "dependencies": { - "@trustwallet/wallet-core": "3.0.1" + "@trustwallet/wallet-core": "3.0.4" + }, + "devDependencies": { + "@types/node": "^10.9.1", + "ts-node": "^10.9.1", + "typescript": "^4.8.3" } } diff --git a/samples/node/tsconfig.json b/samples/node/tsconfig.json new file mode 100644 index 00000000000..d1395c05628 --- /dev/null +++ b/samples/node/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "es2017", + "lib": [ + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "exclude": [ + "node_modules" + ] +} \ No newline at end of file From 919b8268fc2bcd4c2c87aa843fb4a2c547fc4f63 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Wed, 21 Sep 2022 06:35:30 +0900 Subject: [PATCH 084/497] [iOS] Add Authentication for curl request (#2581) --- tools/ios-release | 3 ++- tools/library | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/tools/ios-release b/tools/ios-release index 1499240cbff..85a70879c09 100755 --- a/tools/ios-release +++ b/tools/ios-release @@ -37,8 +37,9 @@ popd # upload to release download_url=$(wc_upload_asset ${release_url} ${filename}) +echo "download_url is $download_url" download_url=$(tr -d '"' <<< $download_url) -echo "download_url is ${download_url}" +echo "trimmed download_url is ${download_url}" # create podspec podspec_name=TrustWalletCore diff --git a/tools/library b/tools/library index 27746bd18f9..46891c22dc9 100755 --- a/tools/library +++ b/tools/library @@ -9,24 +9,22 @@ wc_read_version() { } wc_release_url() { - set -o pipefail tag="$1" - id=$(curl "https://api.github.com/repos/trustwallet/wallet-core/releases/tags/${tag}" | jq ".id") + id=$(curl -u ${GITHUB_USER}:${GITHUB_TOKEN} "https://api.github.com/repos/trustwallet/wallet-core/releases/tags/${tag}" | jq ".id") if [[ $id == "null" ]]; then echo "Failed to get release id for tag ${tag}" - exit -1 + exit 22 fi release_url="https://uploads.github.com/repos/trustwallet/wallet-core/releases/${id}" echo ${release_url} } wc_upload_asset() { - set -o pipefail release_url="$1" filename="$2" upload_url="${release_url}/assets?name=${filename}" - download_url=$(curl -u ${GITHUB_USER}:${GITHUB_TOKEN} -X POST -H "Content-Type: application/octet-stream" --data-binary @${filename} ${upload_url} | jq ".browser_download_url") + download_url=$(curl --progress-bar --retry 3 -u ${GITHUB_USER}:${GITHUB_TOKEN} -X POST -H "Content-Type: application/octet-stream" --data-binary @${filename} ${upload_url} | jq ".browser_download_url") echo ${download_url} } From e6480ff072cc4f90736de3c1b885781c173b3e54 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 21 Sep 2022 01:00:06 +0200 Subject: [PATCH 085/497] [Tools]: Sample Dev go console (#2543) * feat(dev_console): skeleton directory data structure * feat(dev_console): add prepare.sh * feat(dev_console): better twstring.go * feat(dev_console): add size function * feat(dev_console): add mnemonic and wallet basis * feat(dev_console): add mnemonic method to wallet data structure * feat(dev_console): add completer + executor basis * feat(dev_console): start create_wallet part * feat(dev_console): first implementation of wallet creation * feat(dev_console): add twaccount.go skeleton * feat(dev_console): add account address functionality * feat(dev_console): use a common directory for wallet creation - relative to executable path. * feat(dev_console): add load_wallet * feat(dev_console): add address_all * feat(dev_console): add delete_wallet cmd * feat(dev_console): add help cmd * feat(dev_console): add README.md * feat(ci): build golang dev console --- .github/workflows/linux-sampleapp-ci.yml | 10 +- samples/go/dev-console/.gitignore | 1 + samples/go/dev-console/README.md | 12 ++ samples/go/dev-console/cli/address.go | 23 ++++ samples/go/dev-console/cli/completer.go | 37 ++++++ samples/go/dev-console/cli/create_wallet.go | 118 ++++++++++++++++++ samples/go/dev-console/cli/delete_wallet.go | 41 ++++++ samples/go/dev-console/cli/executor.go | 28 +++++ samples/go/dev-console/cli/help.go | 36 ++++++ samples/go/dev-console/cli/load_wallet.go | 77 ++++++++++++ samples/go/dev-console/cmd/cli.go | 15 +++ samples/go/dev-console/go.mod | 20 +++ samples/go/dev-console/go.sum | 39 ++++++ samples/go/dev-console/native/cgo.go | 14 +++ .../go/dev-console/native/packaged/.gitignore | 2 + .../go/dev-console/native/packaged/.gitkeep | 0 .../native/packaged/include/.gitkeep | 0 .../native/packaged/include/dummy.go | 2 + .../dev-console/native/packaged/lib/.gitkeep | 0 .../dev-console/native/packaged/lib/dummy.go | 2 + samples/go/dev-console/native/twaccount.go | 44 +++++++ samples/go/dev-console/native/twcoin.go | 24 ++++ samples/go/dev-console/native/twdata.go | 29 +++++ samples/go/dev-console/native/twmnemonic.go | 10 ++ samples/go/dev-console/native/twstoredkey.go | 54 ++++++++ samples/go/dev-console/native/twstring.go | 31 +++++ samples/go/dev-console/native/twwallet.go | 44 +++++++ samples/go/dev-console/prepare.sh | 10 ++ samples/go/dev-console/wallet/wallet.go | 41 ++++++ 29 files changed, 763 insertions(+), 1 deletion(-) create mode 100644 samples/go/dev-console/.gitignore create mode 100644 samples/go/dev-console/README.md create mode 100644 samples/go/dev-console/cli/address.go create mode 100644 samples/go/dev-console/cli/completer.go create mode 100644 samples/go/dev-console/cli/create_wallet.go create mode 100644 samples/go/dev-console/cli/delete_wallet.go create mode 100644 samples/go/dev-console/cli/executor.go create mode 100644 samples/go/dev-console/cli/help.go create mode 100644 samples/go/dev-console/cli/load_wallet.go create mode 100644 samples/go/dev-console/cmd/cli.go create mode 100644 samples/go/dev-console/go.mod create mode 100644 samples/go/dev-console/go.sum create mode 100644 samples/go/dev-console/native/cgo.go create mode 100644 samples/go/dev-console/native/packaged/.gitignore create mode 100644 samples/go/dev-console/native/packaged/.gitkeep create mode 100644 samples/go/dev-console/native/packaged/include/.gitkeep create mode 100644 samples/go/dev-console/native/packaged/include/dummy.go create mode 100644 samples/go/dev-console/native/packaged/lib/.gitkeep create mode 100644 samples/go/dev-console/native/packaged/lib/dummy.go create mode 100644 samples/go/dev-console/native/twaccount.go create mode 100644 samples/go/dev-console/native/twcoin.go create mode 100644 samples/go/dev-console/native/twdata.go create mode 100644 samples/go/dev-console/native/twmnemonic.go create mode 100644 samples/go/dev-console/native/twstoredkey.go create mode 100644 samples/go/dev-console/native/twstring.go create mode 100644 samples/go/dev-console/native/twwallet.go create mode 100755 samples/go/dev-console/prepare.sh create mode 100644 samples/go/dev-console/wallet/wallet.go diff --git a/.github/workflows/linux-sampleapp-ci.yml b/.github/workflows/linux-sampleapp-ci.yml index acedbeeb32b..3d16471abbd 100644 --- a/.github/workflows/linux-sampleapp-ci.yml +++ b/.github/workflows/linux-sampleapp-ci.yml @@ -64,7 +64,7 @@ jobs: npm run test - name: Install Go env: - GO_VERSION: 1.16.12 + GO_VERSION: 1.19 GO_ARCH: amd64 run: | curl -O -L "https://golang.org/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz" @@ -80,3 +80,11 @@ jobs: env: CC: /usr/bin/clang CXX: /usr/bin/clang++ + - name: Build Golang dev console + run: | + cd samples/go/dev-console + ./prepare.sh + cd cmd && go build -o ../tw_dev_console && cd - + env: + CC: /usr/bin/clang + CXX: /usr/bin/clang++ diff --git a/samples/go/dev-console/.gitignore b/samples/go/dev-console/.gitignore new file mode 100644 index 00000000000..6320cd248dd --- /dev/null +++ b/samples/go/dev-console/.gitignore @@ -0,0 +1 @@ +data \ No newline at end of file diff --git a/samples/go/dev-console/README.md b/samples/go/dev-console/README.md new file mode 100644 index 00000000000..9c1b0ed6495 --- /dev/null +++ b/samples/go/dev-console/README.md @@ -0,0 +1,12 @@ +## Quick start + +Compile wallet core with `${PROJECT_ROOT}/bootstrap.sh` +Use `./prepare.sh` +Compile the cli with `cd cmd && go build -o ../tw_dev_console && cd -` +Start `./tw_dev_console` + +If there is any compilation error on MacOS you can try the following command: + +`go get -u golang.org/x/sys` + +source: https://stackoverflow.com/questions/71507321/go-1-18-build-error-on-mac-unix-syscall-darwin-1-13-go253-golinkname-mus \ No newline at end of file diff --git a/samples/go/dev-console/cli/address.go b/samples/go/dev-console/cli/address.go new file mode 100644 index 00000000000..d2d11a8d6f7 --- /dev/null +++ b/samples/go/dev-console/cli/address.go @@ -0,0 +1,23 @@ +package cli + +import ( + "dev-console/native" + "dev-console/wallet" + "github.com/kyokomi/emoji/v2" +) + +func DumpAllAddress() { + if wallet.GlobalWallet == nil || !wallet.GlobalWallet.Ks.IsLoaded() { + emoji.Printf(":warning:No wallet loaded, use load_wallet or create_wallet first :warning:\n") + return + } + nbWallets := wallet.GlobalWallet.Ks.AccountCount() + var accounts []*native.Account + for idx := int32(0); idx < nbWallets; idx++ { + accounts = append(accounts, wallet.GlobalWallet.Ks.Account(idx)) + } + native.ToTableAccounts(accounts) + for _, account := range accounts { + account.Delete() + } +} diff --git a/samples/go/dev-console/cli/completer.go b/samples/go/dev-console/cli/completer.go new file mode 100644 index 00000000000..15021fec4d5 --- /dev/null +++ b/samples/go/dev-console/cli/completer.go @@ -0,0 +1,37 @@ +package cli + +import ( + "github.com/c-bata/go-prompt" + "strings" +) + +var gCommands = []prompt.Suggest{ + {Text: "exit", Description: "Quit the CLI"}, + {Text: "create_wallet", Description: "Create a new wallet"}, + {Text: "load_wallet", Description: "Load an existing wallet"}, + {Text: "delete_wallet", Description: "Delete an existing wallet"}, + {Text: "address_all", Description: "Show the addresses of all accounts from the current wallet"}, + {Text: "help", Description: "Show the global help"}, +} + +type Completer struct { +} + +func NewCompleter() (*Completer, error) { + return &Completer{}, nil +} + +func (c *Completer) argumentsCompleter(args []string) []prompt.Suggest { + if len(args) <= 1 { + return prompt.FilterContains(gCommands, args[0], true) + } + return []prompt.Suggest{} +} + +func (c *Completer) Complete(d prompt.Document) []prompt.Suggest { + if d.TextBeforeCursor() == "" { + return []prompt.Suggest{} + } + args := strings.Split(d.TextBeforeCursor(), " ") + return c.argumentsCompleter(args) +} diff --git a/samples/go/dev-console/cli/create_wallet.go b/samples/go/dev-console/cli/create_wallet.go new file mode 100644 index 00000000000..11eb80914f4 --- /dev/null +++ b/samples/go/dev-console/cli/create_wallet.go @@ -0,0 +1,118 @@ +package cli + +import ( + "dev-console/native" + "dev-console/wallet" + "fmt" + "github.com/kyokomi/emoji/v2" + "github.com/manifoldco/promptui" + "log" + "path/filepath" +) + +func ConfigureMnemonic() *native.Wallet { + prompt := promptui.Select{ + Label: "Passphrase Configuration", + Items: []string{"Generate a Seed", "Restore a Seed"}, + } + _, result, _ := prompt.Run() + + if result == "Generate a Seed" { + return generateSeed() + } else if result == "Restore a Seed" { + return restoreSeed() + } + return nil +} + +func restoreSeed() *native.Wallet { + promptRestoreSeed := promptui.Prompt{ + Label: "Please enter your seed", + } + resultSeed, err := promptRestoreSeed.Run() + if err != nil { + fmt.Printf("Prompt failed %v\n", err) + return restoreSeed() + } + + if len(resultSeed) == 0 { + fmt.Println("You're custom seed cannot be empty, please try again") + return restoreSeed() + } + + if !native.IsMnemonicValid(resultSeed) { + fmt.Println("You're seed is not a valid bip39 seed, please retry") + return restoreSeed() + } + + wallet, err := native.NewWalletWithMnemonic(resultSeed) + if err != nil { + log.Fatalf("Couldn't create the wallet: %v", err) + } + return wallet +} + +func generateSeed() *native.Wallet { + wallet := native.NewWalletWithRandomMnemonic() + return wallet +} + +func ConfigureWalletName() string { + promptWalletName := promptui.Prompt{ + Label: "Please enter your wallet name", + } + walletName, err := promptWalletName.Run() + if err != nil { + fmt.Printf("Prompt failed %v\n", err) + walletName = ConfigureWalletName() + } + + if len(walletName) == 0 { + fmt.Println("You're custom seed cannot be empty, please try again") + walletName = ConfigureWalletName() + } + + return walletName +} + +func ConfigurePassword() string { + promptPassword := promptui.Prompt{ + Label: "Please, choose a wallet password", + } + walletPassword, err := promptPassword.Run() + if err != nil { + fmt.Printf("Prompt failed %v\n", err) + walletPassword = ConfigureWalletName() + } + + if len(walletPassword) == 0 { + fmt.Println("You're password cannot be empty, please try again") + walletPassword = ConfigureWalletName() + } + + // Do We really need to check if the password is strong? It's a dev console. + return walletPassword +} + +func CreateWallet() { + walletName := ConfigureWalletName() + freshWallet := ConfigureMnemonic() + password := ConfigurePassword() + defer freshWallet.Delete() + storedKey := native.NewStoredKeyFromHDWallet(freshWallet.Mnemonic(), walletName, password, native.CoinTypeBitcoin) + storedKey.AccountForCoin(password, native.CoinTypeBinance) + storedKey.AccountForCoin(password, native.CoinTypeEthereum) + if storedKey != nil { + res := storedKey.Store(filepath.Join(wallet.GetWalletDataDirectory(), walletName+".json")) + if res { + _, _ = emoji.Println("Wallet successfully created :white_check_mark:") + // the global wallet can be loaded on creation or with load_wallet `wallet_name` - afterwards we can query accounts and address + // open to change the package name + // I guess keep the password the time the app is open is OK, no need to query it again + wallet.GlobalWallet = &wallet.Wallet{Ks: storedKey, Password: password, WalletName: walletName} + wallet.GlobalWallet.Dump() + } + } else { + fmt.Println("Couldn't create the wallet") + } +} diff --git a/samples/go/dev-console/cli/delete_wallet.go b/samples/go/dev-console/cli/delete_wallet.go new file mode 100644 index 00000000000..cd61a2b26b6 --- /dev/null +++ b/samples/go/dev-console/cli/delete_wallet.go @@ -0,0 +1,41 @@ +package cli + +import ( + "dev-console/native" + "dev-console/wallet" + "fmt" + "github.com/kyokomi/emoji/v2" + "log" + "os" + "path/filepath" +) + +func DeleteWallet() { + wallets := listWallets() + if len(wallets) == 0 { + fmt.Println("No wallets found, use create_wallet instead.") + return + } + walletName := chooseWallet(wallets) + walletPath := filepath.Join(wallet.GetWalletDataDirectory(), walletName+".json") + + walletPassword := queryWalletPassword() + storedKey := native.Load(walletPath) + if storedKey.IsLoaded() { + + if hdWallet := storedKey.Wallet(walletPassword); hdWallet.IsValid() { + e := os.Remove(walletPath) + if e != nil { + log.Fatal(e) + } + wallet.GlobalWallet = nil + emoji.Printf("Wallet %s successfully deleted :white_check_mark:\n", walletName) + defer hdWallet.Delete() + } else { + fmt.Println("Password from the wallet is incorrect") + DeleteWallet() + } + } else { + fmt.Println("Can't load the wallet.") + } +} diff --git a/samples/go/dev-console/cli/executor.go b/samples/go/dev-console/cli/executor.go new file mode 100644 index 00000000000..7c157234783 --- /dev/null +++ b/samples/go/dev-console/cli/executor.go @@ -0,0 +1,28 @@ +package cli + +import ( + "fmt" + "os" + "strings" +) + +func Executor(fullCommand string) { + fullCommand = strings.TrimSpace(fullCommand) + command := strings.Split(fullCommand, " ") + switch command[0] { + case "create_wallet": + CreateWallet() + case "load_wallet": + LoadWallet() + case "delete_wallet": + DeleteWallet() + case "address_all": + DumpAllAddress() + case "help": + ShowGlobalHelp() + case "exit": + fmt.Println("Quitting the CLI") + os.Exit(0) + } + return +} diff --git a/samples/go/dev-console/cli/help.go b/samples/go/dev-console/cli/help.go new file mode 100644 index 00000000000..c47277c9029 --- /dev/null +++ b/samples/go/dev-console/cli/help.go @@ -0,0 +1,36 @@ +package cli + +import ( + "github.com/olekukonko/tablewriter" + "os" +) + +const ( + createWalletHelp = `The create_wallet command create a new wallet with a given name and password. +You can choose to restore or generate a seed.` + createWalletUsage = `create_wallet` + loadWalletHelp = `The load_wallet command load the current wallet, the password will be prompted.` + loadWalletUsage = `load_wallet` + deleteWalletHelp = `The delete_wallet command delete the chosen wallet, password will be prompted.` + deleteWalletUsage = `delete_wallet` + addressAllHelp = `The address_all command dump a table of all address accounts of the current loaded wallet. +Wallet need to be loaded with load_wallet before usage.` + addressAllUsage = `address_all` +) + +func ShowGlobalHelp() { + data := [][]string{ + {"create_wallet", "", createWalletHelp, createWalletUsage}, + {"load_wallet", "", loadWalletHelp, loadWalletUsage}, + {"delete_wallet", "", deleteWalletHelp, deleteWalletUsage}, + {"address_all", "", addressAllHelp, addressAllUsage}, + } + + table := tablewriter.NewWriter(os.Stdout) + table.SetAutoWrapText(false) + table.SetHeader([]string{"Command", "Args", "Description", "Usage"}) + table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) + table.SetCenterSeparator("|") + table.AppendBulk(data) // Add Bulk Data + table.Render() +} diff --git a/samples/go/dev-console/cli/load_wallet.go b/samples/go/dev-console/cli/load_wallet.go new file mode 100644 index 00000000000..c9f2968ce9c --- /dev/null +++ b/samples/go/dev-console/cli/load_wallet.go @@ -0,0 +1,77 @@ +package cli + +import ( + "dev-console/native" + "dev-console/wallet" + "fmt" + "github.com/manifoldco/promptui" + "log" + "os" + "path/filepath" + "strings" +) + +func listWallets() []string { + files, err := os.ReadDir(wallet.GetWalletDataDirectory()) + if err != nil { + log.Fatal(err) + } + + var wallets []string + for _, file := range files { + wallets = append(wallets, strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))) + } + return wallets +} + +func chooseWallet(wallets []string) string { + prompt := promptui.Select{ + Label: "Choose the wallet to load", + Items: wallets, + } + _, result, _ := prompt.Run() + return result +} + +func queryWalletPassword() string { + promptPassword := promptui.Prompt{ + Label: "Please, enter your wallet password", + } + walletPassword, err := promptPassword.Run() + if err != nil { + fmt.Printf("Prompt failed %v\n", err) + walletPassword = queryWalletPassword() + } + + if len(walletPassword) == 0 { + fmt.Println("You're password cannot be empty, please try again") + walletPassword = queryWalletPassword() + } + + return walletPassword +} + +func LoadWallet() { + wallets := listWallets() + if len(wallets) == 0 { + fmt.Println("No wallets found, use create_wallet instead.") + return + } + walletName := chooseWallet(wallets) + walletPath := filepath.Join(wallet.GetWalletDataDirectory(), walletName+".json") + walletPassword := queryWalletPassword() + storedKey := native.Load(walletPath) + if storedKey.IsLoaded() { + wallet.GlobalWallet = &wallet.Wallet{Ks: storedKey, Password: walletPassword, WalletName: walletName} + if hdWallet := storedKey.Wallet(walletPassword); hdWallet.IsValid() { + fmt.Printf("Wallet %s successfully loaded\n", walletName) + defer hdWallet.Delete() + } else { + fmt.Println("Password from the wallet is incorrect") + wallet.GlobalWallet = nil + LoadWallet() + } + } else { + fmt.Println("Can't load the wallet.") + } +} diff --git a/samples/go/dev-console/cmd/cli.go b/samples/go/dev-console/cmd/cli.go new file mode 100644 index 00000000000..07ee64ec2a0 --- /dev/null +++ b/samples/go/dev-console/cmd/cli.go @@ -0,0 +1,15 @@ +package main + +import ( + "dev-console/cli" + "github.com/c-bata/go-prompt" +) + +func main() { + completer, _ := cli.NewCompleter() + p := prompt.New( + cli.Executor, + completer.Complete, + ) + p.Run() +} diff --git a/samples/go/dev-console/go.mod b/samples/go/dev-console/go.mod new file mode 100644 index 00000000000..f134213cc0d --- /dev/null +++ b/samples/go/dev-console/go.mod @@ -0,0 +1,20 @@ +module dev-console + +go 1.19 + +require ( + github.com/c-bata/go-prompt v0.2.6 + github.com/kyokomi/emoji/v2 v2.2.10 + github.com/manifoldco/promptui v0.9.0 + github.com/olekukonko/tablewriter v0.0.5 +) + +require ( + github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect + github.com/mattn/go-colorable v0.1.7 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/mattn/go-tty v0.0.3 // indirect + github.com/pkg/term v1.2.0-beta.2 // indirect + golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect +) diff --git a/samples/go/dev-console/go.sum b/samples/go/dev-console/go.sum new file mode 100644 index 00000000000..18a71a2e408 --- /dev/null +++ b/samples/go/dev-console/go.sum @@ -0,0 +1,39 @@ +github.com/c-bata/go-prompt v0.2.6 h1:POP+nrHE+DfLYx370bedwNhsqmpCUynWPxuHi0C5vZI= +github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY= +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/kyokomi/emoji/v2 v2.2.10 h1:1z5eMVcxFifsmEoNpdeq4UahbcicgQ4FEHuzrCVwmiI= +github.com/kyokomi/emoji/v2 v2.2.10/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE= +github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= +github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI= +github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw= +github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/samples/go/dev-console/native/cgo.go b/samples/go/dev-console/native/cgo.go new file mode 100644 index 00000000000..3e0569e9162 --- /dev/null +++ b/samples/go/dev-console/native/cgo.go @@ -0,0 +1,14 @@ +package native + +// #cgo CFLAGS: -I packaged/include +// #cgo LDFLAGS: -lTrustWalletCore -lstdc++ -lm -lprotobuf -lTrezorCrypto +// +// +// #cgo LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib -L${SRCDIR}/packaged/lib +// +import "C" + +import ( + _ "dev-console/native/packaged/include" + _ "dev-console/native/packaged/lib" +) diff --git a/samples/go/dev-console/native/packaged/.gitignore b/samples/go/dev-console/native/packaged/.gitignore new file mode 100644 index 00000000000..a48ad1e8d53 --- /dev/null +++ b/samples/go/dev-console/native/packaged/.gitignore @@ -0,0 +1,2 @@ +*.h +*.a \ No newline at end of file diff --git a/samples/go/dev-console/native/packaged/.gitkeep b/samples/go/dev-console/native/packaged/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/samples/go/dev-console/native/packaged/include/.gitkeep b/samples/go/dev-console/native/packaged/include/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/samples/go/dev-console/native/packaged/include/dummy.go b/samples/go/dev-console/native/packaged/include/dummy.go new file mode 100644 index 00000000000..3f807a2211b --- /dev/null +++ b/samples/go/dev-console/native/packaged/include/dummy.go @@ -0,0 +1,2 @@ +// See https://github.com/golang/go/issues/26366. +package include diff --git a/samples/go/dev-console/native/packaged/lib/.gitkeep b/samples/go/dev-console/native/packaged/lib/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/samples/go/dev-console/native/packaged/lib/dummy.go b/samples/go/dev-console/native/packaged/lib/dummy.go new file mode 100644 index 00000000000..662a7ee75a7 --- /dev/null +++ b/samples/go/dev-console/native/packaged/lib/dummy.go @@ -0,0 +1,2 @@ +// See https://github.com/golang/go/issues/26366. +package lib diff --git a/samples/go/dev-console/native/twaccount.go b/samples/go/dev-console/native/twaccount.go new file mode 100644 index 00000000000..33e5b22f2fe --- /dev/null +++ b/samples/go/dev-console/native/twaccount.go @@ -0,0 +1,44 @@ +package native + +// #include +import "C" +import ( + "github.com/olekukonko/tablewriter" + "os" +) + +type Account struct { + account *C.struct_TWAccount +} + +func (self *Account) Delete() { + C.TWAccountDelete(self.account) +} + +func (self *Account) Address() string { + address := TWString{s: C.TWAccountAddress(self.account)} + defer address.Delete() + return address.String() +} + +func (self *Account) CoinType() CoinType { + return CoinType(C.TWAccountCoin(self.account)) +} + +func ToTableAccounts(accounts []*Account) { + var data [][]string + + for _, account := range accounts { + cur := []string{account.CoinType().GetName(), account.Address()} + data = append(data, cur) + } + + table := tablewriter.NewWriter(os.Stdout) + table.SetAutoWrapText(false) + table.SetHeader([]string{"Coin", "Address"}) + table.SetFooter([]string{"", ""}) + table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) + table.SetCenterSeparator("|") + table.AppendBulk(data) // Add Bulk Data + table.Render() +} diff --git a/samples/go/dev-console/native/twcoin.go b/samples/go/dev-console/native/twcoin.go new file mode 100644 index 00000000000..42eb2010640 --- /dev/null +++ b/samples/go/dev-console/native/twcoin.go @@ -0,0 +1,24 @@ +package native + +// #include +// #include +import "C" + +type CoinType uint32 + +const ( + CoinTypeBitcoin CoinType = C.TWCoinTypeBitcoin + CoinTypeBinance CoinType = C.TWCoinTypeBinance + CoinTypeEthereum CoinType = C.TWCoinTypeEthereum + CoinTypeTron CoinType = C.TWCoinTypeTron +) + +func (c CoinType) GetName() string { + name := C.TWCoinTypeConfigurationGetName(C.enum_TWCoinType(c)) + defer C.TWStringDelete(name) + return TWString{s: name}.String() +} + +func (c CoinType) Decimals() int { + return int(C.TWCoinTypeConfigurationGetDecimals(C.enum_TWCoinType(c))) +} diff --git a/samples/go/dev-console/native/twdata.go b/samples/go/dev-console/native/twdata.go new file mode 100644 index 00000000000..c558bddfa05 --- /dev/null +++ b/samples/go/dev-console/native/twdata.go @@ -0,0 +1,29 @@ +package native + +// #include +import "C" + +import ( + "encoding/hex" + "unsafe" +) + +// C.TWData -> Go byte[] +func TWDataGoBytes(d unsafe.Pointer) []byte { + cBytes := C.TWDataBytes(d) + cSize := C.TWDataSize(d) + return C.GoBytes(unsafe.Pointer(cBytes), C.int(cSize)) +} + +// Go byte[] -> C.TWData +func TWDataCreateWithGoBytes(d []byte) unsafe.Pointer { + cBytes := C.CBytes(d) + defer C.free(unsafe.Pointer(cBytes)) + data := C.TWDataCreateWithBytes((*C.uchar)(cBytes), C.ulong(len(d))) + return data +} + +// C.TWData -> Go hex string +func TWDataHexString(d unsafe.Pointer) string { + return hex.EncodeToString(TWDataGoBytes(d)) +} diff --git a/samples/go/dev-console/native/twmnemonic.go b/samples/go/dev-console/native/twmnemonic.go new file mode 100644 index 00000000000..f159a1a486a --- /dev/null +++ b/samples/go/dev-console/native/twmnemonic.go @@ -0,0 +1,10 @@ +package native + +// #include +import "C" + +func IsMnemonicValid(mn string) bool { + str := NewTWString(mn) + defer str.Delete() + return bool(C.TWMnemonicIsValid(str.s)) +} diff --git a/samples/go/dev-console/native/twstoredkey.go b/samples/go/dev-console/native/twstoredkey.go new file mode 100644 index 00000000000..c84976ed47e --- /dev/null +++ b/samples/go/dev-console/native/twstoredkey.go @@ -0,0 +1,54 @@ +package native + +// #include +import "C" + +type StoredKey struct { + storedKey *C.struct_TWStoredKey +} + +func NewStoredKeyFromHDWallet(mnemonic string, walletName string, password string, coinType CoinType) *StoredKey { + mnemonicRaw := NewTWString(mnemonic) + defer mnemonicRaw.Delete() + walletNameRaw := NewTWString(walletName) + defer walletNameRaw.Delete() + passwordRaw := TWDataCreateWithGoBytes([]byte(password)) + sk := C.TWStoredKeyImportHDWallet(mnemonicRaw.s, walletNameRaw.s, passwordRaw, uint32(coinType)) + if sk != nil { + return &StoredKey{storedKey: sk} + } + return nil +} + +func (self *StoredKey) IsLoaded() bool { + return self.storedKey != nil +} + +func Load(path string) *StoredKey { + pathRaw := NewTWString(path) + return &StoredKey{storedKey: C.TWStoredKeyLoad(pathRaw.s)} +} + +func (self *StoredKey) AccountForCoin(password string, coinType CoinType) *Account { + wallet := self.Wallet(password) + defer wallet.Delete() + return &Account{account: C.TWStoredKeyAccountForCoin(self.storedKey, uint32(coinType), wallet.wallet)} +} + +func (self *StoredKey) Store(path string) bool { + pathRaw := NewTWString(path) + defer pathRaw.Delete() + return bool(C.TWStoredKeyStore(self.storedKey, pathRaw.s)) +} + +func (self *StoredKey) Wallet(password string) *Wallet { + return &Wallet{wallet: C.TWStoredKeyWallet(self.storedKey, TWDataCreateWithGoBytes([]byte(password)))} +} + +func (self *StoredKey) AccountCount() int32 { + return int32(C.TWStoredKeyAccountCount(self.storedKey)) +} + +func (self *StoredKey) Account(index int32) *Account { + return &Account{account: C.TWStoredKeyAccount(self.storedKey, C.size_t(index))} +} diff --git a/samples/go/dev-console/native/twstring.go b/samples/go/dev-console/native/twstring.go new file mode 100644 index 00000000000..b8df5b2349b --- /dev/null +++ b/samples/go/dev-console/native/twstring.go @@ -0,0 +1,31 @@ +package native + +// #include +import "C" + +import ( + "unsafe" +) + +type TWString struct { + s unsafe.Pointer +} + +func NewTWString(s string) TWString { + cStr := C.CString(s) + defer C.free(unsafe.Pointer(cStr)) + str := C.TWStringCreateWithUTF8Bytes(cStr) + return TWString{s: str} +} + +func (self TWString) Delete() { + C.TWStringDelete(self.s) +} + +func (self TWString) String() string { + return C.GoString(C.TWStringUTF8Bytes(self.s)) +} + +func (self TWString) Size() int64 { + return int64(C.size_t(C.TWStringSize(self.s))) +} diff --git a/samples/go/dev-console/native/twwallet.go b/samples/go/dev-console/native/twwallet.go new file mode 100644 index 00000000000..c2453580b96 --- /dev/null +++ b/samples/go/dev-console/native/twwallet.go @@ -0,0 +1,44 @@ +package native + +// #include +import "C" +import "errors" + +type Wallet struct { + wallet *C.struct_TWHDWallet +} + +func NewWalletWithRandomMnemonic() *Wallet { + return &Wallet{wallet: C.TWHDWalletCreate(256, NewTWString("").s)} +} + +func NewWalletWithMnemonic(mn string) (*Wallet, error) { + if !IsMnemonicValid(mn) { + return nil, errors.New("mnemonic is not valid") + } + str := NewTWString(mn) + empty := NewTWString("") + defer str.Delete() + defer empty.Delete() + + tw := C.TWHDWalletCreateWithMnemonic(str.s, empty.s) + return &Wallet{wallet: tw}, nil +} + +func (self *Wallet) IsValid() bool { + return self.wallet != nil +} + +func (self *Wallet) Delete() { + C.TWHDWalletDelete(self.wallet) +} + +func (self *Wallet) Seed() string { + return TWDataHexString(C.TWHDWalletSeed(self.wallet)) +} + +func (self *Wallet) Mnemonic() string { + str := TWString{s: C.TWHDWalletMnemonic(self.wallet)} + defer str.Delete() + return str.String() +} diff --git a/samples/go/dev-console/prepare.sh b/samples/go/dev-console/prepare.sh new file mode 100755 index 00000000000..76ec7e9bb85 --- /dev/null +++ b/samples/go/dev-console/prepare.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +mkdir -p build && cd build +cmake -DCMAKE_BUILD_TYPE=Release -DTW_UNIT_TESTS=OFF -DTW_BUILD_EXAMPLES=OFF -DTW_UNITY_BUILD=ON -GNinja "$PWD"/../../../../ +ninja +cp libTrustWalletCore.a ../native/packaged/lib/ +cp libprotobuf.a ../native/packaged/lib +cp trezor-crypto/libTrezorCrypto.a ../native/packaged/lib +cd - +cp -R ../../../include native/packaged/ \ No newline at end of file diff --git a/samples/go/dev-console/wallet/wallet.go b/samples/go/dev-console/wallet/wallet.go new file mode 100644 index 00000000000..4f29e713666 --- /dev/null +++ b/samples/go/dev-console/wallet/wallet.go @@ -0,0 +1,41 @@ +package wallet + +import ( + "dev-console/native" + "errors" + "github.com/kyokomi/emoji/v2" + "log" + "os" + "path/filepath" +) + +type Wallet struct { + Ks *native.StoredKey + Password string + WalletName string +} + +var GlobalWallet *Wallet = nil + +func (self *Wallet) Dump() { + emoji.Printf("Wallet Name: %s :white_check_mark:\n", self.WalletName) + // Should we really dump password? + emoji.Printf("Wallet Password: %s :white_check_mark:\n", self.Password) + wallet := self.Ks.Wallet(self.Password) + defer wallet.Delete() + emoji.Printf("Wallet Mnemonic: %s :white_check_mark:\n", wallet.Mnemonic()) + emoji.Printf("Wallet Accounts count: %d :white_check_mark:\n", self.Ks.AccountCount()) + // Should we dump other infos? +} + +func GetWalletDataDirectory() string { + pwd, _ := os.Getwd() + dir := filepath.Join(pwd, "data") + if _, err := os.Stat(dir); errors.Is(err, os.ErrNotExist) { + err := os.Mkdir(dir, os.ModePerm) + if err != nil { + log.Println(err) + } + } + return dir +} From e61fedd35383bdaa0a3c340360d2390367d01be5 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Wed, 21 Sep 2022 08:01:37 +0900 Subject: [PATCH 086/497] Update Android installation guide in readme (#2579) * Update Android installation guide in readme --- README.md | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ce0409425a2..36b798cb3cd 100644 --- a/README.md +++ b/README.md @@ -38,20 +38,9 @@ If you want to use wallet core in your project follow these instructions. ## Android -Android releases are hosted on [GitHub packages](https://github.com/trustwallet/wallet-core/packages/700258), please checkout [this installation guide](https://docs.github.com/en/packages/guides/configuring-gradle-for-use-with-github-packages#installing-a-package), you need to add GitHub access token to install it. +Android releases are hosted on [GitHub packages](https://github.com/trustwallet/wallet-core/packages/700258), you need to add GitHub access token to install it. Please checkout [this installation guide](https://developer.trustwallet.com/wallet-core/integration-guide/android-guide#adding-library-dependency) or `build.gradle` from our [android sample](https://github.com/trustwallet/wallet-core/blob/master/samples/android/build.gradle) -Add this dependency to build.gradle and run `gradle install` - -```groovy -plugins { - id 'maven' -} - -dependencies { - implementation 'com.trustwallet:wallet-core:x.y.z' -} -``` -Replace x.y.z with latest version: ![GitHub release (latest by date)](https://img.shields.io/github/v/release/trustwallet/wallet-core) +Don't forget replacing the version in the code with latest: ![GitHub release (latest by date)](https://img.shields.io/github/v/release/trustwallet/wallet-core) ## iOS From 5e2c2073be3f88ebd571587b1bb024402ad13668 Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Wed, 21 Sep 2022 12:42:06 +0100 Subject: [PATCH 087/497] [Codegen] Map coin test folder name to coin-id (#2574) * [Codegen] Renamed test directories to match coin ID-s Also, rename Ripple and (H)ECO, split Terra/TerraV2 and Evmos/NativeEvmos * Fix compiler error after Ripple -> XRP directories renamed * Remove exclusion list; add optional coin property testFolderName --- codegen/bin/cointests | 8 - codegen/lib/coin_test_gen.rb | 14 +- registry.json | 21 +- src/Coin.cpp | 2 +- src/{Ripple => XRP}/Address.cpp | 0 src/{Ripple => XRP}/Address.h | 0 src/{Ripple => XRP}/BinaryCoding.h | 0 src/{Ripple => XRP}/Entry.cpp | 0 src/{Ripple => XRP}/Entry.h | 0 src/{Ripple => XRP}/Signer.cpp | 0 src/{Ripple => XRP}/Signer.h | 0 src/{Ripple => XRP}/Transaction.cpp | 0 src/{Ripple => XRP}/Transaction.h | 0 src/{Ripple => XRP}/XAddress.cpp | 0 src/{Ripple => XRP}/XAddress.h | 0 src/interface/TWRippleXAddress.cpp | 2 +- tests/{HECO => ECO}/TWCoinTypeTests.cpp | 0 tests/Evmos/TWAnyAddressTests.cpp | 25 +- tests/Evmos/TWCoinTypeTests.cpp | 21 +- tests/NativeEvmos/TWAnyAddressTests.cpp | 39 ++ tests/NativeEvmos/TWCoinTypeTests.cpp | 32 ++ tests/Terra/SignerTests.cpp | 316 +++++++----- tests/Terra/SignerTestsClassic.cpp | 454 ------------------ tests/Terra/TWCoinTypeTests.cpp | 29 +- tests/TerraV2/SignerTests.cpp | 362 ++++++++++++++ tests/TerraV2/TWCoinTypeTests.cpp | 34 ++ tests/{Ripple => XRP}/AddressTests.cpp | 4 +- tests/{Ripple => XRP}/TWAnySignerTests.cpp | 0 tests/{Ripple => XRP}/TWCoinTypeTests.cpp | 0 .../{Ripple => XRP}/TWRippleAddressTests.cpp | 0 tests/{Ripple => XRP}/TransactionTests.cpp | 6 +- 31 files changed, 712 insertions(+), 657 deletions(-) rename src/{Ripple => XRP}/Address.cpp (100%) rename src/{Ripple => XRP}/Address.h (100%) rename src/{Ripple => XRP}/BinaryCoding.h (100%) rename src/{Ripple => XRP}/Entry.cpp (100%) rename src/{Ripple => XRP}/Entry.h (100%) rename src/{Ripple => XRP}/Signer.cpp (100%) rename src/{Ripple => XRP}/Signer.h (100%) rename src/{Ripple => XRP}/Transaction.cpp (100%) rename src/{Ripple => XRP}/Transaction.h (100%) rename src/{Ripple => XRP}/XAddress.cpp (100%) rename src/{Ripple => XRP}/XAddress.h (100%) rename tests/{HECO => ECO}/TWCoinTypeTests.cpp (100%) create mode 100644 tests/NativeEvmos/TWAnyAddressTests.cpp create mode 100644 tests/NativeEvmos/TWCoinTypeTests.cpp delete mode 100644 tests/Terra/SignerTestsClassic.cpp create mode 100644 tests/TerraV2/SignerTests.cpp create mode 100644 tests/TerraV2/TWCoinTypeTests.cpp rename tests/{Ripple => XRP}/AddressTests.cpp (97%) rename tests/{Ripple => XRP}/TWAnySignerTests.cpp (100%) rename tests/{Ripple => XRP}/TWCoinTypeTests.cpp (100%) rename tests/{Ripple => XRP}/TWRippleAddressTests.cpp (100%) rename tests/{Ripple => XRP}/TransactionTests.cpp (98%) diff --git a/codegen/bin/cointests b/codegen/bin/cointests index 9c223fedf73..a40f56b0250 100755 --- a/codegen/bin/cointests +++ b/codegen/bin/cointests @@ -21,14 +21,6 @@ CurrentDir = File.dirname(__FILE__) $LOAD_PATH.unshift(File.join(CurrentDir, '..', 'lib')) require 'coin_test_gen' -# Transforms a coin name to a C++ name -def self.format_name(n) - formatted = n - #formatted = formatted.sub(/^([a-z]+)/, &:upcase) - formatted = formatted.sub(/\s/, '') - formatted -end - # Transforms number to hex def self.to_hex(i) hex = i.to_i().to_s(16) diff --git a/codegen/lib/coin_test_gen.rb b/codegen/lib/coin_test_gen.rb index 58c7d6955d7..e4d7d845fce 100755 --- a/codegen/lib/coin_test_gen.rb +++ b/codegen/lib/coin_test_gen.rb @@ -14,8 +14,10 @@ def initialize() # Transforms a coin name to a C++ name def format_name(n) formatted = n - #formatted = formatted.sub(/^([a-z]+)/, &:upcase) - formatted = formatted.sub(/\s/, '') + + # Remove whitespaces + formatted.gsub!(/\s+/, '') + formatted end @@ -61,7 +63,13 @@ def generate_coin_test_file(coin, templateFile, overwriteExisting = true) template = ERB.new(File.read(path), nil, '-') result = template.result(binding) - folder = 'tests/' + format_name(coin['name']) + folder = 'tests/' + if coin.key?('testFolderName') + folder += format_name(coin['testFolderName']) + else + folder += format_name(coin['name']) + end + file = 'TWCoinTypeTests.cpp' FileUtils.mkdir_p folder path = File.join(folder, file) diff --git a/registry.json b/registry.json index ddb7b73a287..537498c91ac 100644 --- a/registry.json +++ b/registry.json @@ -1905,7 +1905,8 @@ "rpc": "https://data-seed-prebsc-1-s1.binance.org:8545", "documentation": "https://eth.wiki/json-rpc/API" }, - "deprecated": true + "deprecated": true, + "testFolderName" : "Binance" }, { "id": "smartchain", @@ -1937,7 +1938,8 @@ "source": "https://github.com/binance-chain/bsc", "rpc": "https://bsc-dataseed1.binance.org", "documentation": "https://eth.wiki/json-rpc/API" - } + }, + "testFolderName" : "Binance" }, { "id": "polygon", @@ -2086,7 +2088,8 @@ "source": "https://github.com/HuobiGroup/huobi-eco-chain", "rpc": "https://http-mainnet-node.huobichain.com", "documentation": "https://eth.wiki/json-rpc/API" - } + }, + "testFolderName" : "ECO" }, { "id": "avalanchec", @@ -2116,7 +2119,8 @@ "client": "https://github.com/ava-labs/avalanchego", "clientPublic": "https://api.avax.network/ext/bc/C/rpc", "clientDocs": "https://docs.avax.network/" - } + }, + "testFolderName" : "Avalanche" }, { "id": "xdai", @@ -2363,7 +2367,8 @@ "client": "https://github.com/crypto-org-chain/cronos", "clientPublic": "https://evm-cronos.crypto.org", "clientDocs": "https://eth.wiki/json-rpc/API" - } + }, + "testFolderName" : "Cronos" }, { "id": "kavaevm", @@ -2421,7 +2426,8 @@ "source": "https://github.com/smartbch/smartbch", "rpc": "https://smartbch.fountainhead.cash/mainnet", "documentation": "https://github.com/smartbch/docs/blob/main/developers-guide/jsonrpc.md" - } + }, + "testFolderName" : "Bitcoin" }, { "id": "kcc", @@ -2451,7 +2457,8 @@ "source": "https://github.com/kcc-community/kcc", "rpc": "https://rpc-mainnet.kcc.network", "documentation": "https://docs.kcc.io/#/en-us/" - } + }, + "testFolderName" : "KuCoinCommunityChain" }, { "id": "boba", diff --git a/src/Coin.cpp b/src/Coin.cpp index c90996899b7..f22a8713fc1 100644 --- a/src/Coin.cpp +++ b/src/Coin.cpp @@ -41,7 +41,7 @@ #include "Oasis/Entry.h" #include "Ontology/Entry.h" #include "Polkadot/Entry.h" -#include "Ripple/Entry.h" +#include "XRP/Entry.h" #include "Ronin/Entry.h" #include "Solana/Entry.h" #include "Stellar/Entry.h" diff --git a/src/Ripple/Address.cpp b/src/XRP/Address.cpp similarity index 100% rename from src/Ripple/Address.cpp rename to src/XRP/Address.cpp diff --git a/src/Ripple/Address.h b/src/XRP/Address.h similarity index 100% rename from src/Ripple/Address.h rename to src/XRP/Address.h diff --git a/src/Ripple/BinaryCoding.h b/src/XRP/BinaryCoding.h similarity index 100% rename from src/Ripple/BinaryCoding.h rename to src/XRP/BinaryCoding.h diff --git a/src/Ripple/Entry.cpp b/src/XRP/Entry.cpp similarity index 100% rename from src/Ripple/Entry.cpp rename to src/XRP/Entry.cpp diff --git a/src/Ripple/Entry.h b/src/XRP/Entry.h similarity index 100% rename from src/Ripple/Entry.h rename to src/XRP/Entry.h diff --git a/src/Ripple/Signer.cpp b/src/XRP/Signer.cpp similarity index 100% rename from src/Ripple/Signer.cpp rename to src/XRP/Signer.cpp diff --git a/src/Ripple/Signer.h b/src/XRP/Signer.h similarity index 100% rename from src/Ripple/Signer.h rename to src/XRP/Signer.h diff --git a/src/Ripple/Transaction.cpp b/src/XRP/Transaction.cpp similarity index 100% rename from src/Ripple/Transaction.cpp rename to src/XRP/Transaction.cpp diff --git a/src/Ripple/Transaction.h b/src/XRP/Transaction.h similarity index 100% rename from src/Ripple/Transaction.h rename to src/XRP/Transaction.h diff --git a/src/Ripple/XAddress.cpp b/src/XRP/XAddress.cpp similarity index 100% rename from src/Ripple/XAddress.cpp rename to src/XRP/XAddress.cpp diff --git a/src/Ripple/XAddress.h b/src/XRP/XAddress.h similarity index 100% rename from src/Ripple/XAddress.h rename to src/XRP/XAddress.h diff --git a/src/interface/TWRippleXAddress.cpp b/src/interface/TWRippleXAddress.cpp index 1304b1d17ab..f003e5614a0 100644 --- a/src/interface/TWRippleXAddress.cpp +++ b/src/interface/TWRippleXAddress.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../Ripple/XAddress.h" +#include "../XRP/XAddress.h" #include #include diff --git a/tests/HECO/TWCoinTypeTests.cpp b/tests/ECO/TWCoinTypeTests.cpp similarity index 100% rename from tests/HECO/TWCoinTypeTests.cpp rename to tests/ECO/TWCoinTypeTests.cpp diff --git a/tests/Evmos/TWAnyAddressTests.cpp b/tests/Evmos/TWAnyAddressTests.cpp index 95fdc299a28..5f52cdbf5c4 100644 --- a/tests/Evmos/TWAnyAddressTests.cpp +++ b/tests/Evmos/TWAnyAddressTests.cpp @@ -11,6 +11,8 @@ #include +namespace TW::Evmos::tests { + TEST(EvmosAnyAddress, EvmosValidate) { auto string = STRING("0x30627903124Aa1e71384bc52e1cb96E4AB3252b6"); @@ -34,25 +36,4 @@ TEST(EvmosAnyAddress, EvmosCreate) { assertHexEqual(keyHash, "8f348f300873fd5da36950b2ac75a26584584fee"); } -TEST(EvmosAnyAddress, NativeEvmosValidate) { - auto string = STRING("evmos1mwspdc5y6lj0glm90j9sg7vmr5ksmqcnzhg0h9"); - - EXPECT_TRUE(TWAnyAddressIsValid(string.get(), TWCoinTypeNativeEvmos)); - - auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithString(string.get(), TWCoinTypeNativeEvmos)); - - auto keyHash = WRAPD(TWAnyAddressData(addr.get())); - assertHexEqual(keyHash, "dba016e284d7e4f47f657c8b04799b1d2d0d8313"); -} - -TEST(EvmosAnyAddress, NativeEvmosCreate) { - auto publicKeyHex = "035a0c6b83b8bd9827e507270cadb499b7e3a9095246f6a2213281f783d877c98b"; // shoot island position ... - const auto publicKey = WRAP(TWPublicKey, TWPublicKeyCreateWithData(DATA(publicKeyHex).get(), TWPublicKeyTypeSECP256k1)); - - auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKey(publicKey.get(), TWCoinTypeNativeEvmos)); - - EXPECT_EQ(std::string(TWStringUTF8Bytes(WRAPS(TWAnyAddressDescription(addr.get())).get())), std::string("evmos1mwspdc5y6lj0glm90j9sg7vmr5ksmqcnzhg0h9")); - - auto keyHash = WRAPD(TWAnyAddressData(addr.get())); - assertHexEqual(keyHash, "dba016e284d7e4f47f657c8b04799b1d2d0d8313"); -} +} // namespace TW::Evmos::tests diff --git a/tests/Evmos/TWCoinTypeTests.cpp b/tests/Evmos/TWCoinTypeTests.cpp index d7e5ce7c27a..9e5fdcf643e 100644 --- a/tests/Evmos/TWCoinTypeTests.cpp +++ b/tests/Evmos/TWCoinTypeTests.cpp @@ -8,6 +8,8 @@ #include #include +namespace TW::Evmos::tests { + TEST(TWEvmosCoinType, TWCoinTypeEvmos) { auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeEvmos)); auto txId = WRAPS(TWStringCreateWithUTF8Bytes("0x24af42cf4977a96d62e3a82c3cd9b519c3e7c53dd83398b88f0cb435d867b422")); @@ -27,21 +29,4 @@ TEST(TWEvmosCoinType, TWCoinTypeEvmos) { assertStringsEqual(name, "Evmos"); } -TEST(TWEvmosCoinType, TWCoinTypeNativeEvmos) { - auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeNativeEvmos)); - auto txId = WRAPS(TWStringCreateWithUTF8Bytes("A16C211C83AD1E684DE46F694FAAC17D8465C864BD7385A81EC062CDE0638811")); - auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeNativeEvmos, txId.get())); - auto accId = WRAPS(TWStringCreateWithUTF8Bytes("evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw34")); - auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeNativeEvmos, accId.get())); - auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeNativeEvmos)); - auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeNativeEvmos)); - - ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeNativeEvmos), 18); - ASSERT_EQ(TWBlockchainCosmos, TWCoinTypeBlockchain(TWCoinTypeNativeEvmos)); - - assertStringsEqual(symbol, "EVMOS"); - assertStringsEqual(txUrl, "https://mintscan.io/evmos/txs/A16C211C83AD1E684DE46F694FAAC17D8465C864BD7385A81EC062CDE0638811"); - assertStringsEqual(accUrl, "https://mintscan.io/evmos/account/evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw34"); - assertStringsEqual(id, "nativeevmos"); - assertStringsEqual(name, "Native Evmos"); -} +} // namespace TW::Evmos::tests diff --git a/tests/NativeEvmos/TWAnyAddressTests.cpp b/tests/NativeEvmos/TWAnyAddressTests.cpp new file mode 100644 index 00000000000..410da049ba9 --- /dev/null +++ b/tests/NativeEvmos/TWAnyAddressTests.cpp @@ -0,0 +1,39 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "../interface/TWTestUtilities.h" + +#include +#include + +#include + +namespace TW::NativeEvmos::tests { + +TEST(EvmosAnyAddress, NativeEvmosValidate) { + auto string = STRING("evmos1mwspdc5y6lj0glm90j9sg7vmr5ksmqcnzhg0h9"); + + EXPECT_TRUE(TWAnyAddressIsValid(string.get(), TWCoinTypeNativeEvmos)); + + auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithString(string.get(), TWCoinTypeNativeEvmos)); + + auto keyHash = WRAPD(TWAnyAddressData(addr.get())); + assertHexEqual(keyHash, "dba016e284d7e4f47f657c8b04799b1d2d0d8313"); +} + +TEST(EvmosAnyAddress, NativeEvmosCreate) { + auto publicKeyHex = "035a0c6b83b8bd9827e507270cadb499b7e3a9095246f6a2213281f783d877c98b"; // shoot island position ... + const auto publicKey = WRAP(TWPublicKey, TWPublicKeyCreateWithData(DATA(publicKeyHex).get(), TWPublicKeyTypeSECP256k1)); + + auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKey(publicKey.get(), TWCoinTypeNativeEvmos)); + + EXPECT_EQ(std::string(TWStringUTF8Bytes(WRAPS(TWAnyAddressDescription(addr.get())).get())), std::string("evmos1mwspdc5y6lj0glm90j9sg7vmr5ksmqcnzhg0h9")); + + auto keyHash = WRAPD(TWAnyAddressData(addr.get())); + assertHexEqual(keyHash, "dba016e284d7e4f47f657c8b04799b1d2d0d8313"); +} + +} // namespace TW::NativeEvmos::tests diff --git a/tests/NativeEvmos/TWCoinTypeTests.cpp b/tests/NativeEvmos/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..fdcc17272f5 --- /dev/null +++ b/tests/NativeEvmos/TWCoinTypeTests.cpp @@ -0,0 +1,32 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "../interface/TWTestUtilities.h" +#include +#include + +namespace TW::NativeEvmos::tests { + +TEST(TWEvmosCoinType, TWCoinTypeNativeEvmos) { + auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeNativeEvmos)); + auto txId = WRAPS(TWStringCreateWithUTF8Bytes("A16C211C83AD1E684DE46F694FAAC17D8465C864BD7385A81EC062CDE0638811")); + auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeNativeEvmos, txId.get())); + auto accId = WRAPS(TWStringCreateWithUTF8Bytes("evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw34")); + auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeNativeEvmos, accId.get())); + auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeNativeEvmos)); + auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeNativeEvmos)); + + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeNativeEvmos), 18); + ASSERT_EQ(TWBlockchainCosmos, TWCoinTypeBlockchain(TWCoinTypeNativeEvmos)); + + assertStringsEqual(symbol, "EVMOS"); + assertStringsEqual(txUrl, "https://mintscan.io/evmos/txs/A16C211C83AD1E684DE46F694FAAC17D8465C864BD7385A81EC062CDE0638811"); + assertStringsEqual(accUrl, "https://mintscan.io/evmos/account/evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw34"); + assertStringsEqual(id, "nativeevmos"); + assertStringsEqual(name, "Native Evmos"); +} + +} // namespace TW::NativeEvmos::tests diff --git a/tests/Terra/SignerTests.cpp b/tests/Terra/SignerTests.cpp index 483cd1adfd6..ee67a38dddc 100644 --- a/tests/Terra/SignerTests.cpp +++ b/tests/Terra/SignerTests.cpp @@ -4,7 +4,6 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Coin.h" #include "HexCoding.h" #include "Base64.h" #include "proto/Cosmos.pb.h" @@ -17,94 +16,95 @@ #include #include -using namespace TW; namespace TW::Cosmos::tests { -TEST(TerraSigner, SignSendTx) { +TEST(TerraClassicSigner, SignSendTx) { auto input = Proto::SigningInput(); - input.set_signing_mode(Proto::Protobuf); + input.set_signing_mode(Proto::JSON); input.set_account_number(1037); - input.set_chain_id("phoenix-1"); + input.set_chain_id("columbus-5"); input.set_memo(""); - input.set_sequence(1); + input.set_sequence(2); Address fromAddress; ASSERT_TRUE(Address::decode("terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2", fromAddress)); Address toAddress; - ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); + ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", toAddress)); auto msg = input.add_messages(); auto& message = *msg->mutable_send_coins_message(); message.set_from_address(fromAddress.string()); message.set_to_address(toAddress.string()); auto amountOfTx = message.add_amounts(); - amountOfTx->set_denom("uluna"); + amountOfTx->set_denom("luna"); amountOfTx->set_amount("1000000"); auto& fee = *input.mutable_fee(); fee.set_gas(200000); auto amountOfFee = fee.add_amounts(); - amountOfFee->set_denom("uluna"); - amountOfFee->set_amount("30000"); - - { - std::string json; - google::protobuf::util::MessageToJsonString(input, &json); - assertJSONEqual(json, R"( - { - "signingMode": "Protobuf", - "accountNumber": "1037", - "chainId": "phoenix-1", + amountOfFee->set_denom("luna"); + amountOfFee->set_amount("200"); + + std::string json; + google::protobuf::util::MessageToJsonString(input, &json); + EXPECT_EQ(json, R"({"accountNumber":"1037","chainId":"columbus-5","fee":{"amounts":[{"denom":"luna","amount":"200"}],"gas":"200000"},"sequence":"2","messages":[{"sendCoinsMessage":{"fromAddress":"terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2","toAddress":"terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf","amounts":[{"denom":"luna","amount":"1000000"}]}}]})"); + + auto privateKey = parse_hex("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerra); + + assertJSONEqual(output.json(), R"( + { + "mode": "block", + "tx": { "fee": { - "amounts": [ + "amount": [ { - "denom": "uluna", - "amount": "30000" + "amount": "200", + "denom": "luna" } ], "gas": "200000" }, - "sequence": "1", - "messages": [ + "memo": "", + "msg": [ { - "sendCoinsMessage": { - "fromAddress": "terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2", - "toAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", - "amounts": [ + "type": "cosmos-sdk/MsgSend", + "value": { + "amount": [ { - "denom": "uluna", - "amount": "1000000" + "amount": "1000000", + "denom": "luna" } - ] + ], + "from_address": "terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2", + "to_address": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf" } } + ], + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "AlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3F" + }, + "signature": "ofdIsLJzkODcQwLG89eE2g4HOaUmfKPh/08t07ehKPUqRMl4rVonzo73mkOvqtrHWjdtB+6t6R8DGudPpb6bRg==" + } ] } - )"); - } - - auto privateKey = parse_hex("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005"); - input.set_private_key(privateKey.data(), privateKey.size()); - - auto output = Signer::sign(input, TWCoinTypeTerraV2); - - // similar tx: https://finder.terra.money/mainnet/tx/fbbe73ad2f0db3a13911dc424f8a34370dc4b7e8b66687f536797e68ee200ece - assertJSONEqual(output.serialized(), R"( - { - "tx_bytes": "CpEBCo4BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm4KLHRlcnJhMWhzazZqcnl5cWpmaHA1ZGhjNTV0YzlqdGNreWd4MGVwMzdoZGQyEix0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcBoQCgV1bHVuYRIHMTAwMDAwMBJoClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiECVyhuw/N9M1V7u6oACyd0SskCOqmWfK51oYHR/5H6ncUSBAoCCAEYARIUCg4KBXVsdW5hEgUzMDAwMBDAmgwaQPh0C3rjzdixIUiyPx3FlWAxzbKILNAcSRVeQnaTl1vsI5DEfYa2oYlUBLqyilcMCcU/iaJLhex30No2ak0Zn1Q=", - "mode": "BROADCAST_MODE_BLOCK" } )"); - EXPECT_EQ(hex(output.signature()), "f8740b7ae3cdd8b12148b23f1dc5956031cdb2882cd01c49155e427693975bec2390c47d86b6a1895404bab28a570c09c53f89a24b85ec77d0da366a4d199f54"); + EXPECT_EQ(hex(output.signature()), "a1f748b0b27390e0dc4302c6f3d784da0e0739a5267ca3e1ff4f2dd3b7a128f52a44c978ad5a27ce8ef79a43afaadac75a376d07eeade91f031ae74fa5be9b46"); + EXPECT_EQ(output.serialized(), ""); EXPECT_EQ(output.error(), ""); - EXPECT_EQ(output.json(), ""); } -TEST(TerraSigner, SignWasmTransferTx) { +TEST(TerraClassicSigner, SignWasmTransferTxProtobuf_9FF3F0) { auto input = Proto::SigningInput(); input.set_signing_mode(Proto::Protobuf); input.set_account_number(3407705); - input.set_chain_id("phoenix-1"); + input.set_chain_id("columbus-5"); input.set_memo(""); input.set_sequence(3); @@ -112,10 +112,10 @@ TEST(TerraSigner, SignWasmTransferTx) { ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); Address toAddress; ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); - const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_execute_contract_transfer_message(); + auto& message = *msg->mutable_wasm_terra_execute_contract_transfer_message(); message.set_sender_address(fromAddress.string()); message.set_contract_address(tokenContractAddress); const auto amount = store(uint256_t(250000), 0); @@ -128,69 +128,151 @@ TEST(TerraSigner, SignWasmTransferTx) { amountOfFee->set_denom("uluna"); amountOfFee->set_amount("3000"); - { - std::string json; - google::protobuf::util::MessageToJsonString(input, &json); - assertJSONEqual(json, R"( - { - "signingMode": "Protobuf", - "accountNumber": "3407705", - "chainId": "phoenix-1", - "fee": { - "amounts": [ - { - "denom": "uluna", - "amount": "3000" - } - ], - "gas": "200000" - }, - "sequence": "3", - "messages": [ + std::string json; + google::protobuf::util::MessageToJsonString(input, &json); + assertJSONEqual(json, R"( + { + "signingMode": "Protobuf", + "accountNumber": "3407705", + "chainId": "columbus-5", + "fee": { + "amounts": [ { - "wasmExecuteContractTransferMessage": { - "senderAddress": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", - "contractAddress": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", - "amount": "A9CQ", - "recipientAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" - } + "denom": "uluna", + "amount": "3000" } - ] - } - )"); - } + ], + "gas": "200000" + }, + "sequence": "3", + "messages": [ + { + "wasmTerraExecuteContractTransferMessage": { + "senderAddress": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", + "contractAddress": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", + "amount": "A9CQ", + "recipientAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" + } + } + ] + } + )"); auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); input.set_private_key(privateKey.data(), privateKey.size()); - auto output = Signer::sign(input, TWCoinTypeTerraV2); + auto output = Signer::sign(input, TWCoinTypeTerra); + // https://finder.terra.money/mainnet/tx/9FF3F0A16879254C22EB90D8B4D6195467FE5014381FD36BD3C23CA6698FE94B + // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "CogCCo..wld8"})' https:///cosmos/tx/v1beta1/txs assertJSONEqual(output.serialized(), R"( { - "tx_bytes": "CuUBCuIBCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QSuQEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTE0ejU2bDBmcDJsc2Y4Nnp5M2h0eTJ6NDdlemtobnRodHI5eXE3NhpbeyJ0cmFuc2ZlciI6eyJhbW91bnQiOiIyNTAwMDAiLCJyZWNpcGllbnQiOiJ0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcCJ9fRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYAxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAiBGbQaj+jsXE6/FssD3fC77QOxpli9GqsPea+KoNyMIEgVj89Hii+oU1bAEQS4qV0SaE2V6RNy24uCcFTIRbcQ==", + "tx_bytes": "CucBCuQBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBK5AQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Glt7InRyYW5zZmVyIjp7ImFtb3VudCI6IjI1MDAwMCIsInJlY2lwaWVudCI6InRlcnJhMWpsZ2FxeTludm4yaGY1dDJzcmE5eWN6OHM3N3duZjlsMGttZ2NwIn19EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNwZjrHsPmJKW/rXOWfukpQ1+lOHOJW3/IlFFnKLNmsABIECgIIARgDEhMKDQoFdWx1bmESBDMwMDAQwJoMGkAaprIEMLPH2HmFdwFGoaipb2GIyhXt6ombz+WMnG2mORBI6gFt0M+IymYgzZz6w1SW52R922yafDnn7yXfutRw", "mode": "BROADCAST_MODE_BLOCK" } )"); - EXPECT_EQ(hex(output.signature()), "88119b41a8fe8ec5c4ebf16cb03ddf0bbed03b1a658bd1aab0f79af8aa0dc8c2048158fcf478a2fa85356c01104b8a95d12684d95e91372db8b827054c845b71"); - EXPECT_EQ(output.error(), ""); + EXPECT_EQ(hex(output.signature()), "1aa6b20430b3c7d87985770146a1a8a96f6188ca15edea899bcfe58c9c6da6391048ea016dd0cf88ca6620cd9cfac35496e7647ddb6c9a7c39e7ef25dfbad470"); EXPECT_EQ(output.json(), ""); + EXPECT_EQ(output.error(), ""); } -TEST(TerraSigner, SignWasmGeneric) { +TEST(TerraClassicSigner, SignWasmTransferTxJson_078E90) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::JSON); + input.set_account_number(3407705); + input.set_chain_id("columbus-5"); + input.set_memo(""); + input.set_sequence(2); + + Address fromAddress; + ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); + Address toAddress; + ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC + + auto msg = input.add_messages(); + auto& message = *msg->mutable_wasm_terra_execute_contract_transfer_message(); + message.set_sender_address(fromAddress.string()); + message.set_contract_address(tokenContractAddress); + const auto amount = store(250000); + message.set_amount(amount.data(), amount.size()); + message.set_recipient_address(toAddress.string()); + + auto& fee = *input.mutable_fee(); + fee.set_gas(200000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uluna"); + amountOfFee->set_amount("3000"); + + auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerra); + + // https://finder.terra.money/mainnet/tx/078E90458061611F6FD8B708882B55FF5C1FFB3FCE61322107A0A0DE39FC0F3E + // curl -H 'Content-Type: application/json' --data-binary '{"mode": "block","tx":{...}}' https:///txs + assertJSONEqual(output.json(), R"( + { + "mode": "block", + "tx": + { + "fee": {"amount":[{"amount": "3000","denom": "uluna"}],"gas": "200000"}, + "memo": "", + "msg": + [ + { + "type": "wasm/MsgExecuteContract", + "value": + { + "sender": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", + "contract": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", + "execute_msg": + { + "transfer": + { + "amount": "250000", + "recipient": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" + } + }, + "coins": [] + } + } + ], + "signatures": + [ + { + "pub_key": + { + "type": "tendermint/PubKeySecp256k1", + "value": "A3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awA" + }, + "signature": "BjETdtbA97Wv1zvcsCV1tM+bdYKC8O3uGTk4mMRv6pBJB2y/Ds7qoS7s/zrkhYak1YChklQetHsI30XRXzGIkg==" + } + ] + } + })"); + EXPECT_EQ(hex(output.signature()), "06311376d6c0f7b5afd73bdcb02575b4cf9b758282f0edee19393898c46fea9049076cbf0eceeaa12eecff3ae48586a4d580a192541eb47b08df45d15f318892"); + EXPECT_EQ(output.serialized(), ""); + EXPECT_EQ(output.error(), ""); +} + +TEST(TerraClassicSigner, SignWasmGeneric_EC4F85) { auto input = Proto::SigningInput(); input.set_signing_mode(Proto::Protobuf); input.set_account_number(3407705); - input.set_chain_id("phoenix-1"); + input.set_chain_id("columbus-5"); input.set_memo(""); input.set_sequence(7); Address fromAddress; ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); - const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; + Address toAddress; + ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC const auto txMessage = R"({"transfer": { "amount": "250000", "recipient": "terra1d7048csap4wzcv5zm7z6tdqem2agyp9647vdyj" } })"; auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_execute_contract_generic(); + auto& message = *msg->mutable_wasm_terra_execute_contract_generic(); message.set_sender_address(fromAddress.string()); message.set_contract_address(tokenContractAddress); message.set_execute_msg(txMessage); @@ -204,35 +286,39 @@ TEST(TerraSigner, SignWasmGeneric) { auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); input.set_private_key(privateKey.data(), privateKey.size()); - auto output = Signer::sign(input, TWCoinTypeTerraV2); + auto output = Signer::sign(input, TWCoinTypeTerra); + // https://finder.terra.money/mainnet/tx/EC4F8532847E4D6AF016E6F6D3F027AE7FB6FF0B533C5132B01382D83B214A6F + // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "Cu4BC...iVt"})' https:///cosmos/tx/v1beta1/txs assertJSONEqual(output.serialized(), R"( { - "tx_bytes": "CuwBCukBCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QSwAEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTE0ejU2bDBmcDJsc2Y4Nnp5M2h0eTJ6NDdlemtobnRodHI5eXE3NhpieyJ0cmFuc2ZlciI6IHsgImFtb3VudCI6ICIyNTAwMDAiLCAicmVjaXBpZW50IjogInRlcnJhMWQ3MDQ4Y3NhcDR3emN2NXptN3o2dGRxZW0yYWd5cDk2NDd2ZHlqIiB9IH0SZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awAEgQKAggBGAcSEwoNCgV1bHVuYRIEMzAwMBDAmgwaQGlYzOoAu/PfyCTSTisGJVW9KWwifxMbCmzy2xwqNg+ZHQkDjVRyUBl7gmbXXLzdOMqtwF1CMauJhlGwmEdzhK4=", + "tx_bytes": "Cu4BCusBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLAAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2GmJ7InRyYW5zZmVyIjogeyAiYW1vdW50IjogIjI1MDAwMCIsICJyZWNpcGllbnQiOiAidGVycmExZDcwNDhjc2FwNHd6Y3Y1em03ejZ0ZHFlbTJhZ3lwOTY0N3ZkeWoiIH0gfRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYBxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAkPsS7xlSng2LMc9KiD1soN5NLaDcUh8I9okPmsdJN3le1B7yxRGNB4aQfhaRl/8Z0r5vitRT0AWuxDasd8wcFw==", "mode": "BROADCAST_MODE_BLOCK" } )"); - EXPECT_EQ(hex(output.signature()), "6958ccea00bbf3dfc824d24e2b062555bd296c227f131b0a6cf2db1c2a360f991d09038d547250197b8266d75cbcdd38caadc05d4231ab898651b098477384ae"); - EXPECT_EQ(output.error(), ""); + EXPECT_EQ(hex(output.signature()), "90fb12ef19529e0d8b31cf4a883d6ca0de4d2da0dc521f08f6890f9ac74937795ed41ef2c5118d0786907e169197ff19d2be6f8ad453d005aec436ac77cc1c17"); EXPECT_EQ(output.json(), ""); + EXPECT_EQ(output.error(), ""); } -TEST(TerraSigner, SignWasmGenericWithCoins) { +TEST(TerraClassicSigner, SignWasmGenericWithCoins_6651FC) { auto input = Proto::SigningInput(); input.set_signing_mode(Proto::Protobuf); input.set_account_number(3407705); - input.set_chain_id("phoenix-1"); + input.set_chain_id("columbus-5"); input.set_memo(""); input.set_sequence(9); Address fromAddress; ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); - const auto tokenContractAddress = "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s"; + Address toAddress; + ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); + const auto tokenContractAddress = "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s"; // ANC Market const auto txMessage = R"({ "deposit_stable": {} })"; auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_execute_contract_generic(); + auto& message = *msg->mutable_wasm_terra_execute_contract_generic(); message.set_sender_address(fromAddress.string()); message.set_contract_address(tokenContractAddress); message.set_execute_msg(txMessage); @@ -250,25 +336,27 @@ TEST(TerraSigner, SignWasmGenericWithCoins) { auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); input.set_private_key(privateKey.data(), privateKey.size()); - auto output = Signer::sign(input, TWCoinTypeTerraV2); + auto output = Signer::sign(input, TWCoinTypeTerra); + // https://finder.terra.money/mainnet/tx/6651FCE0EE5C6D6ACB655CC49A6FD5E939FB082862854616EA0642475BCDD0C9 + // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "CrIBCq8B.....0NWg=="})' https:///cosmos/tx/v1beta1/txs assertJSONEqual(output.serialized(), R"( { - "tx_bytes": "CrABCq0BCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QShAEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTFzZXBmajdzMGFlZzU5Njd1eG5mazR0aHpsZXJyc2t0a3BlbG01cxoYeyAiZGVwb3NpdF9zdGFibGUiOiB7fSB9KgwKBHV1c2QSBDEwMDASZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awAEgQKAggBGAkSEwoNCgV1bHVuYRIENzAwMBDAzyQaQEDA2foXegF+rslj6o8bX2HPJfn+q/6Ezbq2iAd0SFOTQqS8aAyywQkdZJRToXcaby1HOYL1WvmsMPgrFzChiY4=", + "tx_bytes": "CrIBCq8BCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBKEAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMXNlcGZqN3MwYWVnNTk2N3V4bmZrNHRoemxlcnJza3RrcGVsbTVzGhh7ICJkZXBvc2l0X3N0YWJsZSI6IHt9IH0qDAoEdXVzZBIEMTAwMBJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYCRITCg0KBXVsdW5hEgQ3MDAwEMDPJBpAGyi7f1ioY8XV6pjFq1s86Om4++CIUnd3rLHif2iopCcYvX0mLkTlQ6NUERg8nWTYgXcj6fOTO/ptgPuAtv0NWg==", "mode": "BROADCAST_MODE_BLOCK" } )"); - EXPECT_EQ(hex(output.signature()), "40c0d9fa177a017eaec963ea8f1b5f61cf25f9feabfe84cdbab688077448539342a4bc680cb2c1091d649453a1771a6f2d473982f55af9ac30f82b1730a1898e"); - EXPECT_EQ(output.error(), ""); + EXPECT_EQ(hex(output.signature()), "1b28bb7f58a863c5d5ea98c5ab5b3ce8e9b8fbe088527777acb1e27f68a8a42718bd7d262e44e543a35411183c9d64d8817723e9f3933bfa6d80fb80b6fd0d5a"); EXPECT_EQ(output.json(), ""); + EXPECT_EQ(output.error(), ""); } -TEST(TerraSigner, SignWasmSendTx) { +TEST(TerraClassicSigner, SignWasmSendTxProtobuf) { auto input = Proto::SigningInput(); input.set_signing_mode(Proto::Protobuf); input.set_account_number(3407705); - input.set_chain_id("phoenix-1"); + input.set_chain_id("columbus-5"); input.set_memo(""); input.set_sequence(4); @@ -276,10 +364,10 @@ TEST(TerraSigner, SignWasmSendTx) { ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); Address toAddress; ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); - const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_execute_contract_send_message(); + auto& message = *msg->mutable_wasm_terra_execute_contract_send_message(); message.set_sender_address(fromAddress.string()); message.set_contract_address(tokenContractAddress); const auto amount = store(uint256_t(250000), 0); @@ -301,7 +389,7 @@ TEST(TerraSigner, SignWasmSendTx) { { "signingMode": "Protobuf", "accountNumber": "3407705", - "chainId": "phoenix-1", + "chainId": "columbus-5", "fee": { "amounts": [ { @@ -314,7 +402,7 @@ TEST(TerraSigner, SignWasmSendTx) { "sequence": "4", "messages": [ { - "wasmExecuteContractSendMessage": { + "wasmTerraExecuteContractSendMessage": { "senderAddress": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", "contractAddress": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", "amount": "A9CQ", @@ -329,26 +417,28 @@ TEST(TerraSigner, SignWasmSendTx) { auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); input.set_private_key(privateKey.data(), privateKey.size()); - auto output = Signer::sign(input, TWCoinTypeTerraV2); + auto output = Signer::sign(input, TWCoinTypeTerra); + // https://finder.terra.money/mainnet/tx/9FF3F0A16879254C22EB90D8B4D6195467FE5014381FD36BD3C23CA6698FE94B + // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "CogCCo..wld8"})' https:///cosmos/tx/v1beta1/txs assertJSONEqual(output.serialized(), R"( { - "tx_bytes": "CoUCCoICCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QS2QEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTE0ejU2bDBmcDJsc2Y4Nnp5M2h0eTJ6NDdlemtobnRodHI5eXE3Nhp7eyJzZW5kIjp7ImFtb3VudCI6IjI1MDAwMCIsImNvbnRyYWN0IjoidGVycmExamxnYXF5OW52bjJoZjV0MnNyYTl5Y3o4czc3d25mOWwwa21nY3AiLCJtc2ciOiJleUp6YjIxbFgyMWxjM05oWjJVaU9udDlmUT09In19EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNwZjrHsPmJKW/rXOWfukpQ1+lOHOJW3/IlFFnKLNmsABIECgIIARgEEhMKDQoFdWx1bmESBDMwMDAQwJoMGkBKJbW1GDrv9j2FIckm7MtpDZzP2RjgDjU84oYmOHNHsxEBPLjtt3YAjsKWBCAsjbnbVoJ3s2XFG08nxQXS9xBK", + "tx_bytes": "CocCCoQCCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLZAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Gnt7InNlbmQiOnsiYW1vdW50IjoiMjUwMDAwIiwiY29udHJhY3QiOiJ0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcCIsIm1zZyI6ImV5SnpiMjFsWDIxbGMzTmhaMlVpT250OWZRPT0ifX0SZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awAEgQKAggBGAQSEwoNCgV1bHVuYRIEMzAwMBDAmgwaQL6NByKeRZsyq5g6CTMdmPqiM77nOe9uLO8FjpetFgkBFiG3Le7ieZZ+4vCMhD1bcFgMwSHibFI/uPil847U/+g=", "mode": "BROADCAST_MODE_BLOCK" } )"); - EXPECT_EQ(hex(output.signature()), "4a25b5b5183aeff63d8521c926eccb690d9ccfd918e00e353ce28626387347b311013cb8edb776008ec29604202c8db9db568277b365c51b4f27c505d2f7104a"); - EXPECT_EQ(output.error(), ""); + EXPECT_EQ(hex(output.signature()), "be8d07229e459b32ab983a09331d98faa233bee739ef6e2cef058e97ad1609011621b72deee279967ee2f08c843d5b70580cc121e26c523fb8f8a5f38ed4ffe8"); EXPECT_EQ(output.json(), ""); + EXPECT_EQ(output.error(), ""); } -TEST(TerraSigner, SignWasmTransferPayload) { - auto proto = Proto::Message_WasmExecuteContractTransfer(); +TEST(TerraClassicSigner, SignWasmTerraTransferPayload) { + auto proto = Proto::Message_WasmTerraExecuteContractTransfer(); proto.set_recipient_address("recipient=address"); const auto amount = store(uint256_t(250000), 0); proto.set_amount(amount.data(), amount.size()); - const auto payload = Protobuf::wasmExecuteTransferPayload(proto); + const auto payload = Protobuf::wasmTerraExecuteTransferPayload(proto); assertJSONEqual(payload.dump(), R"( { @@ -361,4 +451,4 @@ TEST(TerraSigner, SignWasmTransferPayload) { )"); } -} // namespace TW::Terra +} // namespace TW::Cosmos::tests diff --git a/tests/Terra/SignerTestsClassic.cpp b/tests/Terra/SignerTestsClassic.cpp deleted file mode 100644 index 06b5a4470c3..00000000000 --- a/tests/Terra/SignerTestsClassic.cpp +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright © 2017-2022 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -#include "HexCoding.h" -#include "Base64.h" -#include "proto/Cosmos.pb.h" -#include "Cosmos/Address.h" -#include "Cosmos/Signer.h" -#include "Cosmos/ProtobufSerialization.h" -#include "uint256.h" -#include "../interface/TWTestUtilities.h" - -#include -#include - -namespace TW::Cosmos::tests { - -TEST(TerraClassicSigner, SignSendTx) { - auto input = Proto::SigningInput(); - input.set_signing_mode(Proto::JSON); - input.set_account_number(1037); - input.set_chain_id("columbus-5"); - input.set_memo(""); - input.set_sequence(2); - - Address fromAddress; - ASSERT_TRUE(Address::decode("terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2", fromAddress)); - Address toAddress; - ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", toAddress)); - - auto msg = input.add_messages(); - auto& message = *msg->mutable_send_coins_message(); - message.set_from_address(fromAddress.string()); - message.set_to_address(toAddress.string()); - auto amountOfTx = message.add_amounts(); - amountOfTx->set_denom("luna"); - amountOfTx->set_amount("1000000"); - - auto& fee = *input.mutable_fee(); - fee.set_gas(200000); - auto amountOfFee = fee.add_amounts(); - amountOfFee->set_denom("luna"); - amountOfFee->set_amount("200"); - - std::string json; - google::protobuf::util::MessageToJsonString(input, &json); - EXPECT_EQ(json, R"({"accountNumber":"1037","chainId":"columbus-5","fee":{"amounts":[{"denom":"luna","amount":"200"}],"gas":"200000"},"sequence":"2","messages":[{"sendCoinsMessage":{"fromAddress":"terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2","toAddress":"terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf","amounts":[{"denom":"luna","amount":"1000000"}]}}]})"); - - auto privateKey = parse_hex("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005"); - input.set_private_key(privateKey.data(), privateKey.size()); - - auto output = Signer::sign(input, TWCoinTypeTerra); - - assertJSONEqual(output.json(), R"( - { - "mode": "block", - "tx": { - "fee": { - "amount": [ - { - "amount": "200", - "denom": "luna" - } - ], - "gas": "200000" - }, - "memo": "", - "msg": [ - { - "type": "cosmos-sdk/MsgSend", - "value": { - "amount": [ - { - "amount": "1000000", - "denom": "luna" - } - ], - "from_address": "terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2", - "to_address": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf" - } - } - ], - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "AlcobsPzfTNVe7uqAAsndErJAjqplnyudaGB0f+R+p3F" - }, - "signature": "ofdIsLJzkODcQwLG89eE2g4HOaUmfKPh/08t07ehKPUqRMl4rVonzo73mkOvqtrHWjdtB+6t6R8DGudPpb6bRg==" - } - ] - } - } - )"); - EXPECT_EQ(hex(output.signature()), "a1f748b0b27390e0dc4302c6f3d784da0e0739a5267ca3e1ff4f2dd3b7a128f52a44c978ad5a27ce8ef79a43afaadac75a376d07eeade91f031ae74fa5be9b46"); - EXPECT_EQ(output.serialized(), ""); - EXPECT_EQ(output.error(), ""); -} - -TEST(TerraClassicSigner, SignWasmTransferTxProtobuf_9FF3F0) { - auto input = Proto::SigningInput(); - input.set_signing_mode(Proto::Protobuf); - input.set_account_number(3407705); - input.set_chain_id("columbus-5"); - input.set_memo(""); - input.set_sequence(3); - - Address fromAddress; - ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); - Address toAddress; - ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); - const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC - - auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_terra_execute_contract_transfer_message(); - message.set_sender_address(fromAddress.string()); - message.set_contract_address(tokenContractAddress); - const auto amount = store(uint256_t(250000), 0); - message.set_amount(amount.data(), amount.size()); - message.set_recipient_address(toAddress.string()); - - auto& fee = *input.mutable_fee(); - fee.set_gas(200000); - auto amountOfFee = fee.add_amounts(); - amountOfFee->set_denom("uluna"); - amountOfFee->set_amount("3000"); - - std::string json; - google::protobuf::util::MessageToJsonString(input, &json); - assertJSONEqual(json, R"( - { - "signingMode": "Protobuf", - "accountNumber": "3407705", - "chainId": "columbus-5", - "fee": { - "amounts": [ - { - "denom": "uluna", - "amount": "3000" - } - ], - "gas": "200000" - }, - "sequence": "3", - "messages": [ - { - "wasmTerraExecuteContractTransferMessage": { - "senderAddress": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", - "contractAddress": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", - "amount": "A9CQ", - "recipientAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" - } - } - ] - } - )"); - - auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); - input.set_private_key(privateKey.data(), privateKey.size()); - - auto output = Signer::sign(input, TWCoinTypeTerra); - - // https://finder.terra.money/mainnet/tx/9FF3F0A16879254C22EB90D8B4D6195467FE5014381FD36BD3C23CA6698FE94B - // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "CogCCo..wld8"})' https:///cosmos/tx/v1beta1/txs - assertJSONEqual(output.serialized(), R"( - { - "tx_bytes": "CucBCuQBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBK5AQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Glt7InRyYW5zZmVyIjp7ImFtb3VudCI6IjI1MDAwMCIsInJlY2lwaWVudCI6InRlcnJhMWpsZ2FxeTludm4yaGY1dDJzcmE5eWN6OHM3N3duZjlsMGttZ2NwIn19EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNwZjrHsPmJKW/rXOWfukpQ1+lOHOJW3/IlFFnKLNmsABIECgIIARgDEhMKDQoFdWx1bmESBDMwMDAQwJoMGkAaprIEMLPH2HmFdwFGoaipb2GIyhXt6ombz+WMnG2mORBI6gFt0M+IymYgzZz6w1SW52R922yafDnn7yXfutRw", - "mode": "BROADCAST_MODE_BLOCK" - } - )"); - EXPECT_EQ(hex(output.signature()), "1aa6b20430b3c7d87985770146a1a8a96f6188ca15edea899bcfe58c9c6da6391048ea016dd0cf88ca6620cd9cfac35496e7647ddb6c9a7c39e7ef25dfbad470"); - EXPECT_EQ(output.json(), ""); - EXPECT_EQ(output.error(), ""); -} - -TEST(TerraClassicSigner, SignWasmTransferTxJson_078E90) { - auto input = Proto::SigningInput(); - input.set_signing_mode(Proto::JSON); - input.set_account_number(3407705); - input.set_chain_id("columbus-5"); - input.set_memo(""); - input.set_sequence(2); - - Address fromAddress; - ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); - Address toAddress; - ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); - const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC - - auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_terra_execute_contract_transfer_message(); - message.set_sender_address(fromAddress.string()); - message.set_contract_address(tokenContractAddress); - const auto amount = store(250000); - message.set_amount(amount.data(), amount.size()); - message.set_recipient_address(toAddress.string()); - - auto& fee = *input.mutable_fee(); - fee.set_gas(200000); - auto amountOfFee = fee.add_amounts(); - amountOfFee->set_denom("uluna"); - amountOfFee->set_amount("3000"); - - auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); - input.set_private_key(privateKey.data(), privateKey.size()); - - auto output = Signer::sign(input, TWCoinTypeTerra); - - // https://finder.terra.money/mainnet/tx/078E90458061611F6FD8B708882B55FF5C1FFB3FCE61322107A0A0DE39FC0F3E - // curl -H 'Content-Type: application/json' --data-binary '{"mode": "block","tx":{...}}' https:///txs - assertJSONEqual(output.json(), R"( - { - "mode": "block", - "tx": - { - "fee": {"amount":[{"amount": "3000","denom": "uluna"}],"gas": "200000"}, - "memo": "", - "msg": - [ - { - "type": "wasm/MsgExecuteContract", - "value": - { - "sender": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", - "contract": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", - "execute_msg": - { - "transfer": - { - "amount": "250000", - "recipient": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" - } - }, - "coins": [] - } - } - ], - "signatures": - [ - { - "pub_key": - { - "type": "tendermint/PubKeySecp256k1", - "value": "A3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awA" - }, - "signature": "BjETdtbA97Wv1zvcsCV1tM+bdYKC8O3uGTk4mMRv6pBJB2y/Ds7qoS7s/zrkhYak1YChklQetHsI30XRXzGIkg==" - } - ] - } - })"); - EXPECT_EQ(hex(output.signature()), "06311376d6c0f7b5afd73bdcb02575b4cf9b758282f0edee19393898c46fea9049076cbf0eceeaa12eecff3ae48586a4d580a192541eb47b08df45d15f318892"); - EXPECT_EQ(output.serialized(), ""); - EXPECT_EQ(output.error(), ""); -} - -TEST(TerraClassicSigner, SignWasmGeneric_EC4F85) { - auto input = Proto::SigningInput(); - input.set_signing_mode(Proto::Protobuf); - input.set_account_number(3407705); - input.set_chain_id("columbus-5"); - input.set_memo(""); - input.set_sequence(7); - - Address fromAddress; - ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); - Address toAddress; - ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); - const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC - const auto txMessage = R"({"transfer": { "amount": "250000", "recipient": "terra1d7048csap4wzcv5zm7z6tdqem2agyp9647vdyj" } })"; - - auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_terra_execute_contract_generic(); - message.set_sender_address(fromAddress.string()); - message.set_contract_address(tokenContractAddress); - message.set_execute_msg(txMessage); - - auto& fee = *input.mutable_fee(); - fee.set_gas(200000); - auto amountOfFee = fee.add_amounts(); - amountOfFee->set_denom("uluna"); - amountOfFee->set_amount("3000"); - - auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); - input.set_private_key(privateKey.data(), privateKey.size()); - - auto output = Signer::sign(input, TWCoinTypeTerra); - - // https://finder.terra.money/mainnet/tx/EC4F8532847E4D6AF016E6F6D3F027AE7FB6FF0B533C5132B01382D83B214A6F - // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "Cu4BC...iVt"})' https:///cosmos/tx/v1beta1/txs - assertJSONEqual(output.serialized(), R"( - { - "tx_bytes": "Cu4BCusBCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLAAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2GmJ7InRyYW5zZmVyIjogeyAiYW1vdW50IjogIjI1MDAwMCIsICJyZWNpcGllbnQiOiAidGVycmExZDcwNDhjc2FwNHd6Y3Y1em03ejZ0ZHFlbTJhZ3lwOTY0N3ZkeWoiIH0gfRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYBxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAkPsS7xlSng2LMc9KiD1soN5NLaDcUh8I9okPmsdJN3le1B7yxRGNB4aQfhaRl/8Z0r5vitRT0AWuxDasd8wcFw==", - "mode": "BROADCAST_MODE_BLOCK" - } - )"); - - EXPECT_EQ(hex(output.signature()), "90fb12ef19529e0d8b31cf4a883d6ca0de4d2da0dc521f08f6890f9ac74937795ed41ef2c5118d0786907e169197ff19d2be6f8ad453d005aec436ac77cc1c17"); - EXPECT_EQ(output.json(), ""); - EXPECT_EQ(output.error(), ""); -} - -TEST(TerraClassicSigner, SignWasmGenericWithCoins_6651FC) { - auto input = Proto::SigningInput(); - input.set_signing_mode(Proto::Protobuf); - input.set_account_number(3407705); - input.set_chain_id("columbus-5"); - input.set_memo(""); - input.set_sequence(9); - - Address fromAddress; - ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); - Address toAddress; - ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); - const auto tokenContractAddress = "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s"; // ANC Market - const auto txMessage = R"({ "deposit_stable": {} })"; - - auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_terra_execute_contract_generic(); - message.set_sender_address(fromAddress.string()); - message.set_contract_address(tokenContractAddress); - message.set_execute_msg(txMessage); - - auto amount = message.add_coins(); - amount->set_denom("uusd"); - amount->set_amount("1000"); - - auto& fee = *input.mutable_fee(); - fee.set_gas(600000); - auto amountOfFee = fee.add_amounts(); - amountOfFee->set_denom("uluna"); - amountOfFee->set_amount("7000"); - - auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); - input.set_private_key(privateKey.data(), privateKey.size()); - - auto output = Signer::sign(input, TWCoinTypeTerra); - - // https://finder.terra.money/mainnet/tx/6651FCE0EE5C6D6ACB655CC49A6FD5E939FB082862854616EA0642475BCDD0C9 - // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "CrIBCq8B.....0NWg=="})' https:///cosmos/tx/v1beta1/txs - assertJSONEqual(output.serialized(), R"( - { - "tx_bytes": "CrIBCq8BCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBKEAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMXNlcGZqN3MwYWVnNTk2N3V4bmZrNHRoemxlcnJza3RrcGVsbTVzGhh7ICJkZXBvc2l0X3N0YWJsZSI6IHt9IH0qDAoEdXVzZBIEMTAwMBJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYCRITCg0KBXVsdW5hEgQ3MDAwEMDPJBpAGyi7f1ioY8XV6pjFq1s86Om4++CIUnd3rLHif2iopCcYvX0mLkTlQ6NUERg8nWTYgXcj6fOTO/ptgPuAtv0NWg==", - "mode": "BROADCAST_MODE_BLOCK" - } - )"); - - EXPECT_EQ(hex(output.signature()), "1b28bb7f58a863c5d5ea98c5ab5b3ce8e9b8fbe088527777acb1e27f68a8a42718bd7d262e44e543a35411183c9d64d8817723e9f3933bfa6d80fb80b6fd0d5a"); - EXPECT_EQ(output.json(), ""); - EXPECT_EQ(output.error(), ""); -} - -TEST(TerraClassicSigner, SignWasmSendTxProtobuf) { - auto input = Proto::SigningInput(); - input.set_signing_mode(Proto::Protobuf); - input.set_account_number(3407705); - input.set_chain_id("columbus-5"); - input.set_memo(""); - input.set_sequence(4); - - Address fromAddress; - ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); - Address toAddress; - ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); - const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; // ANC - - auto msg = input.add_messages(); - auto& message = *msg->mutable_wasm_terra_execute_contract_send_message(); - message.set_sender_address(fromAddress.string()); - message.set_contract_address(tokenContractAddress); - const auto amount = store(uint256_t(250000), 0); - message.set_amount(amount.data(), amount.size()); - message.set_recipient_contract_address(toAddress.string()); - const auto msgMsg = Base64::encode(data(std::string(R"({"some_message":{}})"))); - EXPECT_EQ(msgMsg, "eyJzb21lX21lc3NhZ2UiOnt9fQ=="); - message.set_msg(msgMsg); - - auto& fee = *input.mutable_fee(); - fee.set_gas(200000); - auto amountOfFee = fee.add_amounts(); - amountOfFee->set_denom("uluna"); - amountOfFee->set_amount("3000"); - - std::string json; - google::protobuf::util::MessageToJsonString(input, &json); - assertJSONEqual(json, R"( - { - "signingMode": "Protobuf", - "accountNumber": "3407705", - "chainId": "columbus-5", - "fee": { - "amounts": [ - { - "denom": "uluna", - "amount": "3000" - } - ], - "gas": "200000" - }, - "sequence": "4", - "messages": [ - { - "wasmTerraExecuteContractSendMessage": { - "senderAddress": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", - "contractAddress": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", - "amount": "A9CQ", - "recipientContractAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", - "msg": "eyJzb21lX21lc3NhZ2UiOnt9fQ==" - } - } - ] - } - )"); - - auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); - input.set_private_key(privateKey.data(), privateKey.size()); - - auto output = Signer::sign(input, TWCoinTypeTerra); - - // https://finder.terra.money/mainnet/tx/9FF3F0A16879254C22EB90D8B4D6195467FE5014381FD36BD3C23CA6698FE94B - // curl -H 'Content-Type: application/json' --data-binary '{"mode": "BROADCAST_MODE_BLOCK","tx_bytes": "CogCCo..wld8"})' https:///cosmos/tx/v1beta1/txs - assertJSONEqual(output.serialized(), R"( - { - "tx_bytes": "CocCCoQCCiYvdGVycmEud2FzbS52MWJldGExLk1zZ0V4ZWN1dGVDb250cmFjdBLZAQosdGVycmExOHd1a3A4NGRxMjI3d3U0bWdoMGptNm45bmxuajZyczgycHA5d2YSLHRlcnJhMTR6NTZsMGZwMmxzZjg2enkzaHR5Mno0N2V6a2hudGh0cjl5cTc2Gnt7InNlbmQiOnsiYW1vdW50IjoiMjUwMDAwIiwiY29udHJhY3QiOiJ0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcCIsIm1zZyI6ImV5SnpiMjFsWDIxbGMzTmhaMlVpT250OWZRPT0ifX0SZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awAEgQKAggBGAQSEwoNCgV1bHVuYRIEMzAwMBDAmgwaQL6NByKeRZsyq5g6CTMdmPqiM77nOe9uLO8FjpetFgkBFiG3Le7ieZZ+4vCMhD1bcFgMwSHibFI/uPil847U/+g=", - "mode": "BROADCAST_MODE_BLOCK" - } - )"); - EXPECT_EQ(hex(output.signature()), "be8d07229e459b32ab983a09331d98faa233bee739ef6e2cef058e97ad1609011621b72deee279967ee2f08c843d5b70580cc121e26c523fb8f8a5f38ed4ffe8"); - EXPECT_EQ(output.json(), ""); - EXPECT_EQ(output.error(), ""); -} - -TEST(TerraClassicSigner, SignWasmTerraTransferPayload) { - auto proto = Proto::Message_WasmTerraExecuteContractTransfer(); - proto.set_recipient_address("recipient=address"); - const auto amount = store(uint256_t(250000), 0); - proto.set_amount(amount.data(), amount.size()); - - const auto payload = Protobuf::wasmTerraExecuteTransferPayload(proto); - - assertJSONEqual(payload.dump(), R"( - { - "transfer": - { - "amount": "250000", - "recipient": "recipient=address" - } - } - )"); -} - -} // namespace TW::Cosmos::tests \ No newline at end of file diff --git a/tests/Terra/TWCoinTypeTests.cpp b/tests/Terra/TWCoinTypeTests.cpp index b812faa478a..e46e7c58f0c 100644 --- a/tests/Terra/TWCoinTypeTests.cpp +++ b/tests/Terra/TWCoinTypeTests.cpp @@ -1,37 +1,14 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -// -// This is a GENERATED FILE, changes made here MAY BE LOST. -// Generated one-time (codegen/bin/cointests) -// #include "../interface/TWTestUtilities.h" #include #include - -TEST(TWTerraCoinType, TWCoinType20) { - auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeTerraV2)); - auto txId = WRAPS(TWStringCreateWithUTF8Bytes("CFF732C6EBEE06FFA08ABE54EE1657FD53E90FAA81604619E2062C46572A6986")); - auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeTerraV2, txId.get())); - auto accId = WRAPS(TWStringCreateWithUTF8Bytes("terra16t3gx5rqvz6ru37yzn3shuu20erv4ngmfr59zf")); - auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeTerraV2, accId.get())); - auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeTerraV2)); - auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeTerraV2)); - - ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeTerraV2), 6); - ASSERT_EQ(TWBlockchainCosmos, TWCoinTypeBlockchain(TWCoinTypeTerraV2)); - ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeTerraV2)); - ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeTerraV2)); - assertStringsEqual(symbol, "LUNA"); - assertStringsEqual(txUrl, "https://finder.terra.money/mainnet/tx/CFF732C6EBEE06FFA08ABE54EE1657FD53E90FAA81604619E2062C46572A6986"); - assertStringsEqual(accUrl, "https://finder.terra.money/mainnet/address/terra16t3gx5rqvz6ru37yzn3shuu20erv4ngmfr59zf"); - assertStringsEqual(id, "terrav2"); - assertStringsEqual(name, "Terra"); -} +namespace TW::Cosmos::tests { TEST(TWTerraCoinType, TWCoinTypeClassic) { auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeTerra)); @@ -54,3 +31,5 @@ TEST(TWTerraCoinType, TWCoinTypeClassic) { assertStringsEqual(id, "terra"); assertStringsEqual(name, "Terra Classic"); } + +} // namespace TW::Cosmos::tests diff --git a/tests/TerraV2/SignerTests.cpp b/tests/TerraV2/SignerTests.cpp new file mode 100644 index 00000000000..4978a5c4405 --- /dev/null +++ b/tests/TerraV2/SignerTests.cpp @@ -0,0 +1,362 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "Base64.h" +#include "proto/Cosmos.pb.h" +#include "Cosmos/Address.h" +#include "Cosmos/Signer.h" +#include "Cosmos/ProtobufSerialization.h" +#include "uint256.h" +#include "../interface/TWTestUtilities.h" + +#include +#include + +namespace TW::Cosmos::tests { + +TEST(TerraSigner, SignSendTx) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(1037); + input.set_chain_id("phoenix-1"); + input.set_memo(""); + input.set_sequence(1); + + Address fromAddress; + ASSERT_TRUE(Address::decode("terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2", fromAddress)); + Address toAddress; + ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_send_coins_message(); + message.set_from_address(fromAddress.string()); + message.set_to_address(toAddress.string()); + auto amountOfTx = message.add_amounts(); + amountOfTx->set_denom("uluna"); + amountOfTx->set_amount("1000000"); + + auto& fee = *input.mutable_fee(); + fee.set_gas(200000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uluna"); + amountOfFee->set_amount("30000"); + + { + std::string json; + google::protobuf::util::MessageToJsonString(input, &json); + assertJSONEqual(json, R"( + { + "signingMode": "Protobuf", + "accountNumber": "1037", + "chainId": "phoenix-1", + "fee": { + "amounts": [ + { + "denom": "uluna", + "amount": "30000" + } + ], + "gas": "200000" + }, + "sequence": "1", + "messages": [ + { + "sendCoinsMessage": { + "fromAddress": "terra1hsk6jryyqjfhp5dhc55tc9jtckygx0ep37hdd2", + "toAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", + "amounts": [ + { + "denom": "uluna", + "amount": "1000000" + } + ] + } + } + ] + } + )"); + } + + auto privateKey = parse_hex("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerraV2); + + // similar tx: https://finder.terra.money/mainnet/tx/fbbe73ad2f0db3a13911dc424f8a34370dc4b7e8b66687f536797e68ee200ece + assertJSONEqual(output.serialized(), R"( + { + "tx_bytes": "CpEBCo4BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm4KLHRlcnJhMWhzazZqcnl5cWpmaHA1ZGhjNTV0YzlqdGNreWd4MGVwMzdoZGQyEix0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcBoQCgV1bHVuYRIHMTAwMDAwMBJoClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiECVyhuw/N9M1V7u6oACyd0SskCOqmWfK51oYHR/5H6ncUSBAoCCAEYARIUCg4KBXVsdW5hEgUzMDAwMBDAmgwaQPh0C3rjzdixIUiyPx3FlWAxzbKILNAcSRVeQnaTl1vsI5DEfYa2oYlUBLqyilcMCcU/iaJLhex30No2ak0Zn1Q=", + "mode": "BROADCAST_MODE_BLOCK" + } + )"); + EXPECT_EQ(hex(output.signature()), "f8740b7ae3cdd8b12148b23f1dc5956031cdb2882cd01c49155e427693975bec2390c47d86b6a1895404bab28a570c09c53f89a24b85ec77d0da366a4d199f54"); + EXPECT_EQ(output.error(), ""); + EXPECT_EQ(output.json(), ""); +} + +TEST(TerraSigner, SignWasmTransferTx) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(3407705); + input.set_chain_id("phoenix-1"); + input.set_memo(""); + input.set_sequence(3); + + Address fromAddress; + ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); + Address toAddress; + ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; + + auto msg = input.add_messages(); + auto& message = *msg->mutable_wasm_execute_contract_transfer_message(); + message.set_sender_address(fromAddress.string()); + message.set_contract_address(tokenContractAddress); + const auto amount = store(uint256_t(250000), 0); + message.set_amount(amount.data(), amount.size()); + message.set_recipient_address(toAddress.string()); + + auto& fee = *input.mutable_fee(); + fee.set_gas(200000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uluna"); + amountOfFee->set_amount("3000"); + + { + std::string json; + google::protobuf::util::MessageToJsonString(input, &json); + assertJSONEqual(json, R"( + { + "signingMode": "Protobuf", + "accountNumber": "3407705", + "chainId": "phoenix-1", + "fee": { + "amounts": [ + { + "denom": "uluna", + "amount": "3000" + } + ], + "gas": "200000" + }, + "sequence": "3", + "messages": [ + { + "wasmExecuteContractTransferMessage": { + "senderAddress": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", + "contractAddress": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", + "amount": "A9CQ", + "recipientAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp" + } + } + ] + } + )"); + } + + auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerraV2); + + assertJSONEqual(output.serialized(), R"( + { + "tx_bytes": "CuUBCuIBCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QSuQEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTE0ejU2bDBmcDJsc2Y4Nnp5M2h0eTJ6NDdlemtobnRodHI5eXE3NhpbeyJ0cmFuc2ZlciI6eyJhbW91bnQiOiIyNTAwMDAiLCJyZWNpcGllbnQiOiJ0ZXJyYTFqbGdhcXk5bnZuMmhmNXQyc3JhOXljejhzNzd3bmY5bDBrbWdjcCJ9fRJnClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDcGY6x7D5iSlv61zln7pKUNfpThziVt/yJRRZyizZrAASBAoCCAEYAxITCg0KBXVsdW5hEgQzMDAwEMCaDBpAiBGbQaj+jsXE6/FssD3fC77QOxpli9GqsPea+KoNyMIEgVj89Hii+oU1bAEQS4qV0SaE2V6RNy24uCcFTIRbcQ==", + "mode": "BROADCAST_MODE_BLOCK" + } + )"); + EXPECT_EQ(hex(output.signature()), "88119b41a8fe8ec5c4ebf16cb03ddf0bbed03b1a658bd1aab0f79af8aa0dc8c2048158fcf478a2fa85356c01104b8a95d12684d95e91372db8b827054c845b71"); + EXPECT_EQ(output.error(), ""); + EXPECT_EQ(output.json(), ""); +} + +TEST(TerraSigner, SignWasmGeneric) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(3407705); + input.set_chain_id("phoenix-1"); + input.set_memo(""); + input.set_sequence(7); + + Address fromAddress; + ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; + const auto txMessage = R"({"transfer": { "amount": "250000", "recipient": "terra1d7048csap4wzcv5zm7z6tdqem2agyp9647vdyj" } })"; + + auto msg = input.add_messages(); + auto& message = *msg->mutable_wasm_execute_contract_generic(); + message.set_sender_address(fromAddress.string()); + message.set_contract_address(tokenContractAddress); + message.set_execute_msg(txMessage); + + auto& fee = *input.mutable_fee(); + fee.set_gas(200000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uluna"); + amountOfFee->set_amount("3000"); + + auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerraV2); + + assertJSONEqual(output.serialized(), R"( + { + "tx_bytes": "CuwBCukBCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QSwAEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTE0ejU2bDBmcDJsc2Y4Nnp5M2h0eTJ6NDdlemtobnRodHI5eXE3NhpieyJ0cmFuc2ZlciI6IHsgImFtb3VudCI6ICIyNTAwMDAiLCAicmVjaXBpZW50IjogInRlcnJhMWQ3MDQ4Y3NhcDR3emN2NXptN3o2dGRxZW0yYWd5cDk2NDd2ZHlqIiB9IH0SZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awAEgQKAggBGAcSEwoNCgV1bHVuYRIEMzAwMBDAmgwaQGlYzOoAu/PfyCTSTisGJVW9KWwifxMbCmzy2xwqNg+ZHQkDjVRyUBl7gmbXXLzdOMqtwF1CMauJhlGwmEdzhK4=", + "mode": "BROADCAST_MODE_BLOCK" + } + )"); + + EXPECT_EQ(hex(output.signature()), "6958ccea00bbf3dfc824d24e2b062555bd296c227f131b0a6cf2db1c2a360f991d09038d547250197b8266d75cbcdd38caadc05d4231ab898651b098477384ae"); + EXPECT_EQ(output.error(), ""); + EXPECT_EQ(output.json(), ""); +} + +TEST(TerraSigner, SignWasmGenericWithCoins) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(3407705); + input.set_chain_id("phoenix-1"); + input.set_memo(""); + input.set_sequence(9); + + Address fromAddress; + ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); + const auto tokenContractAddress = "terra1sepfj7s0aeg5967uxnfk4thzlerrsktkpelm5s"; + const auto txMessage = R"({ "deposit_stable": {} })"; + + auto msg = input.add_messages(); + auto& message = *msg->mutable_wasm_execute_contract_generic(); + message.set_sender_address(fromAddress.string()); + message.set_contract_address(tokenContractAddress); + message.set_execute_msg(txMessage); + + auto amount = message.add_coins(); + amount->set_denom("uusd"); + amount->set_amount("1000"); + + auto& fee = *input.mutable_fee(); + fee.set_gas(600000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uluna"); + amountOfFee->set_amount("7000"); + + auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerraV2); + + assertJSONEqual(output.serialized(), R"( + { + "tx_bytes": "CrABCq0BCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QShAEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTFzZXBmajdzMGFlZzU5Njd1eG5mazR0aHpsZXJyc2t0a3BlbG01cxoYeyAiZGVwb3NpdF9zdGFibGUiOiB7fSB9KgwKBHV1c2QSBDEwMDASZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA3BmOsew+Ykpb+tc5Z+6SlDX6U4c4lbf8iUUWcos2awAEgQKAggBGAkSEwoNCgV1bHVuYRIENzAwMBDAzyQaQEDA2foXegF+rslj6o8bX2HPJfn+q/6Ezbq2iAd0SFOTQqS8aAyywQkdZJRToXcaby1HOYL1WvmsMPgrFzChiY4=", + "mode": "BROADCAST_MODE_BLOCK" + } + )"); + + EXPECT_EQ(hex(output.signature()), "40c0d9fa177a017eaec963ea8f1b5f61cf25f9feabfe84cdbab688077448539342a4bc680cb2c1091d649453a1771a6f2d473982f55af9ac30f82b1730a1898e"); + EXPECT_EQ(output.error(), ""); + EXPECT_EQ(output.json(), ""); +} + +TEST(TerraSigner, SignWasmSendTx) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(3407705); + input.set_chain_id("phoenix-1"); + input.set_memo(""); + input.set_sequence(4); + + Address fromAddress; + ASSERT_TRUE(Address::decode("terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", fromAddress)); + Address toAddress; + ASSERT_TRUE(Address::decode("terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", toAddress)); + const auto tokenContractAddress = "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76"; + + auto msg = input.add_messages(); + auto& message = *msg->mutable_wasm_execute_contract_send_message(); + message.set_sender_address(fromAddress.string()); + message.set_contract_address(tokenContractAddress); + const auto amount = store(uint256_t(250000), 0); + message.set_amount(amount.data(), amount.size()); + message.set_recipient_contract_address(toAddress.string()); + const auto msgMsg = Base64::encode(data(std::string(R"({"some_message":{}})"))); + EXPECT_EQ(msgMsg, "eyJzb21lX21lc3NhZ2UiOnt9fQ=="); + message.set_msg(msgMsg); + + auto& fee = *input.mutable_fee(); + fee.set_gas(200000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uluna"); + amountOfFee->set_amount("3000"); + + std::string json; + google::protobuf::util::MessageToJsonString(input, &json); + assertJSONEqual(json, R"( + { + "signingMode": "Protobuf", + "accountNumber": "3407705", + "chainId": "phoenix-1", + "fee": { + "amounts": [ + { + "denom": "uluna", + "amount": "3000" + } + ], + "gas": "200000" + }, + "sequence": "4", + "messages": [ + { + "wasmExecuteContractSendMessage": { + "senderAddress": "terra18wukp84dq227wu4mgh0jm6n9nlnj6rs82pp9wf", + "contractAddress": "terra14z56l0fp2lsf86zy3hty2z47ezkhnthtr9yq76", + "amount": "A9CQ", + "recipientContractAddress": "terra1jlgaqy9nvn2hf5t2sra9ycz8s77wnf9l0kmgcp", + "msg": "eyJzb21lX21lc3NhZ2UiOnt9fQ==" + } + } + ] + } + )"); + + auto privateKey = parse_hex("cf08ee8493e6f6a53f9721b9045576e80f371c0e36d08fdaf78b27a7afd8e616"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeTerraV2); + + assertJSONEqual(output.serialized(), R"( + { + "tx_bytes": "CoUCCoICCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QS2QEKLHRlcnJhMTh3dWtwODRkcTIyN3d1NG1naDBqbTZuOW5sbmo2cnM4MnBwOXdmEix0ZXJyYTE0ejU2bDBmcDJsc2Y4Nnp5M2h0eTJ6NDdlemtobnRodHI5eXE3Nhp7eyJzZW5kIjp7ImFtb3VudCI6IjI1MDAwMCIsImNvbnRyYWN0IjoidGVycmExamxnYXF5OW52bjJoZjV0MnNyYTl5Y3o4czc3d25mOWwwa21nY3AiLCJtc2ciOiJleUp6YjIxbFgyMWxjM05oWjJVaU9udDlmUT09In19EmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNwZjrHsPmJKW/rXOWfukpQ1+lOHOJW3/IlFFnKLNmsABIECgIIARgEEhMKDQoFdWx1bmESBDMwMDAQwJoMGkBKJbW1GDrv9j2FIckm7MtpDZzP2RjgDjU84oYmOHNHsxEBPLjtt3YAjsKWBCAsjbnbVoJ3s2XFG08nxQXS9xBK", + "mode": "BROADCAST_MODE_BLOCK" + } + )"); + EXPECT_EQ(hex(output.signature()), "4a25b5b5183aeff63d8521c926eccb690d9ccfd918e00e353ce28626387347b311013cb8edb776008ec29604202c8db9db568277b365c51b4f27c505d2f7104a"); + EXPECT_EQ(output.error(), ""); + EXPECT_EQ(output.json(), ""); +} + +TEST(TerraSigner, SignWasmTransferPayload) { + auto proto = Proto::Message_WasmExecuteContractTransfer(); + proto.set_recipient_address("recipient=address"); + const auto amount = store(uint256_t(250000), 0); + proto.set_amount(amount.data(), amount.size()); + + const auto payload = Protobuf::wasmExecuteTransferPayload(proto); + + assertJSONEqual(payload.dump(), R"( + { + "transfer": + { + "amount": "250000", + "recipient": "recipient=address" + } + } + )"); +} + +} // namespace TW::Cosmos::tests diff --git a/tests/TerraV2/TWCoinTypeTests.cpp b/tests/TerraV2/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..96c27cff876 --- /dev/null +++ b/tests/TerraV2/TWCoinTypeTests.cpp @@ -0,0 +1,34 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "../interface/TWTestUtilities.h" +#include +#include + +namespace TW::Cosmos::tests { + +TEST(TWTerraCoinType, TWCoinType20) { + auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeTerraV2)); + auto txId = WRAPS(TWStringCreateWithUTF8Bytes("CFF732C6EBEE06FFA08ABE54EE1657FD53E90FAA81604619E2062C46572A6986")); + auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeTerraV2, txId.get())); + auto accId = WRAPS(TWStringCreateWithUTF8Bytes("terra16t3gx5rqvz6ru37yzn3shuu20erv4ngmfr59zf")); + auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeTerraV2, accId.get())); + auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeTerraV2)); + auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeTerraV2)); + + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeTerraV2), 6); + ASSERT_EQ(TWBlockchainCosmos, TWCoinTypeBlockchain(TWCoinTypeTerraV2)); + ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeTerraV2)); + ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeTerraV2)); + assertStringsEqual(symbol, "LUNA"); + assertStringsEqual(txUrl, "https://finder.terra.money/mainnet/tx/CFF732C6EBEE06FFA08ABE54EE1657FD53E90FAA81604619E2062C46572A6986"); + assertStringsEqual(accUrl, "https://finder.terra.money/mainnet/address/terra16t3gx5rqvz6ru37yzn3shuu20erv4ngmfr59zf"); + assertStringsEqual(id, "terrav2"); + assertStringsEqual(name, "Terra"); +} + +} // namespace TW::Cosmos::tests + diff --git a/tests/Ripple/AddressTests.cpp b/tests/XRP/AddressTests.cpp similarity index 97% rename from tests/Ripple/AddressTests.cpp rename to tests/XRP/AddressTests.cpp index 9af08ceccb1..591b2842123 100644 --- a/tests/Ripple/AddressTests.cpp +++ b/tests/XRP/AddressTests.cpp @@ -4,8 +4,8 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Ripple/Address.h" -#include "Ripple/XAddress.h" +#include "XRP/Address.h" +#include "XRP/XAddress.h" #include "HexCoding.h" #include diff --git a/tests/Ripple/TWAnySignerTests.cpp b/tests/XRP/TWAnySignerTests.cpp similarity index 100% rename from tests/Ripple/TWAnySignerTests.cpp rename to tests/XRP/TWAnySignerTests.cpp diff --git a/tests/Ripple/TWCoinTypeTests.cpp b/tests/XRP/TWCoinTypeTests.cpp similarity index 100% rename from tests/Ripple/TWCoinTypeTests.cpp rename to tests/XRP/TWCoinTypeTests.cpp diff --git a/tests/Ripple/TWRippleAddressTests.cpp b/tests/XRP/TWRippleAddressTests.cpp similarity index 100% rename from tests/Ripple/TWRippleAddressTests.cpp rename to tests/XRP/TWRippleAddressTests.cpp diff --git a/tests/Ripple/TransactionTests.cpp b/tests/XRP/TransactionTests.cpp similarity index 98% rename from tests/Ripple/TransactionTests.cpp rename to tests/XRP/TransactionTests.cpp index 9b14781f5f4..f9015b684da 100644 --- a/tests/Ripple/TransactionTests.cpp +++ b/tests/XRP/TransactionTests.cpp @@ -4,9 +4,9 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "Ripple/Address.h" -#include "Ripple/Transaction.h" -#include "Ripple/BinaryCoding.h" +#include "XRP/Address.h" +#include "XRP/Transaction.h" +#include "XRP/BinaryCoding.h" #include "HexCoding.h" #include "PrivateKey.h" #include "PublicKey.h" From 102e3d75b304cece941de8985bddba9f0388c814 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 22 Sep 2022 07:23:46 +0200 Subject: [PATCH 088/497] [Improvements]: various clang-tidy fixes and typo (#2578) * fix(clang-tidy): various clang-tidy fixes and typo * fix(clang-tidy): apply tidy fixes on Algorand code * fix(clang-tidy): apply tidy fixes on Binance code * fix(clang-tidy): apply tidy fixes on Bitcoin code * Apply suggestions from code review Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- src/Aeternity/Address.cpp | 2 - src/Aeternity/Signer.cpp | 1 - src/Aeternity/Transaction.h | 2 +- src/Aion/Address.cpp | 1 - src/Aion/RLP.h | 2 +- src/Aion/Signer.cpp | 2 - src/Aion/Transaction.cpp | 1 - src/Algorand/OptInAssetTransaction.h | 4 +- src/Algorand/Signer.cpp | 2 +- src/Algorand/Transfer.h | 4 +- src/Binance/Entry.cpp | 3 +- src/Binance/Signer.cpp | 4 +- src/Binance/Signer.h | 3 +- src/Bitcoin/Amount.h | 6 - src/Bitcoin/Entry.cpp | 4 +- src/Bitcoin/InputSelector.h | 2 +- src/Bitcoin/OpCodes.h | 198 +++++++++++++-------------- src/Bitcoin/Script.h | 9 +- src/Bitcoin/SignatureBuilder.cpp | 10 +- src/Bitcoin/SignatureBuilder.h | 7 +- src/Bitcoin/SignatureVersion.h | 2 +- src/Bitcoin/Transaction.cpp | 2 +- src/Bitcoin/TransactionBuilder.cpp | 5 +- 23 files changed, 134 insertions(+), 142 deletions(-) diff --git a/src/Aeternity/Address.cpp b/src/Aeternity/Address.cpp index af8e7e1f8d9..b3d0ecc64fb 100644 --- a/src/Aeternity/Address.cpp +++ b/src/Aeternity/Address.cpp @@ -7,8 +7,6 @@ #include "Address.h" #include "Identifiers.h" #include -#include -#include namespace TW::Aeternity { diff --git a/src/Aeternity/Signer.cpp b/src/Aeternity/Signer.cpp index 2378aef1b63..ff27db8d81a 100644 --- a/src/Aeternity/Signer.cpp +++ b/src/Aeternity/Signer.cpp @@ -5,7 +5,6 @@ // file LICENSE at the root of the source code distribution tree. #include "Signer.h" -#include "Address.h" #include "Base58.h" #include "Base64.h" #include "HexCoding.h" diff --git a/src/Aeternity/Transaction.h b/src/Aeternity/Transaction.h index 6bace4629b8..a58db36f651 100644 --- a/src/Aeternity/Transaction.h +++ b/src/Aeternity/Transaction.h @@ -53,7 +53,7 @@ class Transaction { //// see https://github.com/aeternity/protocol/blob/epoch-v0.22.0/serializations.md#the-id-type static Data buildTag(const std::string& address); - /// Awternity network does not accept zero int values as rlp param, + /// Aeternity network does not accept zero int values as rlp param, /// instead empty byte array should be encoded /// see https://forum.aeternity.com/t/invalid-tx-error-on-mainnet-goggle-says-it-looks-good/4118/5?u=defuera static Data encodeSafeZero(uint256_t value); diff --git a/src/Aion/Address.cpp b/src/Aion/Address.cpp index e781c33b8fa..411a1b97d9e 100644 --- a/src/Aion/Address.cpp +++ b/src/Aion/Address.cpp @@ -5,7 +5,6 @@ // file LICENSE at the root of the source code distribution tree. #include "Address.h" -#include "../Hash.h" #include "../HexCoding.h" namespace TW::Aion { diff --git a/src/Aion/RLP.h b/src/Aion/RLP.h index b713b79c47a..55330d37a5a 100644 --- a/src/Aion/RLP.h +++ b/src/Aion/RLP.h @@ -17,7 +17,7 @@ namespace TW::Aion { -/// Aion's RLP encoging for long numbers +/// Aion's RLP encoding for long numbers /// https://github.com/aionnetwork/aion/issues/680 struct RLP { static Data encodeLong(boost::multiprecision::uint128_t l) noexcept { diff --git a/src/Aion/Signer.cpp b/src/Aion/Signer.cpp index fe1048b70e5..01c90385d91 100644 --- a/src/Aion/Signer.cpp +++ b/src/Aion/Signer.cpp @@ -5,8 +5,6 @@ // file LICENSE at the root of the source code distribution tree. #include "Signer.h" - -#include "../Hash.h" #include "../uint256.h" #include diff --git a/src/Aion/Transaction.cpp b/src/Aion/Transaction.cpp index 327441c1eb3..c108f0d4b37 100644 --- a/src/Aion/Transaction.cpp +++ b/src/Aion/Transaction.cpp @@ -6,7 +6,6 @@ #include "Transaction.h" #include "RLP.h" -#include "../Ethereum/RLP.h" using namespace TW; using boost::multiprecision::uint128_t; diff --git a/src/Algorand/OptInAssetTransaction.h b/src/Algorand/OptInAssetTransaction.h index 8616cbd8900..49d2a219213 100644 --- a/src/Algorand/OptInAssetTransaction.h +++ b/src/Algorand/OptInAssetTransaction.h @@ -6,6 +6,8 @@ #pragma once +#include + #include "Address.h" #include "BaseTransaction.h" #include "Data.h" @@ -31,7 +33,7 @@ class OptInAssetTransaction: public BaseTransaction { : address(address), fee(fee) , assetId(assetId), firstRound(firstRound) , lastRound(lastRound), note(note) - , type(type), genesisId(genesisId) + , type(std::move(type)), genesisId(genesisId) , genesisHash(genesisHash) {} public: diff --git a/src/Algorand/Signer.cpp b/src/Algorand/Signer.cpp index 3f24ba4801a..cfb615def50 100644 --- a/src/Algorand/Signer.cpp +++ b/src/Algorand/Signer.cpp @@ -75,7 +75,7 @@ Data Signer::sign(const PrivateKey& privateKey, const BaseTransaction& transacti append(data, TRANSACTION_TAG); append(data, transaction.serialize()); auto signature = privateKey.sign(data, TWCurveED25519); - return Data(signature.begin(), signature.end()); + return {signature.begin(), signature.end()}; } } // namespace TW::Algorand diff --git a/src/Algorand/Transfer.h b/src/Algorand/Transfer.h index dbf94ac2b48..422ae4d2e4d 100644 --- a/src/Algorand/Transfer.h +++ b/src/Algorand/Transfer.h @@ -6,6 +6,8 @@ #pragma once +#include + #include "Address.h" #include "BaseTransaction.h" #include "Data.h" @@ -32,7 +34,7 @@ class Transfer : public BaseTransaction { : from(from) , to(to) , fee(fee), amount(amount) , firstRound(firstRound), lastRound(lastRound) - , note(note), type(type) + , note(note), type(std::move(type)) , genesisId(genesisIdg), genesisHash(genesisHash) {} public: diff --git a/src/Binance/Entry.cpp b/src/Binance/Entry.cpp index e288581e3f6..48d39fc64c2 100644 --- a/src/Binance/Entry.cpp +++ b/src/Binance/Entry.cpp @@ -8,7 +8,6 @@ #include "../proto/TransactionCompiler.pb.h" #include "Address.h" -#include "Coin.h" #include "Signer.h" namespace TW::Binance { @@ -24,7 +23,7 @@ std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicK Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { Address addr; if (!Address::decode(address, addr)) { - return Data(); + return {}; } return addr.getKeyHash(); } diff --git a/src/Binance/Signer.cpp b/src/Binance/Signer.cpp index 81de18da848..5a06be40181 100644 --- a/src/Binance/Signer.cpp +++ b/src/Binance/Signer.cpp @@ -66,7 +66,7 @@ Data Signer::sign() const { auto hash = preImageHash(); auto key = PrivateKey(input.private_key()); auto signature = key.sign(hash, TWCurveSECP256k1); - return Data(signature.begin(), signature.end() - 1); + return {signature.begin(), signature.end() - 1}; } Data Signer::preImageHash() const { @@ -213,7 +213,7 @@ Data Signer::aminoWrap(const std::string& raw, const Data& typePrefix, bool pref cos.WriteRaw(raw.data(), static_cast(raw.size())); } - return Data(msg.begin(), msg.end()); + return {msg.begin(), msg.end()}; } } // namespace TW::Binance diff --git a/src/Binance/Signer.h b/src/Binance/Signer.h index aceb774d12e..d66b42bf774 100644 --- a/src/Binance/Signer.h +++ b/src/Binance/Signer.h @@ -11,6 +11,7 @@ #include "../proto/Binance.pb.h" #include +#include namespace TW::Binance { @@ -25,7 +26,7 @@ class Signer { Proto::SigningInput input; /// Initializes a transaction signer. - explicit Signer(const Proto::SigningInput& input) : input(input) {} + explicit Signer(Proto::SigningInput input) : input(std::move(input)) {} /// Builds a signed transaction. /// diff --git a/src/Bitcoin/Amount.h b/src/Bitcoin/Amount.h index aa3f9e8dfcb..d286003d75f 100644 --- a/src/Bitcoin/Amount.h +++ b/src/Bitcoin/Amount.h @@ -15,10 +15,4 @@ namespace TW::Bitcoin { /// Amount in satoshis (can be negative) using Amount = int64_t; -/// One bitcoin in satoshis -inline constexpr Amount gCoin = 100000000; - -/// Maxximum valid amount in satoshis. -inline constexpr Amount gMaxAmount = 21000000 * gCoin; - } // namespace TW::Bitcoin diff --git a/src/Bitcoin/Entry.cpp b/src/Bitcoin/Entry.cpp index 33301452f64..26816b632b7 100644 --- a/src/Bitcoin/Entry.cpp +++ b/src/Bitcoin/Entry.cpp @@ -115,7 +115,7 @@ Data Entry::addressToData(TWCoinType coin, const std::string& address) const { case TWCoinTypeViacoin: { const auto decoded = SegwitAddress::decode(address); if (!std::get<2>(decoded)) { - return Data(); + return {}; } return std::get<0>(decoded).witnessProgram; } @@ -137,7 +137,7 @@ Data Entry::addressToData(TWCoinType coin, const std::string& address) const { } default: - return Data(); + return {}; } } diff --git a/src/Bitcoin/InputSelector.h b/src/Bitcoin/InputSelector.h index 84970297eab..73298a69729 100644 --- a/src/Bitcoin/InputSelector.h +++ b/src/Bitcoin/InputSelector.h @@ -14,7 +14,7 @@ namespace TW::Bitcoin { -template // TypeWithAmount has to have a uint64_t amount +template // TypeWithAmount has to have an uint64_t amount class InputSelector { public: /// Selects unspent transactions to use given a target transaction value, using complete logic. diff --git a/src/Bitcoin/OpCodes.h b/src/Bitcoin/OpCodes.h index f3a4405d697..fa797be4b19 100644 --- a/src/Bitcoin/OpCodes.h +++ b/src/Bitcoin/OpCodes.h @@ -9,139 +9,139 @@ enum OpCode { // push value OP_0 = 0x00, - OP_FALSE = OP_0, + OP_FALSE [[maybe_unused]] = OP_0, OP_PUSHDATA1 = 0x4c, OP_PUSHDATA2 = 0x4d, OP_PUSHDATA4 = 0x4e, - OP_1NEGATE = 0x4f, - OP_RESERVED = 0x50, + OP_1NEGATE [[maybe_unused]] = 0x4f, + OP_RESERVED [[maybe_unused]] = 0x50, OP_1 = 0x51, - OP_TRUE = OP_1, - OP_2 = 0x52, + OP_TRUE [[maybe_unused]] = OP_1, + OP_2 [[maybe_unused]] = 0x52, OP_3 = 0x53, - OP_4 = 0x54, - OP_5 = 0x55, - OP_6 = 0x56, - OP_7 = 0x57, - OP_8 = 0x58, + OP_4 [[maybe_unused]] = 0x54, + OP_5 [[maybe_unused]] = 0x55, + OP_6 [[maybe_unused]] = 0x56, + OP_7 [[maybe_unused]] = 0x57, + OP_8 [[maybe_unused]] = 0x58, OP_9 = 0x59, - OP_10 = 0x5a, - OP_11 = 0x5b, - OP_12 = 0x5c, - OP_13 = 0x5d, - OP_14 = 0x5e, - OP_15 = 0x5f, + OP_10 [[maybe_unused]] = 0x5a, + OP_11 [[maybe_unused]] = 0x5b, + OP_12 [[maybe_unused]] = 0x5c, + OP_13 [[maybe_unused]] = 0x5d, + OP_14 [[maybe_unused]] = 0x5e, + OP_15 [[maybe_unused]] = 0x5f, OP_16 = 0x60, // control - OP_NOP = 0x61, - OP_VER = 0x62, - OP_IF = 0x63, - OP_NOTIF = 0x64, - OP_VERIF = 0x65, - OP_VERNOTIF = 0x66, - OP_ELSE = 0x67, - OP_ENDIF = 0x68, - OP_VERIFY = 0x69, + OP_NOP [[maybe_unused]] = 0x61, + OP_VER [[maybe_unused]] = 0x62, + OP_IF [[maybe_unused]] = 0x63, + OP_NOTIF [[maybe_unused]] = 0x64, + OP_VERIF [[maybe_unused]] = 0x65, + OP_VERNOTIF [[maybe_unused]] = 0x66, + OP_ELSE [[maybe_unused]] = 0x67, + OP_ENDIF [[maybe_unused]] = 0x68, + OP_VERIFY [[maybe_unused]] = 0x69, OP_RETURN = 0x6a, // stack ops - OP_TOALTSTACK = 0x6b, - OP_FROMALTSTACK = 0x6c, - OP_2DROP = 0x6d, - OP_2DUP = 0x6e, - OP_3DUP = 0x6f, - OP_2OVER = 0x70, - OP_2ROT = 0x71, - OP_2SWAP = 0x72, - OP_IFDUP = 0x73, - OP_DEPTH = 0x74, - OP_DROP = 0x75, + OP_TOALTSTACK [[maybe_unused]] = 0x6b, + OP_FROMALTSTACK [[maybe_unused]] = 0x6c, + OP_2DROP [[maybe_unused]] = 0x6d, + OP_2DUP [[maybe_unused]] = 0x6e, + OP_3DUP [[maybe_unused]] = 0x6f, + OP_2OVER [[maybe_unused]] = 0x70, + OP_2ROT [[maybe_unused]] = 0x71, + OP_2SWAP [[maybe_unused]] = 0x72, + OP_IFDUP [[maybe_unused]] = 0x73, + OP_DEPTH [[maybe_unused]] = 0x74, + OP_DROP [[maybe_unused]] = 0x75, OP_DUP = 0x76, - OP_NIP = 0x77, - OP_OVER = 0x78, - OP_PICK = 0x79, - OP_ROLL = 0x7a, - OP_ROT = 0x7b, - OP_SWAP = 0x7c, - OP_TUCK = 0x7d, + OP_NIP [[maybe_unused]] = 0x77, + OP_OVER [[maybe_unused]] = 0x78, + OP_PICK [[maybe_unused]] = 0x79, + OP_ROLL [[maybe_unused]] = 0x7a, + OP_ROT [[maybe_unused]] = 0x7b, + OP_SWAP [[maybe_unused]] = 0x7c, + OP_TUCK [[maybe_unused]] = 0x7d, // splice ops - OP_CAT = 0x7e, - OP_SUBSTR = 0x7f, - OP_LEFT = 0x80, - OP_RIGHT = 0x81, - OP_SIZE = 0x82, + OP_CAT [[maybe_unused]] = 0x7e, + OP_SUBSTR [[maybe_unused]] = 0x7f, + OP_LEFT [[maybe_unused]] = 0x80, + OP_RIGHT [[maybe_unused]] = 0x81, + OP_SIZE [[maybe_unused]] = 0x82, // bit logic - OP_INVERT = 0x83, - OP_AND = 0x84, - OP_OR = 0x85, - OP_XOR = 0x86, + OP_INVERT [[maybe_unused]] = 0x83, + OP_AND [[maybe_unused]] = 0x84, + OP_OR [[maybe_unused]] = 0x85, + OP_XOR [[maybe_unused]] = 0x86, OP_EQUAL = 0x87, OP_EQUALVERIFY = 0x88, - OP_RESERVED1 = 0x89, - OP_RESERVED2 = 0x8a, + OP_RESERVED1 [[maybe_unused]] = 0x89, + OP_RESERVED2 [[maybe_unused]] = 0x8a, // numeric - OP_1ADD = 0x8b, - OP_1SUB = 0x8c, - OP_2MUL = 0x8d, - OP_2DIV = 0x8e, - OP_NEGATE = 0x8f, - OP_ABS = 0x90, - OP_NOT = 0x91, - OP_0NOTEQUAL = 0x92, + OP_1ADD [[maybe_unused]] = 0x8b, + OP_1SUB [[maybe_unused]] = 0x8c, + OP_2MUL [[maybe_unused]] = 0x8d, + OP_2DIV [[maybe_unused]] = 0x8e, + OP_NEGATE [[maybe_unused]] = 0x8f, + OP_ABS [[maybe_unused]] = 0x90, + OP_NOT [[maybe_unused]] = 0x91, + OP_0NOTEQUAL [[maybe_unused]] = 0x92, - OP_ADD = 0x93, - OP_SUB = 0x94, - OP_MUL = 0x95, - OP_DIV = 0x96, - OP_MOD = 0x97, - OP_LSHIFT = 0x98, - OP_RSHIFT = 0x99, + OP_ADD [[maybe_unused]] = 0x93, + OP_SUB [[maybe_unused]] = 0x94, + OP_MUL [[maybe_unused]] = 0x95, + OP_DIV [[maybe_unused]] = 0x96, + OP_MOD [[maybe_unused]] = 0x97, + OP_LSHIFT [[maybe_unused]] = 0x98, + OP_RSHIFT [[maybe_unused]] = 0x99, - OP_BOOLAND = 0x9a, - OP_BOOLOR = 0x9b, - OP_NUMEQUAL = 0x9c, - OP_NUMEQUALVERIFY = 0x9d, - OP_NUMNOTEQUAL = 0x9e, - OP_LESSTHAN = 0x9f, - OP_GREATERTHAN = 0xa0, - OP_LESSTHANOREQUAL = 0xa1, - OP_GREATERTHANOREQUAL = 0xa2, - OP_MIN = 0xa3, - OP_MAX = 0xa4, + OP_BOOLAND [[maybe_unused]] = 0x9a, + OP_BOOLOR [[maybe_unused]] = 0x9b, + OP_NUMEQUAL [[maybe_unused]] = 0x9c, + OP_NUMEQUALVERIFY [[maybe_unused]] = 0x9d, + OP_NUMNOTEQUAL [[maybe_unused]] = 0x9e, + OP_LESSTHAN [[maybe_unused]] = 0x9f, + OP_GREATERTHAN [[maybe_unused]] = 0xa0, + OP_LESSTHANOREQUAL [[maybe_unused]] = 0xa1, + OP_GREATERTHANOREQUAL [[maybe_unused]] = 0xa2, + OP_MIN [[maybe_unused]] = 0xa3, + OP_MAX [[maybe_unused]] = 0xa4, - OP_WITHIN = 0xa5, + OP_WITHIN [[maybe_unused]] = 0xa5, // crypto - OP_RIPEMD160 = 0xa6, - OP_SHA1 = 0xa7, - OP_SHA256 = 0xa8, + OP_RIPEMD160 [[maybe_unused]] = 0xa6, + OP_SHA1 [[maybe_unused]] = 0xa7, + OP_SHA256 [[maybe_unused]] = 0xa8, OP_HASH160 = 0xa9, - OP_HASH256 = 0xaa, - OP_CODESEPARATOR = 0xab, + OP_HASH256 [[maybe_unused]] = 0xaa, + OP_CODESEPARATOR [[maybe_unused]] = 0xab, OP_CHECKSIG = 0xac, - OP_CHECKSIGVERIFY = 0xad, + OP_CHECKSIGVERIFY [[maybe_unused]] = 0xad, OP_CHECKMULTISIG = 0xae, - OP_CHECKMULTISIGVERIFY = 0xaf, + OP_CHECKMULTISIGVERIFY [[maybe_unused]] = 0xaf, // expansion - OP_NOP1 = 0xb0, + OP_NOP1 [[maybe_unused]] = 0xb0, OP_CHECKLOCKTIMEVERIFY = 0xb1, - OP_NOP2 = OP_CHECKLOCKTIMEVERIFY, + OP_NOP2 [[maybe_unused]] = OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY = 0xb2, - OP_NOP3 = OP_CHECKSEQUENCEVERIFY, - OP_NOP4 = 0xb3, - OP_NOP5 = 0xb4, - OP_NOP6 = 0xb5, - OP_NOP7 = 0xb6, - OP_NOP8 = 0xb7, - OP_NOP9 = 0xb8, - OP_NOP10 = 0xb9, + OP_NOP3 [[maybe_unused]] = OP_CHECKSEQUENCEVERIFY, + OP_NOP4 [[maybe_unused]] = 0xb3, + OP_NOP5 [[maybe_unused]] = 0xb4, + OP_NOP6 [[maybe_unused]] = 0xb5, + OP_NOP7 [[maybe_unused]] = 0xb6, + OP_NOP8 [[maybe_unused]] = 0xb7, + OP_NOP9 [[maybe_unused]] = 0xb8, + OP_NOP10 [[maybe_unused]] = 0xb9, - OP_INVALIDOPCODE = 0xff, + OP_INVALIDOPCODE [[maybe_unused]] = 0xff, }; static inline bool TWOpCodeIsSmallInteger(uint8_t opcode) { diff --git a/src/Bitcoin/Script.h b/src/Bitcoin/Script.h index f8f0e7257d9..39cc5c874fc 100644 --- a/src/Bitcoin/Script.h +++ b/src/Bitcoin/Script.h @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -29,8 +30,8 @@ class Script { template Script(It begin, It end) : bytes(begin, end) {} - /// Initializaes a script with a collection of raw bytes by moving. - explicit Script(const Data& bytes) : bytes(bytes) {} + /// Initializes a script with a collection of raw bytes by moving. + explicit Script(Data bytes) : bytes(std::move(bytes)) {} /// Whether the script is empty. bool empty() const { return bytes.empty(); } @@ -47,7 +48,7 @@ class Script { /// Determines whether this is a pay-to-witness-public-key-hash (P2WPKH) script. bool isPayToWitnessPublicKeyHash() const; - /// Determines whether this is a witness programm script. + /// Determines whether this is a witness program script. bool isWitnessProgram() const; /// Matches the script to a pay-to-public-key (P2PK) script. @@ -69,7 +70,7 @@ class Script { bool matchMultisig(std::vector& publicKeys, int& required) const; /// Builds a pay-to-public-key (P2PK) script from a public key. - static Script buildPayToPublicKey(const Data& publickKey); + static Script buildPayToPublicKey(const Data& publicKey); /// Builds a pay-to-public-key-hash (P2PKH) script from a public key hash. static Script buildPayToPublicKeyHash(const Data& hash); diff --git a/src/Bitcoin/SignatureBuilder.cpp b/src/Bitcoin/SignatureBuilder.cpp index cec92f1b21d..fe2bb1f6ac3 100644 --- a/src/Bitcoin/SignatureBuilder.cpp +++ b/src/Bitcoin/SignatureBuilder.cpp @@ -151,7 +151,7 @@ Result, Common::Proto::SigningError> SignatureBuilder, Common::Proto::SigningError>::success({data}); } if (script.isWitnessProgram()) { - // Error: Invalid sutput script + // Error: Invalid output script return Result, Common::Proto::SigningError>::failure(Common::Proto::Error_script_output); } if (script.matchMultisig(keys, required)) { @@ -256,7 +256,7 @@ Data SignatureBuilder::createSignature( if (!externalSignatures.has_value() || externalSignatures.value().size() <= _index) { // Error: no or not enough signatures provided - return Data(); + return {}; } Data externalSignature = std::get<0>(externalSignatures.value()[_index]); @@ -265,12 +265,12 @@ Data SignatureBuilder::createSignature( // Verify provided signature if (!PublicKey::isValid(publicKey, TWPublicKeyTypeSECP256k1)) { // Error: invalid public key - return Data(); + return {}; } const auto publicKeyObj = PublicKey(publicKey, TWPublicKeyTypeSECP256k1); if (!publicKeyObj.verifyAsDER(externalSignature, sighash)) { // Error: Signature does not match publickey+hash - return Data(); + return {}; } externalSignature.push_back(static_cast(input.hashType)); @@ -343,4 +343,4 @@ template class SignatureBuilder; template class SignatureBuilder; template class SignatureBuilder; -} // namespace TW::Bitcoin \ No newline at end of file +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/SignatureBuilder.h b/src/Bitcoin/SignatureBuilder.h index 33ed8925394..07ad17f6f4c 100644 --- a/src/Bitcoin/SignatureBuilder.h +++ b/src/Bitcoin/SignatureBuilder.h @@ -17,6 +17,7 @@ #include "../PublicKey.h" #include "../CoinEntry.h" +#include #include #include #include @@ -59,13 +60,13 @@ class SignatureBuilder { /// Initializes a transaction signer with signing input. /// estimationMode: is set, no real signing is performed, only as much as needed to get the almost-exact signed size SignatureBuilder( - const SigningInput& input, - const TransactionPlan& plan, + SigningInput input, + TransactionPlan plan, Transaction& transaction, SigningMode signingMode = SigningMode_Normal, std::optional externalSignatures = {} ) - : input(input), plan(plan), _transaction(transaction), signingMode(signingMode), externalSignatures(externalSignatures) {} + : input(std::move(input)), plan(std::move(plan)), _transaction(transaction), signingMode(signingMode), externalSignatures(std::move(externalSignatures)) {} /// Signs the transaction. /// diff --git a/src/Bitcoin/SignatureVersion.h b/src/Bitcoin/SignatureVersion.h index fa3363eec3f..73659efb711 100644 --- a/src/Bitcoin/SignatureVersion.h +++ b/src/Bitcoin/SignatureVersion.h @@ -11,4 +11,4 @@ enum SignatureVersion { BASE, WITNESS_V0 }; -} // TW::Bitcoin namespace +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/Transaction.cpp b/src/Bitcoin/Transaction.cpp index 1b2a17c8676..152c693d736 100644 --- a/src/Bitcoin/Transaction.cpp +++ b/src/Bitcoin/Transaction.cpp @@ -43,7 +43,7 @@ Data Transaction::getPreImage(const Script& scriptCode, size_t index, // The input being signed (replacing the scriptSig with scriptCode + amount) // The prevout may already be contained in hashPrevout, and the nSequence - // may already be contain in hashSequence. + // may already be contained in hashSequence. reinterpret_cast(inputs[index].previousOutput).encode(data); scriptCode.encode(data); diff --git a/src/Bitcoin/TransactionBuilder.cpp b/src/Bitcoin/TransactionBuilder.cpp index 82ac0367a14..9e72dee4f5f 100644 --- a/src/Bitcoin/TransactionBuilder.cpp +++ b/src/Bitcoin/TransactionBuilder.cpp @@ -10,7 +10,6 @@ #include "SignatureBuilder.h" #include "../Coin.h" -#include "../proto/Bitcoin.pb.h" #include #include @@ -102,7 +101,7 @@ TransactionPlan TransactionBuilder::plan(const SigningInput& input) { // select UTXOs plan.amount = input.amount; - // if amount requested is the same or more than available amount, it cannot be satisifed, but + // if amount requested is the same or more than available amount, it cannot be satisfied, but // treat this case as MaxAmount, and send maximum available (which will be less) if (!maxAmount && static_cast(input.amount) >= inputSum) { maxAmount = true; @@ -151,7 +150,7 @@ TransactionPlan TransactionBuilder::plan(const SigningInput& input) { plan.change = 0; } plan.fee = estimateSegwitFee(feeCalculator, plan, output_size, input); - // If fee is larger then availableAmount (can happen in special maxAmount case), we reduce it (and hope it will go through) + // If fee is larger than availableAmount (can happen in special maxAmount case), we reduce it (and hope it will go through) plan.fee = std::min(plan.availableAmount, plan.fee); assert(plan.fee >= 0 && plan.fee <= plan.availableAmount); From b56cac05d2fa0e81972f632fc55e77c416e637bf Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 23 Sep 2022 00:09:29 +0200 Subject: [PATCH 089/497] [Improvements]: Add new issue template for big goal / complex feature request (#2584) * feat(issue_template): remove new template, update feature_request.md --- .github/ISSUE_TEMPLATE/feature_request.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 11fc491ef1d..16161265dae 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -16,5 +16,23 @@ A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. +**Checklist** + + + + +- [ ] task number 1 + - [ ] subtask number 1 + - [ ] subtask number 2 +- [ ] task number 2 +- [ ] task number 3 + +**Resources** + + + +Resources link + **Additional context** + Add any other context or screenshots about the feature request here. From 41c7e448479ffc585eb3f69e2461b758e2138c40 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 23 Sep 2022 19:53:28 +0900 Subject: [PATCH 090/497] [Documentation] Add missing doc string for Swift classes (#2592) * Add missing doc string for swift classes * set -o pipefail to ios-doc --- include/TrustWalletCore/TWDataVector.h | 14 ++++---- swift/Sources/AnySigner.swift | 34 +++++++++++++++++++ .../Sources/Extensions/AddressProtocol.swift | 1 + tools/ios-doc | 5 ++- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/include/TrustWalletCore/TWDataVector.h b/include/TrustWalletCore/TWDataVector.h index 7df60c8f1a1..6e2e88912d0 100644 --- a/include/TrustWalletCore/TWDataVector.h +++ b/include/TrustWalletCore/TWDataVector.h @@ -11,7 +11,7 @@ TW_EXTERN_C_BEGIN -// A vector of TWData byte arrays +/// A vector of TWData byte arrays TW_EXPORT_CLASS struct TWDataVector; @@ -20,20 +20,20 @@ struct TWDataVector; /// \note Must be deleted with \TWDataVectorDelete /// \return a non-null Vector of Data. TW_EXPORT_STATIC_METHOD -struct TWDataVector *_Nonnull TWDataVectorCreate(); +struct TWDataVector* _Nonnull TWDataVectorCreate(); /// Creates a Vector of Data with the given element /// /// \param data A non-null valid block of data /// \return A Vector of data with a single given element TW_EXPORT_STATIC_METHOD -struct TWDataVector *_Nonnull TWDataVectorCreateWithData(TWData *_Nonnull data); +struct TWDataVector* _Nonnull TWDataVectorCreateWithData(TWData* _Nonnull data); /// Delete/Deallocate a Vector of Data /// /// \param dataVector A non-null Vector of data TW_EXPORT_METHOD -void TWDataVectorDelete(struct TWDataVector *_Nonnull dataVector); +void TWDataVectorDelete(struct TWDataVector* _Nonnull dataVector); /// Add an element to a Vector of Data. Element is cloned /// @@ -41,14 +41,14 @@ void TWDataVectorDelete(struct TWDataVector *_Nonnull dataVector); /// \param data A non-null valid block of data /// \note data input parameter must be deleted on its own TW_EXPORT_METHOD -void TWDataVectorAdd(struct TWDataVector *_Nonnull dataVector, TWData *_Nonnull data); +void TWDataVectorAdd(struct TWDataVector* _Nonnull dataVector, TWData* _Nonnull data); /// Retrieve the number of elements /// /// \param dataVector A non-null Vector of data /// \return the size of the given vector. TW_EXPORT_PROPERTY -size_t TWDataVectorSize(const struct TWDataVector *_Nonnull dataVector); +size_t TWDataVectorSize(const struct TWDataVector* _Nonnull dataVector); /// Retrieve the n-th element. /// @@ -57,6 +57,6 @@ size_t TWDataVectorSize(const struct TWDataVector *_Nonnull dataVector); /// \note Returned element must be freed with \TWDataDelete /// \return A non-null block of data TW_EXPORT_METHOD -TWData *_Nullable TWDataVectorGet(const struct TWDataVector *_Nonnull dataVector, size_t index); +TWData* _Nullable TWDataVectorGet(const struct TWDataVector* _Nonnull dataVector, size_t index); TW_EXTERN_C_END diff --git a/swift/Sources/AnySigner.swift b/swift/Sources/AnySigner.swift index 9a6f5862cd6..5abf730b95d 100644 --- a/swift/Sources/AnySigner.swift +++ b/swift/Sources/AnySigner.swift @@ -10,7 +10,15 @@ import SwiftProtobuf public typealias SigningInput = Message public typealias SigningOutput = Message +/// Represents a signer to sign transactions for any blockchain. public final class AnySigner { + + /// Signs a transaction by SigningInput message and coin type + /// + /// - Parameters: + /// - input: The generic SigningInput SwiftProtobuf message + /// - coin: CoinType + /// - Returns: The generic SigningOutput SwiftProtobuf message public static func sign(input: SigningInput, coin: CoinType) -> SigningOutput { do { let outputData = nativeSign(data: try input.serializedData(), coin: coin) @@ -20,6 +28,12 @@ public final class AnySigner { } } + /// Signs a transaction by serialized data of a SigningInput and coin type + /// + /// - Parameters: + /// - data: The serialized data of a SigningInput + /// - coin: CoinType + /// - Returns: The serialized data of a SigningOutput public static func nativeSign(data: Data, coin: CoinType) -> Data { let inputData = TWDataCreateWithNSData(data) defer { @@ -28,10 +42,18 @@ public final class AnySigner { return TWDataNSData(TWAnySignerSign(inputData, TWCoinType(rawValue: coin.rawValue))) } + /// Check if AnySigner supports signing JSON representation of SigningInput for a given coin. public static func supportsJSON(coin: CoinType) -> Bool { return TWAnySignerSupportsJSON(TWCoinType(rawValue: coin.rawValue)) } + /// Signs a transaction specified by the JSON representation of a SigningInput, coin type and a private key + /// + /// - Parameters: + /// - json: JSON representation of a SigningInput + /// - key: The private key data + /// - coin: CoinType + /// - Returns: The JSON representation of a SigningOutput. public static func signJSON(_ json: String, key: Data, coin: CoinType) -> String { let jsonString = TWStringCreateWithNSString(json) let keyData = TWDataCreateWithNSData(key) @@ -41,6 +63,12 @@ public final class AnySigner { return TWStringNSString(TWAnySignerSignJSON(jsonString, keyData, TWCoinType(rawValue: coin.rawValue))) } + /// Plans a transaction (for UTXO chains only). + /// + /// - Parameters: + /// - input: The generic SigningInput SwiftProtobuf message + /// - coin: CoinType + /// - Returns: TransactionPlan SwiftProtobuf message public static func plan(input: SigningInput, coin: CoinType) -> TransactionPlan { do { let outputData = nativePlan(data: try input.serializedData(), coin: coin) @@ -50,6 +78,12 @@ public final class AnySigner { } } + /// Plans a transaction (for UTXO chains only). + /// + /// - Parameters: + /// - input: The serialized data of a SigningInput + /// - coin: CoinType + /// - Returns: The serialized data of a TransactionPlan public static func nativePlan(data: Data, coin: CoinType) -> Data { let inputData = TWDataCreateWithNSData(data) defer { diff --git a/swift/Sources/Extensions/AddressProtocol.swift b/swift/Sources/Extensions/AddressProtocol.swift index 273e71cea0f..1660d724252 100644 --- a/swift/Sources/Extensions/AddressProtocol.swift +++ b/swift/Sources/Extensions/AddressProtocol.swift @@ -6,6 +6,7 @@ import Foundation +/// Generic Address protocol for AnyAddress / SegwitAddress / SolanaAddress public protocol Address: CustomStringConvertible {} extension AnyAddress: Equatable {} diff --git a/tools/ios-doc b/tools/ios-doc index be998bff74c..9c004897a18 100755 --- a/tools/ios-doc +++ b/tools/ios-doc @@ -2,8 +2,11 @@ # https://developer.apple.com/documentation/xcode/distributing-documentation-to-external-developers +set -e +set -o pipefail + pushd swift -mkdir -p build +mkdir -p build && rm -rf build/*.doccarchive export DOCC_JSON_PRETTYPRINT="YES" xcodebuild -workspace TrustWalletCore.xcworkspace -derivedDataPath build/docsData -scheme WalletCore -destination 'platform=iOS Simulator,name=iPhone 13 Pro Max' -parallelizeTargets docbuild | xcbeautify From b06a748292bf2e5821a9885308895bf1003562d2 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Sun, 25 Sep 2022 11:41:50 +0200 Subject: [PATCH 091/497] [Cardano]: clang fix and improvements (#2582) * feat(cardano): clang tidy fixes and improvements * style: clang-format Transaction.h --- src/Cardano/AddressV2.cpp | 10 +++---- src/Cardano/AddressV2.h | 4 +-- src/Cardano/AddressV3.cpp | 7 ----- src/Cardano/AddressV3.h | 10 +++---- src/Cardano/Signer.cpp | 48 ++++++++++++++++----------------- src/Cardano/Signer.h | 7 ++--- src/Cardano/Transaction.cpp | 42 ++++++++++------------------- src/Cardano/Transaction.h | 54 +++++++++++++++++++++---------------- 8 files changed, 85 insertions(+), 97 deletions(-) diff --git a/src/Cardano/AddressV2.cpp b/src/Cardano/AddressV2.cpp index 4ee32568cfb..6d2140ab82f 100644 --- a/src/Cardano/AddressV2.cpp +++ b/src/Cardano/AddressV2.cpp @@ -16,7 +16,7 @@ namespace TW::Cardano { bool AddressV2::parseAndCheck(const std::string& addr, Data& root_out, Data& attrs_out, byte& type_out) { // Decode Bas58, decode payload + crc, decode root, attr Data base58decoded = Base58::bitcoin.decode(addr); - if (base58decoded.size() == 0) { + if (base58decoded.empty()) { throw std::invalid_argument("Invalid address: could not Base58 decode"); } auto elems = Cbor::Decode(base58decoded).getArrayElements(); @@ -79,7 +79,7 @@ AddressV2::AddressV2(const PublicKey& publicKey) { } Data AddressV2::getCborData() const { - // put together string represenatation, CBOR representation + // put together string representation, CBOR representation // inner data: pubkey, attrs, type auto cbor1 = Cbor::Encode::array({ Cbor::Encode::bytes(root), @@ -105,9 +105,9 @@ std::string AddressV2::string() const { Data AddressV2::keyHash(const TW::Data& xpub) { if (xpub.size() != 64) { - throw std::invalid_argument("invalid xbub length"); + throw std::invalid_argument("invalid xpub length"); } - // hash of follwoing Cbor-array: [0, [0, xbub], {} ] + // hash of following Cbor-array: [0, [0, xpub], {} ] // 3rd entry map is empty map for V2, contains derivation path for V1 // clang-format off Data cborData = Cbor::Encode::array({ @@ -123,4 +123,4 @@ Data AddressV2::keyHash(const TW::Data& xpub) { return blake; } -} // namespace TW::Cardano \ No newline at end of file +} // namespace TW::Cardano diff --git a/src/Cardano/AddressV2.h b/src/Cardano/AddressV2.h index 6c03006b4e0..929a52356f9 100644 --- a/src/Cardano/AddressV2.h +++ b/src/Cardano/AddressV2.h @@ -20,7 +20,7 @@ namespace TW::Cardano { * Derivation is BIP39, default derivation path is "m/44'/1815'/0'/0/0", with last element being the account number. * Curve is ED25519 with special variations, custom logic in HDWallet and TrezorCrypto lib. * Private key is ED25519: 32-byte PK is extended with 32-byte extra extension, and 32-byte chain code. - * Private key is derived from mnemonic raw entropy (not seed, as in other cases); 96-byte secret is generated (pk, extrension, and chain code). + * Private key is derived from mnemonic raw entropy (not seed, as in other cases); 96-byte secret is generated (pk, extension, and chain code). * Public key is 64-byte: the 32-byte ED25519 public key plus the 32-byte chain code of the PK. * Address derivation: Only V2, type 0 (=public key) addresses are generated. * - CBOR binary scheme is used inside addresses. @@ -46,7 +46,7 @@ class AddressV2 { Data attrs; /// Type; 0: public key. - TW::byte type; + TW::byte type{}; static const TW::byte PayloadTag = 24; diff --git a/src/Cardano/AddressV3.cpp b/src/Cardano/AddressV3.cpp index 43b12442774..44c34ab0352 100644 --- a/src/Cardano/AddressV3.cpp +++ b/src/Cardano/AddressV3.cpp @@ -175,13 +175,6 @@ AddressV3::Kind AddressV3::kindFromFirstByte(uint8_t first) { return (Kind)((first & 0xF0) >> 4); } -void AddressV3::operator=(const AddressV3& other) { - networkId = other.networkId; - kind = other.kind; - bytes = other.bytes; - legacyAddressV2 = other.legacyAddressV2; -} - std::string AddressV3::getHrp(Kind kind) noexcept { switch (kind) { case Kind_Base: diff --git a/src/Cardano/AddressV3.h b/src/Cardano/AddressV3.h index bee61121ffd..f9580812afe 100644 --- a/src/Cardano/AddressV3.h +++ b/src/Cardano/AddressV3.h @@ -43,9 +43,9 @@ class AddressV3 { static const uint8_t EncodedSize1 = 1 + HashSize; static const uint8_t EncodedSize2 = 1 + 2 * HashSize; - NetworkId networkId = Network_Production; + NetworkId networkId{Network_Production}; - Kind kind = Kind_Base; + Kind kind{Kind_Base}; /// raw key/hash bytes Data bytes; @@ -80,7 +80,7 @@ class AddressV3 { /// Copy constructor AddressV3(const AddressV3& other); - void operator=(const AddressV3& other); + AddressV3& operator=(const AddressV3& other) noexcept = default; /// Returns the Bech string representation of the address, with default HRP. std::string string() const; @@ -88,7 +88,7 @@ class AddressV3 { std::string string(const std::string& hrp) const; /// Hrp of kind - static std::string getHrp(const Kind kind) noexcept; + static std::string getHrp(Kind kind) noexcept; /// Check whether data length is correct static bool checkLength(Kind kind, size_t length) noexcept; /// Check validity of binary address. @@ -107,7 +107,7 @@ class AddressV3 { static Kind kindFromFirstByte(uint8_t first); private: - AddressV3() : networkId(Network_Production), kind(Kind_Base) {} + AddressV3() = default; }; inline bool operator==(const AddressV3& lhs, const AddressV3& rhs) { diff --git a/src/Cardano/Signer.cpp b/src/Cardano/Signer.cpp index 67063685d25..103f57f5e92 100644 --- a/src/Cardano/Signer.cpp +++ b/src/Cardano/Signer.cpp @@ -90,7 +90,7 @@ Common::Proto::SigningError Signer::buildTransactionAux(Transaction& tx, const P Data deriveStakingPrivateKey(const Data& privateKeyData) { if (privateKeyData.size() != PrivateKey::cardanoKeySize) { - return Data(); + return {}; } assert(privateKeyData.size() == PrivateKey::cardanoKeySize); const auto halfSize = PrivateKey::cardanoKeySize / 2; @@ -196,7 +196,7 @@ Cbor::Encode cborizeSignatures(const std::vector>& signatu // clang-format on } -Proto::SigningOutput Signer::signWithPlan() { +Proto::SigningOutput Signer::signWithPlan() const { auto ret = Proto::SigningOutput(); if (_plan.error != Common::Proto::OK) { // plan has error @@ -251,10 +251,10 @@ Common::Proto::SigningError Signer::encodeTransaction(Data& encoded, Data& txId, return Common::Proto::OK; } -// Select a subset of inputs, to cover desired coin amount. Simple algorithm: pick largest ones. +// Select a subset of inputs, to cover desired coin amount. Simple algorithm: pick the largest ones. std::vector selectInputsSimpleNative(const std::vector& inputs, Amount amount) { auto ii = std::vector(inputs); - sort(ii.begin(), ii.end(), [](TxInput t1, TxInput t2) { + sort(ii.begin(), ii.end(), [](auto&& t1, auto&& t2) { return t1.amount > t2.amount; }); auto selected = std::vector(); @@ -270,15 +270,16 @@ std::vector selectInputsSimpleNative(const std::vector& inputs return selected; } -// Select a subset of inputs, to cover desired token amount. Simple algorithm: pick largest ones. -void selectInputsSimpleToken(const std::vector& inputs, std::string key, uint256_t amount, std::vector& selectedInputs) { - uint256_t selectedAmount = std::accumulate(selectedInputs.begin(), selectedInputs.end(), uint256_t(0), [key]([[maybe_unused]] uint256_t sum, const TxInput& si) { return si.tokenBundle.getAmount(key); }); +// Select a subset of inputs, to cover desired token amount. Simple algorithm: pick the largest ones. +void selectInputsSimpleToken(const std::vector& inputs, std::string key, const uint256_t& amount, std::vector& selectedInputs) { + auto accumulateFunctor = [key]([[maybe_unused]] auto&& sum, auto&& si) { return si.tokenBundle.getAmount(key); }; + uint256_t selectedAmount = std::accumulate(selectedInputs.begin(), selectedInputs.end(), uint256_t(0), accumulateFunctor); if (selectedAmount >= amount) { return; // already covered } // sort inputs descending auto ii = std::vector(inputs); - std::sort(ii.begin(), ii.end(), [key](TxInput t1, TxInput t2) { return t1.tokenBundle.getAmount(key) > t2.tokenBundle.getAmount(key); }); + std::sort(ii.begin(), ii.end(), [key](auto&& t1, auto&& t2) { return t1.tokenBundle.getAmount(key) > t2.tokenBundle.getAmount(key); }); for (const auto& i : ii) { if (static_cast(distance(selectedInputs.begin(), find(selectedInputs.begin(), selectedInputs.end(), i))) < selectedInputs.size()) { // already selected @@ -293,25 +294,24 @@ void selectInputsSimpleToken(const std::vector& inputs, std::string key // not enough } -// Select a subset of inputs, to cover desired amount. Simple algorithm: pick largest ones +// Select a subset of inputs, to cover desired amount. Simple algorithm: pick the largest ones std::vector Signer::selectInputsWithTokens(const std::vector& inputs, Amount amount, const TokenBundle& requestedTokens) { auto selected = selectInputsSimpleNative(inputs, amount); - for (auto iter = requestedTokens.bundle.begin(); iter != requestedTokens.bundle.end(); ++iter) { - const auto& ta = iter->second; - selectInputsSimpleToken(inputs, ta.key(), ta.amount, selected); + for (auto&& [_, curAmount] : requestedTokens.bundle) { + selectInputsSimpleToken(inputs, curAmount.key(), curAmount.amount, selected); } return selected; } // Create a simple plan, used for estimation TransactionPlan simplePlan(Amount amount, const TokenBundle& requestedTokens, const std::vector& selectedInputs, bool maxAmount, uint64_t deposit, uint64_t undeposit) { - TransactionPlan plan{.amount = amount, .utxos = selectedInputs, .deposit = deposit, .undeposit = undeposit}; + TransactionPlan plan{.utxos = selectedInputs, .amount = amount, .deposit = deposit, .undeposit = undeposit}; // Sum availableAmount plan.availableAmount = 0; for (auto& u : plan.utxos) { plan.availableAmount += u.amount; - for (auto iter = u.tokenBundle.bundle.begin(); iter != u.tokenBundle.bundle.end(); ++iter) { - plan.availableTokens.add(iter->second); + for (auto && [_, curAmount] : u.tokenBundle.bundle) { + plan.availableTokens.add(curAmount); } } plan.fee = PlaceholderFee; // placeholder value @@ -386,11 +386,11 @@ Amount txFeeFunction(uint64_t txSizeInBytes) { const double fixedTerm = 155381 + 500; const double linearTerm = 43.946 + 0.1; - const Amount fee = (Amount)(ceil(fixedTerm + (double)txSizeInBytes * linearTerm)); + const auto fee = (Amount)(ceil(fixedTerm + (double)txSizeInBytes * linearTerm)); return fee; } -Amount Signer::estimateFee(const Proto::SigningInput& input, Amount amount, const TokenBundle& requestedTokens, const std::vector selectedInputs) { +Amount Signer::estimateFee(const Proto::SigningInput& input, Amount amount, const TokenBundle& requestedTokens, const std::vector& selectedInputs) { return txFeeFunction(estimateTxSize(input, amount, requestedTokens, selectedInputs)); } @@ -429,12 +429,12 @@ TransactionPlan Signer::doPlan() const { } assert(plan.amount > 0 || maxAmount); if (requestedTokens.size() > 1) { - // We support transfer of only one coin (for simplicity; inputs may contain more coints which are preserved) + // We support transfer of only one coin (for simplicity; inputs may contain more coins which are preserved) plan.error = Common::Proto::Error_invalid_requested_token_amount; return plan; } - // if amount requested is the same or more than available amount, it cannot be satisifed, but + // if amount requested is the same or more than available amount, it cannot be satisfied, but // treat this case as MaxAmount, and send maximum available (which will be less) if (!maxAmount && input.transfer_message().amount() >= inputSumAfterDeposit) { maxAmount = true; @@ -449,14 +449,14 @@ TransactionPlan Signer::doPlan() const { // maxAmount, select all plan.utxos = utxos; } - assert(plan.utxos.size() > 0); + assert(!plan.utxos.empty()); // Sum availableAmount plan.availableAmount = 0; for (auto& u : plan.utxos) { plan.availableAmount += u.amount; - for (auto iter = u.tokenBundle.bundle.begin(); iter != u.tokenBundle.bundle.end(); ++iter) { - plan.availableTokens.add(iter->second); + for (auto && [_, curAmount] : u.tokenBundle.bundle) { + plan.availableTokens.add(curAmount); } } if (plan.availableAmount == 0) { @@ -474,8 +474,8 @@ TransactionPlan Signer::doPlan() const { } assert(plan.amount <= availableAmountAfterDeposit); // check that there are enough tokens in the inputs - for (auto iter = requestedTokens.bundle.begin(); iter != requestedTokens.bundle.end(); ++iter) { - if (iter->second.amount > plan.availableTokens.getAmount(iter->second.key())) { + for (auto && [_, curAmount] : requestedTokens.bundle) { + if (curAmount.amount > plan.availableTokens.getAmount(curAmount.key())) { plan.error = Common::Proto::Error_low_balance; return plan; } diff --git a/src/Cardano/Signer.h b/src/Cardano/Signer.h index 2daae8b5caa..01d538a617f 100644 --- a/src/Cardano/Signer.h +++ b/src/Cardano/Signer.h @@ -12,6 +12,7 @@ #include #include +#include namespace TW::Cardano { @@ -27,11 +28,11 @@ class Signer { Proto::SigningInput input; TransactionPlan _plan; - Signer(const Proto::SigningInput& input): input(input) {} + explicit Signer(Proto::SigningInput input): input(std::move(input)) {} Proto::SigningOutput sign(); // Sign using existing plan - Proto::SigningOutput signWithPlan(); + Proto::SigningOutput signWithPlan() const; // Create plan from signing input TransactionPlan doPlan() const; /// Returns a transaction plan (utxo selection, fee estimation) @@ -44,7 +45,7 @@ class Signer { static Common::Proto::SigningError encodeTransaction(Data& encoded, Data& txId, const Proto::SigningInput& input, const TransactionPlan& plan, bool sizeEstimationOnly = false); // Build aux transaction object, using input and plan static Common::Proto::SigningError buildTransactionAux(Transaction& tx, const Proto::SigningInput& input, const TransactionPlan& plan); - static Amount estimateFee(const Proto::SigningInput& input, Amount amount, const TokenBundle& requestedTokens, const std::vector selectedInputs); + static Amount estimateFee(const Proto::SigningInput& input, Amount amount, const TokenBundle& requestedTokens, const std::vector& selectedInputs); static std::vector selectInputsWithTokens(const std::vector& inputs, Amount amount, const TokenBundle& requestedTokens); // Build list of public keys + signature static Common::Proto::SigningError assembleSignatures(std::vector>& signatures, const Proto::SigningInput& input, const TransactionPlan& plan, const Data& txId, bool sizeEstimationOnly = false); diff --git a/src/Cardano/Transaction.cpp b/src/Cardano/Transaction.cpp index 71ef9c68787..da6a4924572 100644 --- a/src/Cardano/Transaction.cpp +++ b/src/Cardano/Transaction.cpp @@ -13,11 +13,7 @@ namespace TW::Cardano { TokenAmount TokenAmount::fromProto(const Proto::TokenAmount& proto) { - auto ret = TokenAmount(); - ret.policyId = proto.policy_id(); - ret.assetName = proto.asset_name(); - ret.amount = load(proto.amount()); - return ret; + return {proto.policy_id(), proto.asset_name(), load(proto.amount())}; } Proto::TokenAmount TokenAmount::toProto() const { @@ -30,10 +26,9 @@ Proto::TokenAmount TokenAmount::toProto() const { } TokenBundle TokenBundle::fromProto(const Proto::TokenBundle& proto) { - auto ret = TokenBundle(); - for (auto i = 0; i < proto.token_size(); ++i) { - ret.add(TokenAmount::fromProto(proto.token(i))); - } + TokenBundle ret; + const auto addFunctor = [&ret](auto&& cur) { ret.add(TokenAmount::fromProto(cur)); }; + std::for_each(std::cbegin(proto.token()), std::cend(proto.token()), addFunctor); return ret; } @@ -47,21 +42,14 @@ Proto::TokenBundle TokenBundle::toProto() const { void TokenBundle::add(const TokenAmount& ta) { const auto key = ta.key(); - if (bundle.find(key) == bundle.end()) { - bundle[key] = ta; - } else { - auto entry = bundle[key]; - entry.amount += ta.amount; - bundle[key] = entry; + if (auto&& [it, inserted] = bundle.try_emplace(key, ta); !inserted) { + it->second.amount += ta.amount; } } uint256_t TokenBundle::getAmount(const std::string& key) const { const auto& findkey = bundle.find(key); - if (findkey == bundle.end()) { - return 0; - } - return findkey->second.amount; + return findkey == bundle.end() ? 0 : findkey->second.amount; } std::unordered_set TokenBundle::getPolicyIds() const { @@ -74,7 +62,7 @@ std::unordered_set TokenBundle::getPolicyIds() const { std::vector TokenBundle::getByPolicyId(const std::string& policyId) const { std::vector filtered; - for (const auto& t : bundle) { + for (auto&& t : bundle) { if (t.second.policyId == policyId) { filtered.emplace_back(t.second); } @@ -110,8 +98,6 @@ uint64_t TokenBundle::minAdaAmount() const { std::unordered_set policyIdRegistry; std::unordered_set assetNameRegistry; - uint64_t numPids = 0; - uint64_t numAssets = 0; uint64_t sumAssetNameLengths = 0; for (const auto& t : bundle) { policyIdRegistry.emplace(t.second.policyId); @@ -119,9 +105,9 @@ uint64_t TokenBundle::minAdaAmount() const { assetNameRegistry.emplace(t.second.assetName); } } - numPids = uint64_t(policyIdRegistry.size()); - numAssets = uint64_t(assetNameRegistry.size()); - for_each(assetNameRegistry.begin(), assetNameRegistry.end(), [&sumAssetNameLengths](std::string a) { sumAssetNameLengths += a.length(); }); + auto numPids = uint64_t(policyIdRegistry.size()); + auto numAssets = uint64_t(assetNameRegistry.size()); + for_each(assetNameRegistry.begin(), assetNameRegistry.end(), [&sumAssetNameLengths](auto&& a) { sumAssetNameLengths += a.length(); }); return minAdaAmountHelper(numPids, numAssets, sumAssetNameLengths); } @@ -281,7 +267,7 @@ Cbor::Encode cborizeCert(const Certificate& cert) { Cbor::Encode cborizeCerts(const std::vector& certs) { std::vector c; - for (const auto& i: certs) { + for (const auto& i : certs) { c.emplace_back(cborizeCert(i)); } return Cbor::Encode::array(c); @@ -289,7 +275,7 @@ Cbor::Encode cborizeCerts(const std::vector& certs) { Cbor::Encode cborizeWithdrawals(const std::vector& withdrawals) { std::map mapElems; - for (const auto& w: withdrawals) { + for (const auto& w : withdrawals) { mapElems.emplace(Cbor::Encode::bytes(w.stakingKey), Cbor::Encode::uint(w.amount)); } return Cbor::Encode::map(mapElems); @@ -323,7 +309,7 @@ Data Transaction::encode() const { Data Transaction::getId() const { const auto encoded = encode(); - const auto hash = Hash::blake2b(encoded, 32); + auto hash = Hash::blake2b(encoded, 32); return hash; } diff --git a/src/Cardano/Transaction.h b/src/Cardano/Transaction.h index 0bdab1c70bf..a8e7e758000 100644 --- a/src/Cardano/Transaction.h +++ b/src/Cardano/Transaction.h @@ -13,9 +13,10 @@ #include "../proto/Cardano.pb.h" #include "../proto/Common.pb.h" -#include -#include #include +#include +#include +#include namespace TW::Cardano { @@ -28,7 +29,8 @@ class TokenAmount { uint256_t amount; TokenAmount() = default; - TokenAmount(const std::string& policyId, const std::string& assetName, uint256_t amount) : policyId(policyId), assetName(assetName), amount(amount) {} + TokenAmount(std::string policyId, std::string assetName, uint256_t amount) + : policyId(std::move(policyId)), assetName(std::move(assetName)), amount(std::move(amount)) {} static TokenAmount fromProto(const Proto::TokenAmount& proto); Proto::TokenAmount toProto() const; @@ -41,7 +43,11 @@ class TokenBundle { std::map bundle; TokenBundle() = default; - TokenBundle(const std::vector& tokens) { for (const auto& t: tokens) { add(t); } } + explicit TokenBundle(const std::vector& tokens) { + for (const auto& t : tokens) { + add(t); + } + } static TokenBundle fromProto(const Proto::TokenBundle& proto); Proto::TokenBundle toProto() const; @@ -64,14 +70,14 @@ class TokenBundle { class OutPoint { public: Data txHash; - uint64_t outputIndex; + uint64_t outputIndex{}; OutPoint() = default; - OutPoint(const Data& txHash, uint64_t outputIndex) : txHash(txHash), outputIndex(outputIndex) {} - static OutPoint fromProto(const Proto::OutPoint& proto); + OutPoint(Data txHash, uint64_t outputIndex) + : txHash(std::move(txHash)), outputIndex(outputIndex) {} }; -class TxInput: public OutPoint { +class TxInput : public OutPoint { public: std::string address; @@ -92,28 +98,30 @@ class TxOutput { Data address; /// ADA amount - Amount amount; + Amount amount{}; /// Token amounts (optional) TokenBundle tokenBundle; TxOutput() = default; - TxOutput(const Data& address, Amount amount) : address(address), amount(amount) {} - TxOutput(const Data& address, Amount amount, const TokenBundle& tokenBundle) : address(address), amount(amount), tokenBundle(tokenBundle) {} + TxOutput(Data address, Amount amount) + : address(std::move(address)), amount(amount) {} + TxOutput(Data address, Amount amount, TokenBundle tokenBundle) + : address(std::move(address)), amount(amount), tokenBundle(std::move(tokenBundle)) {} }; class TransactionPlan { public: std::vector utxos; Amount availableAmount = 0; // total coins in the input utxos - Amount amount = 0; // coins in the output UTXO - Amount fee = 0; // coin amount deducted as fee - Amount change = 0; // coins in the change UTXO - Amount deposit = 0; // coins deposited (going to deposit) in this TX - Amount undeposit = 0; // coins undeposited (returned from deposit) in this TX - TokenBundle availableTokens; // total tokens in the utxos (optional) - TokenBundle outputTokens; // tokens in the output (optional) - TokenBundle changeTokens; // tokens in the change (optional) + Amount amount = 0; // coins in the output UTXO + Amount fee = 0; // coin amount deducted as fee + Amount change = 0; // coins in the change UTXO + Amount deposit = 0; // coins deposited (going to deposit) in this TX + Amount undeposit = 0; // coins undeposited (returned from deposit) in this TX + TokenBundle availableTokens; // total tokens in the utxos (optional) + TokenBundle outputTokens; // tokens in the output (optional) + TokenBundle changeTokens; // tokens in the change (optional) Common::Proto::SigningError error = Common::Proto::SigningError::OK; static TransactionPlan fromProto(const Proto::TransactionPlan& proto); @@ -123,9 +131,9 @@ class TransactionPlan { /// A key with a type, used in a Certificate class CertificateKey { public: - enum KeyType: uint8_t { + enum KeyType : uint8_t { AddressKeyHash = 0, - //ScriptHash = 1, + // ScriptHash = 1, }; KeyType type; Data key; @@ -134,11 +142,11 @@ class CertificateKey { /// Certificate, mainly used for staking class Certificate { public: - enum CertificateType: uint8_t { + enum CertificateType : uint8_t { SkatingKeyRegistration = 0, StakingKeyDeregistration = 1, Delegation = 2, - //StakePoolRegistration = 3, // not supported + // StakePoolRegistration = 3, // not supported }; CertificateType type; CertificateKey certKey; From 1619e79d24faa4d5bfb816401f9880d6acfa31a9 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Tue, 27 Sep 2022 00:25:13 +0000 Subject: [PATCH 092/497] [devconsole] Keystore in devconsole, support stored wallets (#2583) * Minor index.ts changes * WalletManager class (refactor) * Import new wallet into keystore as well (buggy) * Support wallets stored in keystore * Rework, store StoredKey * Rearrange sample script * Improved FS error handling. --- .../devconsole.ts/package-lock.json | 18 +- samples/typescript/devconsole.ts/package.json | 8 +- .../samplescripts/wallets.sampleinput.txt | 51 +++ samples/typescript/devconsole.ts/src/index.ts | 315 +++++++++++++----- 4 files changed, 297 insertions(+), 95 deletions(-) create mode 100644 samples/typescript/devconsole.ts/samplescripts/wallets.sampleinput.txt diff --git a/samples/typescript/devconsole.ts/package-lock.json b/samples/typescript/devconsole.ts/package-lock.json index 81fe3f8df9d..50046ba9ab4 100644 --- a/samples/typescript/devconsole.ts/package-lock.json +++ b/samples/typescript/devconsole.ts/package-lock.json @@ -7,16 +7,16 @@ "": { "name": "cli-wasm", "version": "0.0.1", - "license": "ISC", + "license": "MIT", "dependencies": { - "@trustwallet/wallet-core": "3.0.1", + "@trustwallet/wallet-core": "3.0.4", "chalk": "^4.1.2", "clear": "^0.1.0", "figlet": "^1.5.2", "inquirer": "^8.2.4" }, "bin": { - "cli": "index.js" + "cli": "index.ts" }, "devDependencies": { "@types/node": "^18.7.15", @@ -116,9 +116,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@trustwallet/wallet-core": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.1.tgz", - "integrity": "sha512-WrZwWO85ja4SKyCftJQqj/XWqcLmrP6qJ42YuU9FSzdJp68IdOICckGj5INaW0DE+3O85bPNO+zTmBTBKRZr7g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.4.tgz", + "integrity": "sha512-FrIVEwRmUYFuwU9IoXg0J8fngeW7nlJZZAsrnOWba2g/yGWZl4FQ4z87MEQ5ROOGW9jJzsdWG4PRZffvYzhqsg==", "dependencies": { "protobufjs": ">=6.11.3" } @@ -964,9 +964,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "@trustwallet/wallet-core": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.1.tgz", - "integrity": "sha512-WrZwWO85ja4SKyCftJQqj/XWqcLmrP6qJ42YuU9FSzdJp68IdOICckGj5INaW0DE+3O85bPNO+zTmBTBKRZr7g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.4.tgz", + "integrity": "sha512-FrIVEwRmUYFuwU9IoXg0J8fngeW7nlJZZAsrnOWba2g/yGWZl4FQ4z87MEQ5ROOGW9jJzsdWG4PRZffvYzhqsg==", "requires": { "protobufjs": ">=6.11.3" } diff --git a/samples/typescript/devconsole.ts/package.json b/samples/typescript/devconsole.ts/package.json index fcb97e2ed30..7ca581061d5 100644 --- a/samples/typescript/devconsole.ts/package.json +++ b/samples/typescript/devconsole.ts/package.json @@ -2,9 +2,9 @@ "name": "cli-wasm", "version": "0.0.1", "description": "CLI utility for Wallet Core, through WASM", - "main": "index.js", + "main": "index.ts", "bin": { - "cli": "index.js" + "cli": "index.ts" }, "scripts": { "start": "ts-node src/index.ts", @@ -12,9 +12,9 @@ "test": "cat test/data/privpubkey.testinput.txt | ts-node src/index.ts" }, "author": "Trust Wallet", - "license": "ISC", + "license": "MIT", "dependencies": { - "@trustwallet/wallet-core": "3.0.1", + "@trustwallet/wallet-core": "3.0.4", "chalk": "^4.1.2", "clear": "^0.1.0", "figlet": "^1.5.2", diff --git a/samples/typescript/devconsole.ts/samplescripts/wallets.sampleinput.txt b/samples/typescript/devconsole.ts/samplescripts/wallets.sampleinput.txt new file mode 100644 index 00000000000..415993f3d4e --- /dev/null +++ b/samples/typescript/devconsole.ts/samplescripts/wallets.sampleinput.txt @@ -0,0 +1,51 @@ +// Delete all wallets to start with empty state (commented out not to accidentally remove data) +//await walletsDeleteAll('deleteall') + +// create a wallet +await walletCreate(256, 'First') +await walletsList() +await walletDump() + +// add an extra coin to it +await walletAddCoin(WC.CoinType.solana) +await walletDump() + +// Create a second wallet by mnemonic import +await walletImport('ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal', 'Imported') +await walletsList() +await walletDump() + +// Load first ... +await walletsList() +await walletLoad(0) +await walletDump() + +// ... then second +await walletsList() +await walletLoad(1) +await walletDump() + +// retrieve private key and verify that it derives the same address +coin = WC.CoinType.bitcoin +privkey = wallets.wallet.wallet.privateKey(coin, 'devconsole.ts') +pubkey = privkey.getPublicKeySecp256k1(true); HexCoding.encode(pubkey.data()) +addrDerived = AnyAddress.createWithPublicKey(pubkey, coin).description() +addrStored = wallets.wallet.wallet.account(0).address() +addrDerived === addrStored + +// create another wallet +await walletCreate(256, 'Another') +await walletsList() +await walletDump() + +// Delete it +await walletDelete('delete') +await walletsList() +await walletDump() + +await walletLoad(0) +await walletDump() + +// Delete all wallets (commented out not to accidentally remove data) +//await walletDeleteAll('deleteall') +//await walletsList() diff --git a/samples/typescript/devconsole.ts/src/index.ts b/samples/typescript/devconsole.ts/src/index.ts index 636607edc17..fd994c1f539 100644 --- a/samples/typescript/devconsole.ts/src/index.ts +++ b/samples/typescript/devconsole.ts/src/index.ts @@ -1,11 +1,11 @@ -#!/usr/bin/env node +#!/usr/bin/env ts-node const chalk = require('chalk'); const clear = require('clear'); const figlet = require('figlet'); const repl = require('node:repl'); -//const inquirer = require('inquirer'); -const { initWasm, TW } = require("@trustwallet/wallet-core"); +const { initWasm, TW, KeyStore } = require("@trustwallet/wallet-core"); +const fs = require("fs"); function enumerateNamespaces(topLevelNamespace: any) { const exceptions: string[] = ['AsciiToString', 'ExitStatus', 'ENV', 'ERRNO_CODES', 'ERRNO_MESSAGES', 'DNS', 'Protocols', 'Sockets', 'UNWIND_CACHE', 'PATH', 'PATH_FS', 'SYSCALLS', 'JSEvents', 'JSEvents_requestFullscreen', 'JSEvents_resizeCanvasForFullscreen', 'ExceptionInfo', 'Browser', 'FS', 'MEMFS', 'TTY', 'PIPEFS', 'SOCKFS', 'RegisteredClass', 'Emval']; @@ -26,61 +26,234 @@ function enumerateNamespaces(topLevelNamespace: any) { .filter(n => !exceptions.includes(n)); } -(async function () { - class AddressCoin { - coin: any; - address: string; - constructor(coin: string, address: string) { - this.coin = coin; - this.address = address; +async function main() { + // Wrapper for a wallet stored in keystore + class StoredKeyWallet { + wallet: any; // StoredKey + constructor(w: any) { + this.wallet = w; } - }; + status(): string { + return `Wallet '${this.wallet.name()}', with ${this.wallet.accountCount()} addresses`; + } + dump(): void { + console.error(`Wallet '${this.wallet.name()}', ${this.wallet.isMnemonic() ? 'type mnemonic' : ''}:`); - class TestWallet { - name: string; - wallet: any; - addresses: AddressCoin[]; + if (this.wallet.accountCount() == 0) { + console.log('No addresses'); + } else { + console.log('Addresses:'); + const n = this.wallet.accountCount(); + for (var i = 0; i < n; ++i) { + const a = this.wallet.account(i); + console.log(` ${WC.CoinTypeConfiguration.getSymbol(a.coin())}: ${a.address()}`); + } + } + } + } - constructor(name: string = '', wallet: any) { - this.name = name; - this.wallet = wallet; - this.addresses = []; - this.addDefaultCoins(); + // Handles several wallets, with keystore + class TestWalletManager { + // single opened StoredKeyWallet instance + wallet: StoredKeyWallet | null = null; + StoreFolderPath = "/tmp/devconsole.ts"; + StoreFixedPassword = "devconsole.ts"; + HDWalletPassord = ''; + DefaultCoins: any[] = []; + keystore: any = null; + // wallets available in storage + storeWallets: any[] = []; + + init(): void { + this.DefaultCoins = [WC.CoinType.bitcoin, WC.CoinType.ethereum, WC.CoinType.binance]; + this.keystore = null; + // check and try to create store folder + if (!fs.existsSync(this.StoreFolderPath)) { + // try to create, ignore error + fs.mkdirSync(this.StoreFolderPath); + } + // check again + if (!fs.existsSync(this.StoreFolderPath)) { + console.log(`ERROR: Could not open/create storage folder! Wallet storage will not work. '${this.StoreFolderPath}'`); + return; + } + const storage = new KeyStore.FileSystemStorage(this.StoreFolderPath); + this.keystore = new KeyStore.Default(WC, storage); } - public static createRandom(name: string = '', strength: number = 256): TestWallet { - let wallet = WC.HDWallet.create(strength, ''); - return new TestWallet(name, wallet); + async refreshStoreWallets(): Promise { + if (!this.keystore) { return; } + process.stdout.write(`Refreshing wallets list ... `); + try { + this.storeWallets = await this.keystore.loadAll(); + console.log(`found ${this.storeWallets.length} wallets (dir: ${this.StoreFolderPath})`); + } catch (err) { + console.log(`Exception: ${err}`); + } } - public static createWithMnemonic(name: string = '', mnemonic: string): TestWallet { - let wallet = WC.HDWallet.createWithMnemonic(mnemonic, ''); - return new TestWallet(name, wallet); + async list(): Promise { + if (!this.keystore) { + console.log(`Keystore not available!`); + return; + } + await this.refreshStoreWallets(); + if (!this.storeWallets || this.storeWallets.length == 0) { + console.log("No wallets found in storage."); + } else { + let idx = 0; + console.log(`Found ${this.storeWallets.length} wallets in storage, use walletLoad(id) to load:`); + this.storeWallets.forEach(w => console.log(`${idx++}: ${w.name} \t${w.activeAccounts.length} addrs \t${w.id}`)); + } } - addCoin(coin: string): void { - const address = this.wallet.getAddressForCoin(coin); - this.addresses.push(new AddressCoin(coin, address)); + async load(index: number) { + this.wallet = null; + if (!this.keystore) { return; } + try { + await this.refreshStoreWallets(); + if (index >= this.storeWallets.length) { + console.log(`Index out of range, max ${this.storeWallets.length}`); + await walletsList(); + return; + } + const id = this.storeWallets[index].id; + process.stdout.write(`Loading wallet ${index} ${id} ... `); + const wallet = await this.keystore.load(id); + console.log("done"); + this.wallet = new StoredKeyWallet(this.keystore.mapStoredKey(wallet)); + this.status(); + } catch (err) { + console.log(`Exception: ${err}`); + } } - addDefaultCoins(): void { - this.addCoin(WC.CoinType.bitcoin); - this.addCoin(WC.CoinType.ethereum); - this.addCoin(WC.CoinType.binance); + async loadAWallet() { + if (this.storeWallets.length > 0) { + await this.load(0); + } } - status(): string { - return `Wallet '${this.name}', with ${this.addresses.length} addresses`; + autoFillName(name: string): string { + return (name === '') ? `Wallet${(this.storeWallets.length + 1).toString()}` : name; } - dump(): void { - console.error(`Wallet ${this.name}:`); - - if (this.addresses.length == 0) { - console.log('No addresses'); - } else { - console.log('Addresses:'); - this.addresses.forEach(element => { - console.log(` ${WC.CoinTypeConfiguration.getSymbol(element.coin)}: ${element.address}`); + async create(strength: number, name: string): Promise { + this.wallet = null; + if (!this.keystore) { return; } + try { + if (name === '') { name = this.autoFillName(name); } + const hdWallet = WC.HDWallet.create(strength, this.HDWalletPassord); + const storedKey = WC.StoredKey.importHDWallet(hdWallet.mnemonic(), name, Buffer.from(this.StoreFixedPassword), this.DefaultCoins[0]); + this.DefaultCoins.forEach((coin) => { + storedKey.accountForCoin(coin, hdWallet); }); + let wallet = this.keystore.mapWallet(storedKey); + await this.keystore.importWallet(wallet); + this.wallet = new StoredKeyWallet(storedKey); + console.log(`Wallet ${name} created, mnemonic: ${hdWallet.mnemonic()}`); + this.status(); + return this.wallet; + } catch (err) { + console.log(`Exception: ${err}`); + } + } + async import(mnemonic: string, name: string): Promise { + this.wallet = null; + if (!this.keystore) { return; } + try { + if (!WC.Mnemonic.isValid(mnemonic)) { + console.error(`Mnemonic is not valid ${mnemonic}`); + return null; + } + if (name === '') { name = this.autoFillName(name); } + // There are two ways to do this here: + // 1. Create HDWallet with mnemonic, create StoroedKey with it (add coins), then map to a KeyStore wallet and import it into the storage, or + // 2. Import in KeyStore directly (using mnemonic), and obtain StoredKey from it + let wallet = await this.keystore.import(mnemonic, name, this.StoreFixedPassword, this.DefaultCoins); + this.wallet = new StoredKeyWallet(this.keystore.mapStoredKey(wallet)); + console.log(`Wallet ${name} imported, mnemonic: ${mnemonic}`); + this.status(); + return this.wallet; + } catch (err) { + console.log(`Exception: ${err}`); + } + } + async addCoin(coin: string): Promise { + if (this.wallet == null) { + console.error('No wallet open, see walletCreate() / walletLoad() / walletsList()'); + return; + } + if (!this.keystore) { return; } + const wallet = await this.keystore.addAccounts(this.wallet?.wallet.identifier(), this.StoreFixedPassword, [coin]); + this.wallet = new StoredKeyWallet(this.keystore.mapStoredKey(wallet)); + } + // Delete loaded wallet + async delete(param: string): Promise { + if (!this.wallet) { + console.log(`No wallet loaded`); + return; + } + if (!this.keystore) { return; } + try { + if (param !== 'delete') { + console.log(`Are you sure? Invoke with 'delete' parameter!`); + return; + } + const name = this.wallet.wallet.name(); + const id = this.wallet.wallet.identifier(); + await this.keystore.delete(id, this.StoreFixedPassword); + this.wallet = null; + console.log(`Wallet '${name}' ${id} deleted.`); + await this.refreshStoreWallets(); + } catch (err) { + console.log(`Exception: ${err}`); + } + } + async deleteAll(param: string): Promise { + await this.refreshStoreWallets(); + if (this.storeWallets.length == 0) { + console.log(`No wallets found`); + return; + } + if (!this.keystore) { return; } + try { + if (param !== 'deleteall') { + console.log(`Are you sure? Invoke with 'deleteall' parameter!`); + return; + } + while (this.storeWallets.length > 0) { + const id = this.storeWallets[0].id; + await this.keystore.delete(id, this.StoreFixedPassword); + await this.refreshStoreWallets(); + } + this.wallet = null; + console.log(`All wallets deleted.`) + } catch (err) { + console.log(`Exception: ${err}`); + } + } + status(): void { + if (this.wallet === null) { + console.error(`No wallet open, ${this.storeWallets.length} available; see walletCreate() / walletLoad() / walletsList()`); + } else { + console.error(`Wallet open: ${this.wallet.status()}`); + } + } + dump(): void { + this.status(); + if (this.wallet) { + this.wallet.dump(); } } }; + // single global TestWalletManager instance + let wallets: TestWalletManager = new TestWalletManager(); + + async function walletsList() { await wallets.list(); } + async function walletLoad(index: number) { await wallets.load(index); } + async function walletsDeleteAll(param: string) { await wallets.deleteAll(param); } + async function walletCreate(strength: number = 256, name: string = ''): Promise { return await wallets.create(strength, name); } + async function walletImport(mnemonic: string, name: string = ''): Promise { return wallets.import(mnemonic, name); } + async function walletAddCoin(coin: string): Promise { return wallets.addCoin(coin); } + function walletDump(): void { wallets.dump(); } + async function walletDelete(param: string) { await wallets.delete(param); } + function help(): void { console.log('This is an interactive typescript shell, to work with wallet-core (wasm)'); console.log('You can use:'); @@ -127,42 +300,6 @@ function enumerateNamespaces(topLevelNamespace: any) { process.exit(code); } - function walletCreate(strength: number = 256, name: string = ''): any { - wallet = TestWallet.createRandom(name, strength); - console.log(`Wallet ${wallet.name} created, mnemonic: ${wallet.wallet.mnemonic()}`); - walletStatus(); - return wallet; - } - - function walletImport(mnemonic: string, name: string = ''): any { - if (!WC.Mnemonic.isValid(mnemonic)) { - console.error(`Mnemonic is not valid ${mnemonic}`); - return null; - } - wallet = TestWallet.createWithMnemonic(name, mnemonic); - console.log(`Wallet ${wallet.name} imported, mnemonic: ${wallet.wallet.mnemonic()}`); - walletStatus(); - return wallet; - } - - function walletStatus(): void { - if (wallet === null) { - console.error('No wallet, see createWallet()'); - } else { - console.error(`Wallet loaded: ${wallet.status()}`); - } - } - - function walletDump(): void { - walletStatus(); - if (wallet) { - wallet.dump(); - } - } - - // single global TestWallet instance - let wallet: TestWallet | null = null; - clear(); console.log( chalk.blue( @@ -181,6 +318,10 @@ function enumerateNamespaces(topLevelNamespace: any) { console.log(chalk.red(`This is a test tool, DO NOT USE WITH REAL FUNDS!`)); console.log(); + wallets.init(); + await wallets.refreshStoreWallets(); + await wallets.loadAWallet(); + const local = repl.start('> '); // Expose WC namespaces, as top-level @@ -190,18 +331,28 @@ function enumerateNamespaces(topLevelNamespace: any) { local.context.WC = WC; // Expose TW namespaces (under TW) local.context.TW = TW; + // Expose KeyStore namespace (under KeyStore) + local.context.KeyStore = KeyStore; // Expose more stuff; utilities local.context.help = help; local.context.exit = exit; + local.context.walletsList = walletsList; + local.context.walletLoad = walletLoad; + local.context.walletsDeleteAll = walletsDeleteAll; local.context.walletCreate = walletCreate; local.context.walletImport = walletImport; + local.context.walletAddCoin = walletAddCoin; local.context.walletDump = walletDump; - local.context.wallet = wallet; + local.context.walletDelete = walletDelete; + local.context.wallets = wallets; + local.context.wallet = wallets.wallet; local.context.coin = WC.CoinType.bitcoin; local.on('exit', () => { console.log('Bye!'); process.exit(); }); -})(); +} + +main(); From 8c207cb5ef66028f00071de15386a7e93df7dfe1 Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Tue, 27 Sep 2022 13:39:28 +0100 Subject: [PATCH 093/497] [Trezor] Fix buffer with unmatched bound warning (#2596) This change is in line with the upstream version: https://github.com/trezor/trezor-firmware/blob/master/crypto/sha2.c --- trezor-crypto/crypto/sha2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trezor-crypto/crypto/sha2.c b/trezor-crypto/crypto/sha2.c index 0f14e970874..bea30dae7cf 100644 --- a/trezor-crypto/crypto/sha2.c +++ b/trezor-crypto/crypto/sha2.c @@ -643,7 +643,7 @@ void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { usedspace = 0; } -char *sha1_End(SHA1_CTX* context, char buffer[]) { +char *sha1_End(SHA1_CTX* context, char buffer[SHA1_DIGEST_STRING_LENGTH]) { sha2_byte digest[SHA1_DIGEST_LENGTH] = {0}, *d = digest; int i = 0; @@ -950,7 +950,7 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { usedspace = 0; } -char *sha256_End(SHA256_CTX* context, char buffer[]) { +char *sha256_End(SHA256_CTX* context, char buffer[SHA256_DIGEST_STRING_LENGTH]) { sha2_byte digest[SHA256_DIGEST_LENGTH] = {0}, *d = digest; int i = 0; @@ -1269,7 +1269,7 @@ void sha512_Final(SHA512_CTX* context, sha2_byte digest[]) { memzero(context, sizeof(SHA512_CTX)); } -char *sha512_End(SHA512_CTX* context, char buffer[]) { +char *sha512_End(SHA512_CTX* context, char buffer[SHA512_DIGEST_STRING_LENGTH]) { sha2_byte digest[SHA512_DIGEST_LENGTH] = {0}, *d = digest; int i = 0; From 55235d4eb180ed0813fe52a8b8159ad1e86c0083 Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Wed, 28 Sep 2022 00:03:32 +0100 Subject: [PATCH 094/497] [WASM] Upgrade Emscripten version to 3.1.22 (#2601) --- tools/install-wasm-dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/install-wasm-dependencies b/tools/install-wasm-dependencies index 915f901e120..dcf17caa686 100755 --- a/tools/install-wasm-dependencies +++ b/tools/install-wasm-dependencies @@ -2,7 +2,7 @@ set -e -emsdk_version=3.1.14 +emsdk_version=3.1.22 git clone https://github.com/emscripten-core/emsdk.git From 84dac5211b3307a58bdbca156b019e8dce1aa125 Mon Sep 17 00:00:00 2001 From: wh Date: Thu, 29 Sep 2022 16:51:46 +0800 Subject: [PATCH 095/497] [Fix] fix some neo issues (#2599) * fix neo txid & asset id serialization missing zero leading issue * fix neo output reference not correct * fix TWCardanoGetStakingAddress not included issue * fix neo attribute serialize & deserialize not correct * fix some coding style and comments * use switch instead of if-else * use constants instead of number directly * add an empty line at the end of files --- src/NEO/CoinReference.h | 5 +- src/NEO/Constants.h | 16 +++++ src/NEO/Signer.cpp | 2 +- src/NEO/TransactionAttribute.h | 89 +++++++++++++++++++------ src/NEO/TransactionOutput.h | 13 ++-- tests/Cardano/TWCardanoAddressTests.cpp | 1 + tests/NEO/CoinReferenceTests.cpp | 8 +++ tests/NEO/TransactionAttributeTests.cpp | 16 +++-- tests/NEO/TransactionTests.cpp | 2 +- 9 files changed, 112 insertions(+), 40 deletions(-) create mode 100644 src/NEO/Constants.h diff --git a/src/NEO/CoinReference.h b/src/NEO/CoinReference.h index 1a7dd9fd120..8890f537d3d 100644 --- a/src/NEO/CoinReference.h +++ b/src/NEO/CoinReference.h @@ -19,6 +19,7 @@ class CoinReference : public Serializable { public: /// Number of bytes for prevIndex. static const size_t prevIndexSize = 2; + static const size_t prevHashSize = 32; uint256_t prevHash; uint16_t prevIndex = 0; @@ -35,7 +36,7 @@ class CoinReference : public Serializable { } Data serialize() const override { - auto resp = store(prevHash); + auto resp = store(prevHash, prevHashSize); encode16LE(prevIndex, resp); return resp; } @@ -46,4 +47,4 @@ class CoinReference : public Serializable { } }; -} \ No newline at end of file +} // namespace TW::NEO diff --git a/src/NEO/Constants.h b/src/NEO/Constants.h new file mode 100644 index 00000000000..817dc8840cf --- /dev/null +++ b/src/NEO/Constants.h @@ -0,0 +1,16 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +namespace TW::NEO { + +static const size_t assetIdSize = 32; +static const size_t contractHashSize = 32; +static const size_t valueSize = 8; +static const size_t scriptHashSize = 20; + +} // namespace TW::NEO diff --git a/src/NEO/Signer.cpp b/src/NEO/Signer.cpp index 3329497f39f..1824af1b940 100644 --- a/src/NEO/Signer.cpp +++ b/src/NEO/Signer.cpp @@ -78,7 +78,7 @@ Proto::TransactionPlan Signer::plan(const Proto::SigningInput& input) { for (int i = 0; i < input.outputs_size(); i++) { auto* outputPlan = plan.add_outputs(); - if (available.find(input.inputs(i).asset_id()) == available.end() || + if (available.find(input.outputs(i).asset_id()) == available.end() || available[input.outputs(i).asset_id()] < input.outputs(i).amount()) { throw Common::Proto::SigningError(Common::Proto::Error_low_balance); } diff --git a/src/NEO/TransactionAttribute.h b/src/NEO/TransactionAttribute.h index be027e9bfd0..e1ac1235651 100644 --- a/src/NEO/TransactionAttribute.h +++ b/src/NEO/TransactionAttribute.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,49 +6,96 @@ #pragma once -#include "TransactionAttributeUsage.h" +#include "Constants.h" #include "ISerializable.h" #include "Serializable.h" +#include "TransactionAttributeUsage.h" #include "Data.h" namespace TW::NEO { class TransactionAttribute : public Serializable { - public: +public: TransactionAttributeUsage usage = TAU_ContractHash; Data _data; virtual ~TransactionAttribute() {} int64_t size() const override { - return 1 + _data.size(); + switch (usage) { + case TransactionAttributeUsage::TAU_ContractHash: + case TransactionAttributeUsage::TAU_ECDH02: + case TransactionAttributeUsage::TAU_ECDH03: + case TransactionAttributeUsage::TAU_Vote: + return 1 + contractHashSize; + case TransactionAttributeUsage::TAU_Script: + return 1 + scriptHashSize; + default: + if (usage >= TransactionAttributeUsage::TAU_Hash1 && + usage <= TransactionAttributeUsage::TAU_Hash15) { + return 1 + contractHashSize; + } + return 1 + varIntSize(_data.size()) + _data.size(); + } } void deserialize(const Data& data, int initial_pos = 0) override { if (static_cast(data.size()) < initial_pos + 1) { throw std::invalid_argument("Invalid data for deserialization"); } - usage = (TransactionAttributeUsage) data[initial_pos]; - if (usage == TransactionAttributeUsage::TAU_ContractHash || usage == TransactionAttributeUsage::TAU_Vote || - (usage >= TransactionAttributeUsage::TAU_Hash1 && usage <= TransactionAttributeUsage::TAU_Hash15)) { - _data = readBytes(data, 32, initial_pos + 1); - } else if (usage == TransactionAttributeUsage::TAU_ECDH02 || - usage == TransactionAttributeUsage::TAU_ECDH03) { - _data = readBytes(data, 32, initial_pos + 1); - } else if (usage == TransactionAttributeUsage::TAU_Script) { - _data = readBytes(data, 20, initial_pos + 1); - } else if (usage == TransactionAttributeUsage::TAU_DescriptionUrl) { - _data = readBytes(data, 1, initial_pos + 1); - } else if (usage == TransactionAttributeUsage::TAU_Description || - usage >= TransactionAttributeUsage::TAU_Remark) { - _data = readBytes(data, int(data.size()) - 1 - initial_pos, initial_pos + 1); - } else { + + // see: https://github.com/neo-project/neo/blob/v2.12.0/neo/Network/P2P/Payloads/TransactionAttribute.cs#L32 + usage = (TransactionAttributeUsage)data[initial_pos]; + switch (usage) { + case TransactionAttributeUsage::TAU_ECDH02: + case TransactionAttributeUsage::TAU_ECDH03: { + this->_data = concat({(TW::byte)usage}, readBytes(data, contractHashSize, initial_pos + 1)); + break; + } + + case TransactionAttributeUsage::TAU_Script: { + this->_data = readBytes(data, scriptHashSize, initial_pos + 1); + break; + } + + case TransactionAttributeUsage::TAU_DescriptionUrl: + case TransactionAttributeUsage::TAU_Description: + case TransactionAttributeUsage::TAU_Remark: { + this->_data = readVarBytes(data, initial_pos + 1); + break; + } + + default: + if (usage == TransactionAttributeUsage::TAU_ContractHash || + usage == TransactionAttributeUsage::TAU_Vote || + (usage >= TransactionAttributeUsage::TAU_Hash1 && usage <= TransactionAttributeUsage::TAU_Hash15)) { + this->_data = readBytes(data, contractHashSize, initial_pos + 1); + break; + } throw std::invalid_argument("TransactionAttribute Deserialize FormatException"); } } Data serialize() const override { - return concat(Data({static_cast(usage)}), _data); + Data result; + result.push_back((TW::byte)usage); + + // see: https://github.com/neo-project/neo/blob/v2.12.0/neo/Network/P2P/Payloads/TransactionAttribute.cs#L49 + if (usage == TransactionAttributeUsage::TAU_DescriptionUrl || + usage == TransactionAttributeUsage::TAU_Description || + usage >= TransactionAttributeUsage::TAU_Remark) { + Data resp; + encodeVarInt((uint64_t)_data.size(), resp); + result.insert(result.end(), resp.begin(), resp.end()); + } + if (usage == TransactionAttributeUsage::TAU_ECDH02 || + usage == TransactionAttributeUsage::TAU_ECDH03) { + result.insert(result.end(), _data.begin() + 1, _data.begin() + 1 + contractHashSize); + } else { + result.insert(result.end(), _data.begin(), _data.end()); + } + + return result; } bool operator==(const TransactionAttribute &other) const { @@ -58,4 +105,4 @@ class TransactionAttribute : public Serializable { } }; -} +} // namespace TW::NEO diff --git a/src/NEO/TransactionOutput.h b/src/NEO/TransactionOutput.h index dd99028a687..cc52b032301 100644 --- a/src/NEO/TransactionOutput.h +++ b/src/NEO/TransactionOutput.h @@ -7,6 +7,7 @@ #pragma once #include "../uint256.h" +#include "Constants.h" #include "Data.h" #include "../BinaryCoding.h" #include "ReadData.h" @@ -17,10 +18,6 @@ namespace TW::NEO { class TransactionOutput : public Serializable { public: - static const size_t assetIdSize = 32; - static const size_t valueSize = 8; - static const size_t scriptHashSize = 20; - uint256_t assetId; int64_t value = 0; uint256_t scriptHash; @@ -28,7 +25,7 @@ class TransactionOutput : public Serializable { virtual ~TransactionOutput() {} int64_t size() const override { - return store(assetId).size() + valueSize + store(scriptHash).size(); + return store(assetId, assetIdSize).size() + valueSize + store(scriptHash, scriptHashSize).size(); } void deserialize(const Data& data, int initial_pos = 0) override { @@ -38,9 +35,9 @@ class TransactionOutput : public Serializable { } Data serialize() const override { - auto resp = store(assetId); + auto resp = store(assetId, assetIdSize); encode64LE(value, resp); - return concat(resp, store(scriptHash)); + return concat(resp, store(scriptHash, scriptHashSize)); } bool operator==(const TransactionOutput &other) const { @@ -50,4 +47,4 @@ class TransactionOutput : public Serializable { } }; -} \ No newline at end of file +} // namespace TW::NEO diff --git a/tests/Cardano/TWCardanoAddressTests.cpp b/tests/Cardano/TWCardanoAddressTests.cpp index 33af5be338b..4ce62f4e01a 100644 --- a/tests/Cardano/TWCardanoAddressTests.cpp +++ b/tests/Cardano/TWCardanoAddressTests.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff --git a/tests/NEO/CoinReferenceTests.cpp b/tests/NEO/CoinReferenceTests.cpp index 90c1f2700dc..1101986a96f 100644 --- a/tests/NEO/CoinReferenceTests.cpp +++ b/tests/NEO/CoinReferenceTests.cpp @@ -21,6 +21,14 @@ TEST(NEOCoinReference, Serialize) { EXPECT_EQ(prevHash + "0100", hex(coinReference.serialize())); } +TEST(NEOCoinReference, SerializeWithZeroLeading) { + auto coinReference = CoinReference(); + string prevHash = "0037ebf259ca5c6c43a5e7117c910858ea1146290e07d39e48554bc00d890b94"; + coinReference.prevHash = load(parse_hex(prevHash)); + coinReference.prevIndex = 1; + EXPECT_EQ(prevHash + "0100", hex(coinReference.serialize())); +} + TEST(NEOCoinReference, Deserialize) { auto coinReference = CoinReference(); coinReference.deserialize(parse_hex("bdecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4a0100")); diff --git a/tests/NEO/TransactionAttributeTests.cpp b/tests/NEO/TransactionAttributeTests.cpp index d911270c92f..73b64b14554 100644 --- a/tests/NEO/TransactionAttributeTests.cpp +++ b/tests/NEO/TransactionAttributeTests.cpp @@ -28,7 +28,9 @@ TEST(NEOTransactionAttribute, Serialize) { EXPECT_EQ("30" + data, hex(transactionAttribute.serialize())); transactionAttribute.usage = TransactionAttributeUsage::TAU_ECDH02; - transactionAttribute._data = parse_hex(data); + transactionAttribute._data = {(TW::byte)transactionAttribute.usage}; + auto d = parse_hex(data); + transactionAttribute._data.insert(transactionAttribute._data.end(), d.begin(), d.end()); EXPECT_EQ("02" + data, hex(transactionAttribute.serialize())); data = "bdecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af"; @@ -39,12 +41,12 @@ TEST(NEOTransactionAttribute, Serialize) { data = "bd"; transactionAttribute.usage = TransactionAttributeUsage::TAU_DescriptionUrl; transactionAttribute._data = parse_hex(data); - EXPECT_EQ("81" + data, hex(transactionAttribute.serialize())); + EXPECT_EQ("8101" + data, hex(transactionAttribute.serialize())); data = "bdecbb623eee6f9ade28d5a8ff5fb3ea"; transactionAttribute.usage = TransactionAttributeUsage::TAU_Remark; transactionAttribute._data = parse_hex(data); - EXPECT_EQ("f0" + data, hex(transactionAttribute.serialize())); + EXPECT_EQ("f010" + data, hex(transactionAttribute.serialize())); } TEST(NEOTransactionAttribute, Deserialize) { @@ -61,7 +63,7 @@ TEST(NEOTransactionAttribute, Deserialize) { transactionAttribute.deserialize(parse_hex("02" + data)); EXPECT_EQ(TransactionAttributeUsage::TAU_ECDH02, transactionAttribute.usage); - EXPECT_EQ(data, hex(transactionAttribute._data)); + EXPECT_EQ("02" + data, hex(transactionAttribute._data)); data = "bdecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af"; transactionAttribute.deserialize(parse_hex("20" + data)); @@ -69,12 +71,12 @@ TEST(NEOTransactionAttribute, Deserialize) { EXPECT_EQ(data, hex(transactionAttribute._data)); data = "bd"; - transactionAttribute.deserialize(parse_hex("81" + data)); + transactionAttribute.deserialize(parse_hex("8101" + data)); EXPECT_EQ(TransactionAttributeUsage::TAU_DescriptionUrl, transactionAttribute.usage); EXPECT_EQ(data, hex(transactionAttribute._data)); data = "bdecbb623eee6f9ade28d5a8ff5fb3ea"; - transactionAttribute.deserialize(parse_hex("f0" + data)); + transactionAttribute.deserialize(parse_hex("f010" + data)); EXPECT_EQ(TransactionAttributeUsage::TAU_Remark, transactionAttribute.usage); EXPECT_EQ(data, hex(transactionAttribute._data)); @@ -84,8 +86,8 @@ TEST(NEOTransactionAttribute, Deserialize) { TEST(NEOTransactionAttribute, DeserializeInitialPositionAfterData) { auto transactionAttribute = TransactionAttribute(); EXPECT_THROW(transactionAttribute.deserialize(Data(), 1), std::invalid_argument); - EXPECT_THROW(transactionAttribute.deserialize(Data({1}), 2), std::invalid_argument); } + } // namespace TW::NEO::tests diff --git a/tests/NEO/TransactionTests.cpp b/tests/NEO/TransactionTests.cpp index 08c328ea405..fc973084e90 100644 --- a/tests/NEO/TransactionTests.cpp +++ b/tests/NEO/TransactionTests.cpp @@ -62,7 +62,7 @@ TEST(NEOTransaction, SerializeDeserializeAttribute) { transaction.attributes.push_back(TransactionAttribute()); transaction.attributes[1].usage = TransactionAttributeUsage::TAU_ECDH02; - transaction.attributes[1]._data = parse_hex("b7ecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4a"); + transaction.attributes[1]._data = parse_hex("02b7ecbb623eee6f9ade28d5a8ff5fb3ea9c9d73af039e0286201b3b0291fb4d4a"); serialized = transaction.serialize(); const string twoVarLong = "02"; string expectedSerialized = "8007" + twoVarLong; From e446d8675017a5f92277eaef51a8ff16fa6b715f Mon Sep 17 00:00:00 2001 From: wh Date: Fri, 30 Sep 2022 18:06:56 +0800 Subject: [PATCH 096/497] [Fio] Fix `signatureToBase58` typo (#2606) * fix a typo of fio * fix signatureToBase58 issue --- src/FIO/Signer.cpp | 2 +- src/FIO/Signer.h | 2 +- src/FIO/TransactionBuilder.cpp | 2 +- tests/FIO/SignerTests.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/FIO/Signer.cpp b/src/FIO/Signer.cpp index 19b1803f624..e4390dd3b44 100644 --- a/src/FIO/Signer.cpp +++ b/src/FIO/Signer.cpp @@ -40,7 +40,7 @@ Data Signer::signData(const PrivateKey& privKey, const Data& data) { return signature; } -std::string Signer::signatureToBsase58(const Data& sig) { +std::string Signer::signatureToBase58(const Data& sig) { Data sigWithSuffix(sig); append(sigWithSuffix, TW::data(SignatureSuffix)); // take hash, ripemd, first 4 bytes diff --git a/src/FIO/Signer.h b/src/FIO/Signer.h index c41b072ed72..7e0800d71d9 100644 --- a/src/FIO/Signer.h +++ b/src/FIO/Signer.h @@ -30,7 +30,7 @@ class Signer { static Data signData(const PrivateKey& privKey, const Data& data); /// Used internally, encode signature to base58 with prefix. Ex.: "SIG_K1_K54CA1jmhgWrSdvrNrkokPyvqh7dwsSoQHNU9xgD3Ezf6cJySzhKeUubVRqmpYdnjoP1DM6SorroVAgrCu3qqvJ9coAQ6u" - static std::string signatureToBsase58(const Data& sig); + static std::string signatureToBase58(const Data& sig); /// Verify a signature, used in testing static bool verify(const PublicKey& pubKey, const Data& data, const Data& signature); diff --git a/src/FIO/TransactionBuilder.cpp b/src/FIO/TransactionBuilder.cpp index c0203ec9911..1c5fa2b4d8b 100644 --- a/src/FIO/TransactionBuilder.cpp +++ b/src/FIO/TransactionBuilder.cpp @@ -240,7 +240,7 @@ string TransactionBuilder::signAdnBuildTx(const Data& chainId, const Data& packe Data sigBuf(chainId); append(sigBuf, packedTx); append(sigBuf, TW::Data(32)); // context_free - string signature = Signer::signatureToBsase58(Signer::signData(privateKey, sigBuf)); + string signature = Signer::signatureToBase58(Signer::signData(privateKey, sigBuf)); // Build json json tx = { diff --git a/tests/FIO/SignerTests.cpp b/tests/FIO/SignerTests.cpp index e85ab9422d5..871db8d8091 100644 --- a/tests/FIO/SignerTests.cpp +++ b/tests/FIO/SignerTests.cpp @@ -18,7 +18,7 @@ namespace TW::FIO::tests { using namespace std; TEST(FIOSigner, SignEncode) { - string sig1 = Signer::signatureToBsase58(parse_hex("1f4fccc30bcba876963aef6de584daf7258306c02f4528fe25b116b517de8b349968bdc080cd6bef36f5a46d31a7c01ed0806ad215bb66a94f61e27a895d610983")); + string sig1 = Signer::signatureToBase58(parse_hex("1f4fccc30bcba876963aef6de584daf7258306c02f4528fe25b116b517de8b349968bdc080cd6bef36f5a46d31a7c01ed0806ad215bb66a94f61e27a895d610983")); EXPECT_EQ("SIG_K1_K5hJTPeiV4bDkNR13mf66N2DY5AtVL4NU1iWE4G4dsczY2q68oCcUVxhzFdxjgV2eAeb2jNV1biqtCJ3SaNL8kkNgoZ43H", sig1); } @@ -37,7 +37,7 @@ TEST(FIOSigner, SignInternals) { Data sign2 = Signer::signData(pk, rawData); EXPECT_EQ("1f4ae8d1b993f94d0de4b249d5185481770de0711863ad640b3aac21de598fcc02761c6e5395106bafb7b09aab1c7aa5ac0573dbd821c2d255725391a5105d30d1", hex(sign2)); - string sigStr = Signer::signatureToBsase58(sign2); + string sigStr = Signer::signatureToBase58(sign2); EXPECT_EQ("SIG_K1_K54CA1jmhgWrSdvrNrkokPyvqh7dwsSoQHNU9xgD3Ezf6cJySzhKeUubVRqmpYdnjoP1DM6SorroVAgrCu3qqvJ9coAQ6u", sigStr); EXPECT_TRUE(Signer::verify(pk.getPublicKey(TWPublicKeyTypeSECP256k1), hash, sign2)); } From 4efd4be01e6e49887d7915766a45be908ae8b169 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Fri, 30 Sep 2022 23:30:46 +0200 Subject: [PATCH 097/497] New swift test for external signature feature (#2607) --- swift/Tests/TransactionCompilerTests.swift | 176 ++++++++++++++++++ tests/TransactionCompilerTests.cpp | 8 +- .../interface/TWTransactionCompilerTests.cpp | 2 +- 3 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 swift/Tests/TransactionCompilerTests.swift diff --git a/swift/Tests/TransactionCompilerTests.swift b/swift/Tests/TransactionCompilerTests.swift new file mode 100644 index 00000000000..b5e147a65f5 --- /dev/null +++ b/swift/Tests/TransactionCompilerTests.swift @@ -0,0 +1,176 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import XCTest +import WalletCore + +class TransactionCompilerTests: XCTestCase { + override func setUp() { + continueAfterFailure = false + } + + func testBitcoinCompileWithSignatures() throws { + // Test external signining with a Bitcoin transaction with 3 input UTXOs, all used, but only using 2 public keys. + // Three signatures are neeeded. This illustrates that order of UTXOs/hashes is not always the same. + + let revUtxoHash0 = Data(hexString: "07c42b969286be06fae38528c85f0a1ce508d4df837eb5ac4cf5f2a7a9d65fa8")! + let revUtxoHash1 = Data(hexString: "d6892a5aa54e3b8fe430efd23f49a8950733aaa9d7c915d9989179f48dd1905e")! + let revUtxoHash2 = Data(hexString: "6021efcf7555f90627364339fc921139dd40a06ccb2cb2a2a4f8f4ea7a2dc74d")! + let inPubKey0 = Data(hexString: "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382")! + let inPubKey1 = Data(hexString: "0217142f69535e4dad0dc7060df645c55a174cc1bfa5b9eb2e59aad2ae96072dfc")! + let inPubKeyHash0 = Data(hexString: "bd92088bb7e82d611a9b94fbb74a0908152b784f")! + let inPubKeyHash1 = Data(hexString: "6641abedacf9483b793afe1718689cc9420bbb1c")! + + // Test data: Input UTXO infos + struct UtxoInfo { + let revUtxoHash: Data + let publicKey: Data + let amount: Int64 + let index: UInt32 + } + let utxoInfos: [UtxoInfo] = [ + // first + UtxoInfo(revUtxoHash: revUtxoHash0, publicKey: inPubKey0, amount: 600000, index: 0), + // second UTXO, with same pubkey + UtxoInfo(revUtxoHash: revUtxoHash1, publicKey: inPubKey0, amount: 500000, index: 1), + // third UTXO, with different pubkey + UtxoInfo(revUtxoHash: revUtxoHash2, publicKey: inPubKey1, amount: 400000, index: 0), + ] + + // Signature infos, indexed by pubkeyhash+hash + struct SignatureInfo { + let signature: Data + let publicKey: Data + } + let signatureInfos: [String: SignatureInfo] = [ + inPubKeyHash0.hexString + "+" + "a296bead4172007be69b21971a790e076388666c162a9505698415f1b003ebd7": + SignatureInfo(signature: Data(hexString: "304402201857bc6e6e48b46046a4bd204136fc77e24c240943fb5a1f0e86387aae59b34902200a7f31478784e51c49f46ef072745a4f263d7efdbc9c6784aa2571ff4f6f2a40")!, publicKey: inPubKey0), + inPubKeyHash1.hexString + "+" + "505f527f00e15fcc5a2d2416c9970beb57dfdfaca99e572a01f143b24dd8fab6": + SignatureInfo(signature: Data(hexString: "3044022041294880caa09bb1b653775310fcdd1458da6b8e7d7fae34e37966414fe115820220646397c9d2513edc5974ecc336e9b287de0cdf071c366f3b3dc3ff309213e4e4")!, publicKey: inPubKey1), + inPubKeyHash0.hexString + "+" + "60ed6e9371e5ddc72fd88e46a12cb2f68516ebd307c0fd31b1b55cf767272101": + SignatureInfo(signature: Data(hexString: "30440220764e3d5b3971c4b3e70b23fb700a7462a6fe519d9830e863a1f8388c402ad0b102207e777f7972c636961f92375a2774af3b7a2a04190251bbcb31d19c70927952dc")!, publicKey: inPubKey0), + ] + + let coin = CoinType.bitcoin + let ownAddress = "bc1qhkfq3zahaqkkzx5mjnamwjsfpq2jk7z00ppggv" + + // Setup input for Plan + var signingInput = BitcoinSigningInput.with { + $0.coinType = coin.rawValue + $0.hashType = BitcoinSigHashType.all.rawValue + $0.amount = 1200000 + $0.useMaxAmount = false + $0.byteFee = 1 + $0.toAddress = "bc1q2dsdlq3343vk29runkgv4yc292hmq53jedfjmp" + $0.changeAddress = ownAddress + } + + // process UTXOs + var count: UInt32 = 0 + for u in utxoInfos { + let publicKey = PublicKey(data: u.publicKey, type: PublicKeyType.secp256k1) + let address = SegwitAddress(hrp: .bitcoin, publicKey: publicKey!) + if (count == 0) { XCTAssertEqual(address.description, ownAddress) } + if (count == 1) { XCTAssertEqual(address.description, ownAddress) } + if (count == 2) { XCTAssertEqual(address.description, "bc1qveq6hmdvl9yrk7f6lct3s6yue9pqhwcuxedggg") } + + let utxoScript = BitcoinScript.lockScriptForAddress(address: address.description, coin: coin) + if (count == 0) { XCTAssertEqual(utxoScript.data.hexString, "0014bd92088bb7e82d611a9b94fbb74a0908152b784f") } + if (count == 1) { XCTAssertEqual(utxoScript.data.hexString, "0014bd92088bb7e82d611a9b94fbb74a0908152b784f") } + if (count == 2) { XCTAssertEqual(utxoScript.data.hexString, "00146641abedacf9483b793afe1718689cc9420bbb1c") } + + let keyHash: Data = utxoScript.matchPayToWitnessPublicKeyHash()! + if (count == 0) { XCTAssertEqual(keyHash.hexString, inPubKeyHash0.hexString) } + if (count == 1) { XCTAssertEqual(keyHash.hexString, inPubKeyHash0.hexString) } + if (count == 2) { XCTAssertEqual(keyHash.hexString, inPubKeyHash1.hexString) } + + let redeemScript = BitcoinScript.buildPayToPublicKeyHash(hash: keyHash) + if (count == 0) { XCTAssertEqual(redeemScript.data.hexString, "76a914bd92088bb7e82d611a9b94fbb74a0908152b784f88ac") } + if (count == 1) { XCTAssertEqual(redeemScript.data.hexString, "76a914bd92088bb7e82d611a9b94fbb74a0908152b784f88ac") } + if (count == 2) { XCTAssertEqual(redeemScript.data.hexString, "76a9146641abedacf9483b793afe1718689cc9420bbb1c88ac") } + signingInput.scripts[keyHash.hexString] = redeemScript.data + + let outPoint = BitcoinOutPoint.with { + $0.hash = u.revUtxoHash + $0.index = u.index + $0.sequence = UInt32.max + } + let utxo = BitcoinUnspentTransaction.with { + $0.script = utxoScript.data + $0.amount = u.amount + $0.outPoint = outPoint + } + signingInput.utxo.append(utxo) + + count += 1 + } + XCTAssertEqual(count, 3) + XCTAssertEqual(signingInput.utxo.count, 3) + + // Plan + let plan: BitcoinTransactionPlan = AnySigner.plan(input: signingInput, coin: coin) + + // At this point plan can be checked, assume it is accepted unmodified + XCTAssertEqual(plan.amount, 1200000) + XCTAssertEqual(plan.fee, 277) + XCTAssertEqual(plan.change, 299723) + XCTAssertEqual(plan.utxos.count, 3) + // Note that UTXOs happen to be in reverse order compared to the input + XCTAssertEqual(plan.utxos[0].outPoint.hash.hexString, revUtxoHash2.hexString) + XCTAssertEqual(plan.utxos[1].outPoint.hash.hexString, revUtxoHash1.hexString) + XCTAssertEqual(plan.utxos[2].outPoint.hash.hexString, revUtxoHash0.hexString) + + // Extend input with accepted plan + signingInput.plan = plan + + // Serialize input + let txInputData = try signingInput.serializedData() + XCTAssertEqual(txInputData.count, 692) + + /// Step 2: Obtain preimage hashes + let preImageHashes = TransactionCompiler.preImageHashes(coinType: coin, txInputData: txInputData) + let preSigningOutput: BitcoinPreSigningOutput = try BitcoinPreSigningOutput(serializedData: preImageHashes) + + XCTAssertEqual(preSigningOutput.error, CommonSigningError.ok) + XCTAssertEqual(preSigningOutput.hashPublicKeys[0].dataHash.hexString, "505f527f00e15fcc5a2d2416c9970beb57dfdfaca99e572a01f143b24dd8fab6") + XCTAssertEqual(preSigningOutput.hashPublicKeys[1].dataHash.hexString, "a296bead4172007be69b21971a790e076388666c162a9505698415f1b003ebd7") + XCTAssertEqual(preSigningOutput.hashPublicKeys[2].dataHash.hexString, "60ed6e9371e5ddc72fd88e46a12cb2f68516ebd307c0fd31b1b55cf767272101") + XCTAssertEqual(preSigningOutput.hashPublicKeys[0].publicKeyHash.hexString, inPubKeyHash1.hexString) + XCTAssertEqual(preSigningOutput.hashPublicKeys[1].publicKeyHash.hexString, inPubKeyHash0.hexString) + XCTAssertEqual(preSigningOutput.hashPublicKeys[2].publicKeyHash.hexString, inPubKeyHash0.hexString) + + // Simulate signatures, normally they are obtained from external source, e.g. a signature server. + var signatureVec = DataVector() + var pubkeyVec = DataVector() + for h in preSigningOutput.hashPublicKeys { + let preImageHash = h.dataHash + let pubkeyHash = h.publicKeyHash + + let key: String = pubkeyHash.hexString + "+" + preImageHash.hexString + XCTAssertTrue(signatureInfos.contains { $0.key == key }) + let sigInfo: SignatureInfo = signatureInfos[key]! + let publicKeyData = sigInfo.publicKey + let publicKey = PublicKey(data: publicKeyData, type: PublicKeyType.secp256k1) + let signature = sigInfo.signature + + signatureVec.add(data: signature) + pubkeyVec.add(data: publicKeyData) + + // Verify signature (pubkey & hash & signature) + publicKey?.verifyAsDER(signature: signature, message: preImageHash) + } + + /// Step 3: Compile transaction info + let compileWithSignatures = TransactionCompiler.compileWithSignatures(coinType: coin, txInputData: txInputData, signatures: signatureVec, publicKeys: pubkeyVec) + + let ExpectedTx = "010000000001036021efcf7555f90627364339fc921139dd40a06ccb2cb2a2a4f8f4ea7a2dc74d0000000000ffffffffd6892a5aa54e3b8fe430efd23f49a8950733aaa9d7c915d9989179f48dd1905e0100000000ffffffff07c42b969286be06fae38528c85f0a1ce508d4df837eb5ac4cf5f2a7a9d65fa80000000000ffffffff02804f1200000000001600145360df8231ac5965147c9d90ca930a2aafb05232cb92040000000000160014bd92088bb7e82d611a9b94fbb74a0908152b784f02473044022041294880caa09bb1b653775310fcdd1458da6b8e7d7fae34e37966414fe115820220646397c9d2513edc5974ecc336e9b287de0cdf071c366f3b3dc3ff309213e4e401210217142f69535e4dad0dc7060df645c55a174cc1bfa5b9eb2e59aad2ae96072dfc0247304402201857bc6e6e48b46046a4bd204136fc77e24c240943fb5a1f0e86387aae59b34902200a7f31478784e51c49f46ef072745a4f263d7efdbc9c6784aa2571ff4f6f2a400121024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382024730440220764e3d5b3971c4b3e70b23fb700a7462a6fe519d9830e863a1f8388c402ad0b102207e777f7972c636961f92375a2774af3b7a2a04190251bbcb31d19c70927952dc0121024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb49338200000000" + + XCTAssertEqual(compileWithSignatures.count, 786) + let output: BitcoinSigningOutput = try BitcoinSigningOutput(serializedData: compileWithSignatures) + XCTAssertEqual(output.encoded.count, 518) + XCTAssertEqual(output.encoded.hexString, ExpectedTx) + } +} diff --git a/tests/TransactionCompilerTests.cpp b/tests/TransactionCompilerTests.cpp index 0d9c8e4eab8..9590eb07ef6 100644 --- a/tests/TransactionCompilerTests.cpp +++ b/tests/TransactionCompilerTests.cpp @@ -99,7 +99,7 @@ TEST(TransactionCompiler, BinanceCompileWithSignatures) { } TEST(TransactionCompiler, BitcoinCompileWithSignatures) { - // Test external signining with a Bircoin transaction with 3 input UTXOs, all used, but only using 2 public keys. + // Test external signining with a Bitcoin transaction with 3 input UTXOs, all used, but only using 2 public keys. // Three signatures are neeeded. This illustrates that order of UTXOs/hashes is not always the same. const auto revUtxoHash0 = parse_hex("07c42b969286be06fae38528c85f0a1ce508d4df837eb5ac4cf5f2a7a9d65fa8"); @@ -110,7 +110,7 @@ TEST(TransactionCompiler, BitcoinCompileWithSignatures) { const auto inPubKeyHash0 = parse_hex("bd92088bb7e82d611a9b94fbb74a0908152b784f"); const auto inPubKeyHash1 = parse_hex("6641abedacf9483b793afe1718689cc9420bbb1c"); - // Input UTXO infos + // Test data: Input UTXO infos struct UtxoInfo { Data revUtxoHash; Data publicKey; @@ -210,7 +210,7 @@ TEST(TransactionCompiler, BitcoinCompileWithSignatures) { Bitcoin::Proto::TransactionPlan plan; ANY_PLAN(signingInput, plan, coin); - // Plan is checked, assume it is accepted + // At this point plan can be checked, assume it is accepted unmodified EXPECT_EQ(plan.amount(), 1'200'000); EXPECT_EQ(plan.fee(), 277); EXPECT_EQ(plan.change(), 299'723); @@ -240,7 +240,7 @@ TEST(TransactionCompiler, BitcoinCompileWithSignatures) { EXPECT_EQ(hex(preSigningOutput.hash_public_keys()[1].public_key_hash()), hex(inPubKeyHash0)); EXPECT_EQ(hex(preSigningOutput.hash_public_keys()[2].public_key_hash()), hex(inPubKeyHash0)); - // Simulate signatures, normally obtained from signature server. + // Simulate signatures, normally they are obtained from external source, e.g. a signature server. std::vector signatureVec; std::vector pubkeyVec; for (const auto& h: preSigningOutput.hash_public_keys()) { diff --git a/tests/interface/TWTransactionCompilerTests.cpp b/tests/interface/TWTransactionCompilerTests.cpp index 5793a97340a..20cab4a754e 100644 --- a/tests/interface/TWTransactionCompilerTests.cpp +++ b/tests/interface/TWTransactionCompilerTests.cpp @@ -199,7 +199,7 @@ Data dataFromTWData(std::shared_ptr data) { } TEST(TWTransactionCompiler, ExternalSignatureSignBitcoin) { - // Test external signining with a Bircoin transaction with 3 input UTXOs, all used, but only using 2 public keys. + // Test external signining with a Bitcoin transaction with 3 input UTXOs, all used, but only using 2 public keys. // Three signatures are neeeded. This illustrates that order of UTXOs/hashes is not always the same. const auto revUtxoHash0 = parse_hex("07c42b969286be06fae38528c85f0a1ce508d4df837eb5ac4cf5f2a7a9d65fa8"); From 0ea61af0ae2f0a61cdc868126504df855a105d05 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 3 Oct 2022 13:31:40 +0200 Subject: [PATCH 098/497] [Aptos]: Add Aptos chain (#2595) --- .../blockchains/CoinAddressDerivationTests.kt | 1 + .../app/blockchains/aptos/TestAptosAddress.kt | 28 +++ .../app/blockchains/aptos/TestAptosSigner.kt | 58 +++++ docs/registry.md | 1 + include/TrustWalletCore/TWBlockchain.h | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 30 +++ src/Aptos/Address.cpp | 88 +++++++ src/Aptos/Address.h | 58 +++++ src/Aptos/Entry.cpp | 26 ++ src/Aptos/Entry.h | 22 ++ src/Aptos/MoveTypes.cpp | 146 +++++++++++ src/Aptos/MoveTypes.h | 101 ++++++++ src/Aptos/Signer.cpp | 115 +++++++++ src/Aptos/Signer.h | 27 ++ src/Aptos/TransactionBuilder.h | 100 ++++++++ src/Aptos/TransactionPayload.cpp | 57 +++++ src/Aptos/TransactionPayload.h | 46 ++++ src/BCS.cpp | 42 ++++ src/BCS.h | 222 +++++++++++++++++ src/Coin.cpp | 3 + src/concepts/tw_concepts.h | 19 ++ src/proto/Aptos.proto | 92 +++++++ swift/Tests/Blockchains/AptosTests.swift | 48 ++++ swift/Tests/CoinAddressDerivationTests.swift | 3 + tests/Aptos/AddressTests.cpp | 54 ++++ tests/Aptos/MoveTypesTests.cpp | 59 +++++ tests/Aptos/SignerTests.cpp | 231 ++++++++++++++++++ tests/Aptos/TWAnySignerTests.cpp | 63 +++++ tests/Aptos/TWAptosAddressTests.cpp | 34 +++ tests/Aptos/TWCoinTypeTests.cpp | 35 +++ tests/Aptos/TransactionPayloadTests.cpp | 32 +++ tests/BCSTests.cpp | 165 +++++++++++++ tests/Cardano/TWCardanoAddressTests.cpp | 1 + tests/CoinAddressDerivationTests.cpp | 3 + tests/HDWallet/HDWalletTests.cpp | 11 + 36 files changed, 2023 insertions(+) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosAddress.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt create mode 100644 src/Aptos/Address.cpp create mode 100644 src/Aptos/Address.h create mode 100644 src/Aptos/Entry.cpp create mode 100644 src/Aptos/Entry.h create mode 100644 src/Aptos/MoveTypes.cpp create mode 100644 src/Aptos/MoveTypes.h create mode 100644 src/Aptos/Signer.cpp create mode 100644 src/Aptos/Signer.h create mode 100644 src/Aptos/TransactionBuilder.h create mode 100644 src/Aptos/TransactionPayload.cpp create mode 100644 src/Aptos/TransactionPayload.h create mode 100644 src/BCS.cpp create mode 100644 src/BCS.h create mode 100644 src/concepts/tw_concepts.h create mode 100644 src/proto/Aptos.proto create mode 100644 swift/Tests/Blockchains/AptosTests.swift create mode 100644 tests/Aptos/AddressTests.cpp create mode 100644 tests/Aptos/MoveTypesTests.cpp create mode 100644 tests/Aptos/SignerTests.cpp create mode 100644 tests/Aptos/TWAnySignerTests.cpp create mode 100644 tests/Aptos/TWAptosAddressTests.cpp create mode 100644 tests/Aptos/TWCoinTypeTests.cpp create mode 100644 tests/Aptos/TransactionPayloadTests.cpp create mode 100644 tests/BCSTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 55d6d14dd38..34765728c77 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -105,5 +105,6 @@ class CoinAddressDerivationTests { NATIVEEVMOS -> assertEquals("evmos13u6g7vqgw074mgmf2ze2cadzvkz9snlwstd20d", address) NERVOS -> assertEquals("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02wectaumxn0664yw2jd53lqk4mxg3", address) EVERSCALE -> assertEquals("0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04", address) + APTOS -> assertEquals("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", address) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosAddress.kt new file mode 100644 index 00000000000..180617ff5b1 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosAddress.kt @@ -0,0 +1,28 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.aptos + +import org.junit.Assert.assertFalse +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestAptosAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val any = AnyAddress("0x6af7d07b8a541913dfa87a9f99628faa255c70241ef9ebd9b82a7e715ee13108", CoinType.APTOS) + assertEquals(any.coin(), CoinType.APTOS) + assertEquals(any.description(), "0x6af7d07b8a541913dfa87a9f99628faa255c70241ef9ebd9b82a7e715ee13108") + + assertFalse(AnyAddress.isValid("0xMQqpqMQgCBuiPkoXfgZZsJvuzCeI1zc00z6vHJj4", CoinType.APTOS)) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt new file mode 100644 index 00000000000..32df8c8e33e --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt @@ -0,0 +1,58 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.aptos + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.proto.Aptos + +class TestAptosSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun AptosTransactionSigning() { + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xbb3b3c33781c27e486afa2db854fb0a5c846d0967672feb2c6c3297a2b14e1ce?network=Devnet + val key = + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec".toHexBytesInByteString() + + val transfer = Aptos.TransferMessage.newBuilder().setAmount(1000) + .setTo("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30").build() + val signingInput = Aptos.SigningInput.newBuilder().setChainId(32) + .setSender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30") + .setSequenceNumber(15) + .setGasUnitPrice(100) + .setMaxGasAmount(3296766) + .setExpirationTimestampSecs(3664390082) + .setTransfer(transfer) + .setPrivateKey(key) + .build() + + val result = AnySigner.sign(signingInput, CoinType.APTOS, Aptos.SigningOutput.parser()) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.rawTxn.toByteArray())), + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000020" + ) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.authenticator.signature.toByteArray())), + "2ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05" + ) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.encoded.toByteArray())), + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000200020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c402ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05" + ) + } +} diff --git a/docs/registry.md b/docs/registry.md index 755c49365ac..2bc175c03ad 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -50,6 +50,7 @@ This list is generated from [./registry.json](../registry.json) | 500 | Theta | THETA | | | | 501 | Solana | SOL | | | | 508 | Elrond | eGLD | | | +| 637 | Aptos | APT | | | | 714 | BNB Beacon Chain | BNB | | | | 818 | VeChain | VET | | | | 820 | Callisto | CLO | | | diff --git a/include/TrustWalletCore/TWBlockchain.h b/include/TrustWalletCore/TWBlockchain.h index eb289fc6d43..80fe59660ce 100644 --- a/include/TrustWalletCore/TWBlockchain.h +++ b/include/TrustWalletCore/TWBlockchain.h @@ -54,6 +54,7 @@ enum TWBlockchain { TWBlockchainKusama = 40, // Polkadot TWBlockchainNervos = 41, TWBlockchainEverscale = 42, + TWBlockchainAptos = 43, // Aptos }; TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 002b622c28a..831f9c3124a 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -116,6 +116,7 @@ enum TWCoinType { TWCoinTypeOKXChain = 996, TWCoinTypeNervos = 309, TWCoinTypeEverscale = 396, + TWCoinTypeAptos = 637, }; /// Returns the blockchain for a coin type. diff --git a/registry.json b/registry.json index 537498c91ac..2c8dcb73ebe 100644 --- a/registry.json +++ b/registry.json @@ -393,6 +393,36 @@ "documentation": "https://www.icondev.io/docs/icon-json-rpc-v3" } }, + { + "id": "aptos", + "name": "Aptos", + "displayName": "Aptos", + "coinId": 637, + "symbol": "APT", + "decimals": 8, + "chainId": "1", + "blockchain": "Aptos", + "derivation": [ + { + "path": "m/44'/637'/0'/0'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://explorer.aptoslabs.com", + "txPath": "/txn/", + "accountPath": "/account/", + "sampleTx": "91424546", + "sampleAccount": "0x6af7d07b8a541913dfa87a9f99628faa255c70241ef9ebd9b82a7e715ee13108" + }, + "info": { + "url": "https://aptoslabs.com/", + "source": "https://github.com/aptos-labs/aptos-core", + "rpc": "https://fullnode.devnet.aptoslabs.com", + "documentation": "https://fullnode.devnet.aptoslabs.com/v1/spec#/" + } + }, { "id": "cosmos", "name": "Cosmos", diff --git a/src/Aptos/Address.cpp b/src/Aptos/Address.cpp new file mode 100644 index 00000000000..30c1b587872 --- /dev/null +++ b/src/Aptos/Address.cpp @@ -0,0 +1,88 @@ +// Copyright © 2017-2022 Trust Wallet. +// Author: Clement Doumergue +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Address.h" +#include "HexCoding.h" + +namespace { + +std::string normalize(const std::string& string, std::size_t hexLen) { + std::string hexStr((TW::Aptos::Address::size * 2) - hexLen, '0'); + hexStr.append(string); + return hexStr; +} + +} // namespace + +namespace TW::Aptos { + +bool Address::isValid(const std::string& string) { + auto address = string; + if (address.starts_with("0x")) { + address = address.substr(2); + if (std::size_t hexLen = address.size(); hexLen < Address::size * 2) { + address = normalize(address, hexLen); + } + } + if (address.size() != 2 * Address::size) { + return false; + } + const auto data = parse_hex(address); + return isValid(data); +} + +Address::Address(const std::string& string) { + if (!isValid(string)) { + throw std::invalid_argument("Invalid address string"); + } + auto hexFunctor = [&string]() { + if (std::size_t hexLen = string.size() - 2; string.starts_with("0x") && hexLen < Address::size * 2) { + //! We have specific address like 0x1, padding it. + return parse_hex(normalize(string.substr(2), hexLen)); + } else { + return parse_hex(string); + } + }; + + const auto data = hexFunctor(); + std::copy(data.begin(), data.end(), bytes.begin()); +} + +Address::Address(const Data& data) { + if (!isValid(data)) { + throw std::invalid_argument("Invalid address data"); + } + std::copy(data.begin(), data.end(), bytes.begin()); +} + +Address::Address(const PublicKey& publicKey) { + if (publicKey.type != TWPublicKeyTypeED25519) { + throw std::invalid_argument("Invalid public key type"); + } + auto key_data = publicKey.bytes; + append(key_data, 0x00); + const auto data = Hash::sha3_256(key_data); + std::copy(data.begin(), data.end(), bytes.begin()); +} + +std::string Address::string(bool withPrefix) const { + std::string output = withPrefix ? "0x" : ""; + return output + hex(bytes); +} + +std::string Address::shortString() const { + std::string s = hex(bytes); + s.erase(0, s.find_first_not_of('0')); + return s; +} + +BCS::Serializer& operator<<(BCS::Serializer& stream, Address addr) noexcept { + stream.add_bytes(addr.bytes.begin(), addr.bytes.end()); + return stream; +} + +} // namespace TW::Aptos diff --git a/src/Aptos/Address.h b/src/Aptos/Address.h new file mode 100644 index 00000000000..52b995fa3be --- /dev/null +++ b/src/Aptos/Address.h @@ -0,0 +1,58 @@ +// Copyright © 2017-2022 Trust Wallet. +// Author: Clement Doumergue +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "BCS.h" +#include "Data.h" +#include "../PublicKey.h" + +#include + +namespace TW::Aptos { + +class Address { +public: + static constexpr size_t size = 32; + + std::array bytes; + + /// Determines whether a collection of bytes makes a valid address. + static bool isValid(const Data& data) { return data.size() == size; } + + /// Determines whether a string makes a valid address. + static bool isValid(const std::string& string); + + /// Initializes an Aptos address with a string representation. + explicit Address(const std::string& string); + + /// Initializes an Aptos address with a collection of bytes + explicit Address(const Data& data); + + /// Initializes an Aptos address with a public key. + explicit Address(const PublicKey& publicKey); + + /// Constructor that allow factory programming; + Address() noexcept = default; + + /// Returns a string representation of the address. + [[nodiscard]] std::string string(bool withPrefix = true) const; + + /// Returns a short string representation of the address. E.G 0x1; + [[nodiscard]] std::string shortString() const; +}; + +constexpr inline bool operator==(const Address& lhs, const Address& rhs) noexcept { + return lhs.bytes == rhs.bytes; +} + +inline const Address gAddressZero = Address("0x0"); +inline const Address gAddressOne = Address("0x1"); + +BCS::Serializer& operator<<(BCS::Serializer& stream, Address) noexcept; + +} // namespace TW::Aptos diff --git a/src/Aptos/Entry.cpp b/src/Aptos/Entry.cpp new file mode 100644 index 00000000000..4c299f946a2 --- /dev/null +++ b/src/Aptos/Entry.cpp @@ -0,0 +1,26 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Entry.h" + +#include "Address.h" +#include "Signer.h" + +namespace TW::Aptos { + +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { + return Address::isValid(address); +} + +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { + return Address(publicKey).string(); +} + +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { + signTemplate(dataIn, dataOut); +} + +} // namespace TW::Aptos diff --git a/src/Aptos/Entry.h b/src/Aptos/Entry.h new file mode 100644 index 00000000000..0fd1ab1d008 --- /dev/null +++ b/src/Aptos/Entry.h @@ -0,0 +1,22 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "../CoinEntry.h" + +namespace TW::Aptos { + +/// Entry point for implementation of Aptos coin. +/// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file +class Entry final : public CoinEntry { +public: + bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; +}; + +} // namespace TW::Aptos diff --git a/src/Aptos/MoveTypes.cpp b/src/Aptos/MoveTypes.cpp new file mode 100644 index 00000000000..884df19ec10 --- /dev/null +++ b/src/Aptos/MoveTypes.cpp @@ -0,0 +1,146 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include + +namespace TW::Aptos { + +Aptos::ModuleId::ModuleId(Address accountAddress, Identifier name) noexcept + : mAccountAddress(accountAddress), mName(std::move(name)) { +} + +Data ModuleId::accessVector() const noexcept { + BCS::Serializer serializer; + serializer << static_cast(gCodeTag) << mAccountAddress << mName; + return serializer.bytes; +} + +std::string ModuleId::string() const noexcept { + std::stringstream ss; + ss << mAccountAddress.string() << "::" << mName; + return ss.str(); +} + +std::string ModuleId::shortString() const noexcept { + std::stringstream ss; + ss << "0x" << mAccountAddress.shortString() << "::" << mName; + return ss.str(); +} + +Data StructTag::serialize(bool withResourceTag) const noexcept { + BCS::Serializer serializer; + if (withResourceTag) + { + serializer << gResourceTag; + } + serializer << mAccountAddress << mModule << mName << mTypeParams; + return serializer.bytes; +} + +StructTag::StructTag(Address accountAddress, Identifier module, Identifier name, std::vector typeParams) noexcept + : mAccountAddress(accountAddress), mModule(std::move(module)), mName(std::move(name)), mTypeParams(std::move(typeParams)) { +} +std::string StructTag::string() const noexcept { + std::stringstream ss; + ss << "0x" << mAccountAddress.shortString() << "::" << mModule << "::" << mName; + if (!mTypeParams.empty()) { + ss << "<"; + ss << TypeTagToString(*mTypeParams.begin()); + std::for_each(begin(mTypeParams) + 1, end(mTypeParams), [&ss](auto&& cur) { + ss << ", " << TypeTagToString(cur); + }); + ss << ">"; + } + return ss.str(); +} + +BCS::Serializer& operator<<(BCS::Serializer& stream, Bool) noexcept { + stream << Bool::value; + return stream; +} +BCS::Serializer& operator<<(BCS::Serializer& stream, U8) noexcept { + stream << U8::value; + return stream; +} +BCS::Serializer& operator<<(BCS::Serializer& stream, U64) noexcept { + stream << U64::value; + return stream; +} +BCS::Serializer& operator<<(BCS::Serializer& stream, U128) noexcept { + stream << U128::value; + return stream; +} +BCS::Serializer& operator<<(BCS::Serializer& stream, TAddress) noexcept { + stream << TAddress::value; + return stream; +} +BCS::Serializer& operator<<(BCS::Serializer& stream, TSigner) noexcept { + stream << TSigner::value; + return stream; +} + +BCS::Serializer& operator<<(BCS::Serializer& stream, const StructTag& st) noexcept { + auto res = st.serialize(); + stream.add_bytes(begin(res), end(res)); + return stream; +} + +BCS::Serializer& operator<<(BCS::Serializer& stream, const TStructTag& st) noexcept { + stream << TStructTag::value; + auto res = st.st.serialize(false); + stream.add_bytes(begin(res), end(res)); + return stream; +} + +BCS::Serializer& operator<<(BCS::Serializer& stream, const Vector& t) noexcept { + stream << Vector::value; + for (auto&& cur: t.tags) { + stream << cur; + } + return stream; +} + +BCS::Serializer& operator<<(BCS::Serializer& stream, const TypeTag& t) noexcept { + std::visit([&stream](auto&& arg) { stream << arg; }, t.tags); + return stream; +} + +BCS::Serializer& operator<<(BCS::Serializer& stream, const ModuleId& module) noexcept { + stream << module.address() << module.name(); + return stream; +} +std::string TypeTagToString(const TypeTag& typeTag) noexcept { + auto visit_functor = [](const TypeTag::TypeTagVariant& value) -> std::string { + if (std::holds_alternative(value)) { + return "bool"; + } else if (std::holds_alternative(value)) { + return "u8"; + } else if (std::holds_alternative(value)) { + return "u64"; + } else if (std::holds_alternative(value)) { + return "u128"; + } else if (std::holds_alternative(value)) { + return "address"; + } else if (std::holds_alternative(value)) { + return "signer"; + } else if (auto* vectorData = std::get_if(&value); vectorData != nullptr && !vectorData->tags.empty()) { + std::stringstream ss; + ss << "vector<" << TypeTagToString(*vectorData->tags.begin()) << ">"; + return ss.str(); + } else if (auto* structData = std::get_if(&value); structData) { + return structData->string(); + } else if (auto* tStructData = std::get_if(&value); tStructData) { + return tStructData->st.string(); + } else { + return ""; + } + }; + + return std::visit(visit_functor, typeTag.tags); +} + +} // namespace TW::Aptos diff --git a/src/Aptos/MoveTypes.h b/src/Aptos/MoveTypes.h new file mode 100644 index 00000000000..d3810f300a3 --- /dev/null +++ b/src/Aptos/MoveTypes.h @@ -0,0 +1,101 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Aptos/Address.h" +#include "BCS.h" +#include + +namespace TW::Aptos { + +constexpr std::uint8_t gCodeTag{0}; +constexpr std::uint8_t gResourceTag{1}; +using Identifier = std::string; + +class ModuleId { +public: + ///< Constructor + ModuleId(Address accountAddress, Identifier name) noexcept; + + ///< Getters + [[nodiscard]] const std::string& name() const noexcept { return mName; } + [[nodiscard]] const Address& address() const noexcept { return mAccountAddress; } + [[nodiscard]] Data accessVector() const noexcept; + [[nodiscard]] std::string string() const noexcept; + [[nodiscard]] std::string shortString() const noexcept; + +private: + Address mAccountAddress; + Identifier mName; +}; + +BCS::Serializer& operator<<(BCS::Serializer& stream, const ModuleId& module) noexcept; + +struct TypeTag; + +struct Bool { + static constexpr std::uint8_t value = 0; +}; +struct U8 { + static constexpr std::uint8_t value = 1; +}; +struct U64 { + static constexpr std::uint8_t value = 2; +}; +struct U128 { + static constexpr std::uint8_t value = 3; +}; +struct TAddress { + static constexpr std::uint8_t value = 4; +}; +struct TSigner { + static constexpr std::uint8_t value = 5; +}; +struct Vector { + static constexpr std::uint8_t value = 6; + std::vector tags; +}; + +class StructTag { +public: + explicit StructTag(Address accountAddress, Identifier module, Identifier name, std::vector typeParams) noexcept; + [[nodiscard]] Data serialize(bool withResourceTag = true) const noexcept; + [[nodiscard]] ModuleId moduleID() const noexcept { return {mAccountAddress, mName}; }; + [[nodiscard]] std::string string() const noexcept; + +private: + Address mAccountAddress; + Identifier mModule; + Identifier mName; + std::vector mTypeParams; +}; + +// C++ limitation, the first StructTag will serialize with ResourceTag, the inner one will use the value 7 instead. Tweaking by wrapping the struct +struct TStructTag { + static constexpr std::uint8_t value = 7; + StructTag st; +}; + +struct TypeTag { + using TypeTagVariant = std::variant; + TypeTagVariant tags; +}; + +std::string TypeTagToString(const TypeTag& typeTag) noexcept; +BCS::Serializer& operator<<(BCS::Serializer& stream, const StructTag& st) noexcept; +BCS::Serializer& operator<<(BCS::Serializer& stream, Bool) noexcept; +BCS::Serializer& operator<<(BCS::Serializer& stream, U8) noexcept; +BCS::Serializer& operator<<(BCS::Serializer& stream, U64) noexcept; +BCS::Serializer& operator<<(BCS::Serializer& stream, U128) noexcept; +BCS::Serializer& operator<<(BCS::Serializer& stream, TAddress) noexcept; +BCS::Serializer& operator<<(BCS::Serializer& stream, TSigner) noexcept; +BCS::Serializer& operator<<(BCS::Serializer& stream, const Vector& t) noexcept; +BCS::Serializer& operator<<(BCS::Serializer& stream, const TStructTag& t) noexcept; +BCS::Serializer& operator<<(BCS::Serializer& stream, const TypeTag& t) noexcept; +static const TypeTag gTransferTag = {TypeTag::TypeTagVariant(TStructTag{.st = StructTag(gAddressOne, "aptos_coin", "AptosCoin", {})})}; + +} // namespace TW::Aptos diff --git a/src/Aptos/Signer.cpp b/src/Aptos/Signer.cpp new file mode 100644 index 00000000000..eb1e05424d4 --- /dev/null +++ b/src/Aptos/Signer.cpp @@ -0,0 +1,115 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Signer.h" +#include "Address.h" +#include "Hash.h" +#include "MoveTypes.h" +#include "TransactionBuilder.h" +#include "TransactionPayload.h" + +namespace TW::Aptos { + +template +std::pair, nlohmann::json> commonTransferPayload(const TPayload& input) { + BCS::Serializer aSerializer; + aSerializer << Address(input.to()); + std::vector args; + args.emplace_back(aSerializer.bytes); + aSerializer.clear(); + aSerializer << input.amount(); + args.emplace_back(aSerializer.bytes); + nlohmann::json argsJson = nlohmann::json::array({input.to(), std::to_string(input.amount())}); + return std::make_pair(args, argsJson); +} + +TransactionPayload transferPayload(const Proto::SigningInput& input) { + auto&& [args, argsJson] = commonTransferPayload(input.transfer()); + ModuleId module(gAddressOne, "coin"); + TransactionPayload payload = EntryFunction(module, "transfer", {gTransferTag}, args, argsJson); + return payload; +} + +TransactionPayload createAccountPayload(const Proto::SigningInput& input) { + ModuleId module(gAddressOne, "aptos_account"); + BCS::Serializer aSerializer; + aSerializer << Address(input.create_account().auth_key()); + std::vector args; + args.emplace_back(aSerializer.bytes); + nlohmann::json argsJson = nlohmann::json::array({input.create_account().auth_key()}); + TransactionPayload payload = EntryFunction(module, "create_account", {}, args, argsJson); + return payload; +} + +TransactionPayload tokenTransferPayload(const Proto::SigningInput& input) { + + auto&& [args, argsJson] = commonTransferPayload(input.token_transfer()); + auto& function = input.token_transfer().function(); + TypeTag tokenTransferTag = {TypeTag::TypeTagVariant(TStructTag{.st = StructTag(Address(function.account_address()), + function.module(), function.name(), {})})}; + ModuleId module(gAddressOne, "coin"); + TransactionPayload payload = EntryFunction(module, "transfer", {tokenTransferTag}, args, argsJson); + return payload; +} + +Proto::SigningOutput blindSign(const Proto::SigningInput& input) { + auto output = Proto::SigningOutput(); + BCS::Serializer serializer; + auto encodedCall = parse_hex(input.any_encoded()); + serializer.add_bytes(begin(encodedCall), end(encodedCall)); + auto privateKey = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); + auto signature = privateKey.sign(encodedCall, TWCurveED25519); + auto pubKeyData = privateKey.getPublicKey(TWPublicKeyTypeED25519).bytes; + output.set_raw_txn(encodedCall.data(), encodedCall.size()); + output.mutable_authenticator()->set_public_key(pubKeyData.data(), pubKeyData.size()); + output.mutable_authenticator()->set_signature(signature.data(), signature.size()); + serializer << BCS::uleb128{.value = 0} << pubKeyData << signature; + output.set_encoded(serializer.bytes.data(), serializer.bytes.size()); + + // clang-format off + nlohmann::json json = { + {"type", "ed25519_signature"}, + {"public_key", hexEncoded(pubKeyData)}, + {"signature", hexEncoded(signature)} + }; + // clang-format on + + output.set_json(json.dump()); + return output; +} + +Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) { + auto protoOutput = Proto::SigningOutput(); + if (!input.any_encoded().empty()) { + return blindSign(input); + } + auto payloadFunctor = [&input]() { + switch (input.transaction_payload_case()) { + case Proto::SigningInput::kTransfer: { + return transferPayload(input); + } + case Proto::SigningInput::kTokenTransfer: { + return tokenTransferPayload(input); + } + case Proto::SigningInput::kCreateAccount: + return createAccountPayload(input); + case Proto::SigningInput::TRANSACTION_PAYLOAD_NOT_SET: + throw std::runtime_error("Transaction payload should be set"); + } + }; + TransactionBuilder::builder() + .sender(Address(input.sender())) + .sequenceNumber(input.sequence_number()) + .payload(payloadFunctor()) + .maxGasAmount(input.max_gas_amount()) + .gasUnitPrice(input.gas_unit_price()) + .expirationTimestampSecs(input.expiration_timestamp_secs()) + .chainId(static_cast(input.chain_id())) + .sign(input, protoOutput); + return protoOutput; +} + +} // namespace TW::Aptos diff --git a/src/Aptos/Signer.h b/src/Aptos/Signer.h new file mode 100644 index 00000000000..ad1f09ffdd8 --- /dev/null +++ b/src/Aptos/Signer.h @@ -0,0 +1,27 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" +#include "../PrivateKey.h" +#include "../proto/Aptos.pb.h" + +namespace TW::Aptos { + +inline const Data gAptosSalt = data("APTOS::RawTransaction"); + +/// Helper class that performs Aptos transaction signing. +class Signer { +public: + /// Hide default constructor + Signer() = delete; + + /// Signs a Proto::SigningInput transaction + static Proto::SigningOutput sign(const Proto::SigningInput& input); +}; + +} // namespace TW::Aptos diff --git a/src/Aptos/TransactionBuilder.h b/src/Aptos/TransactionBuilder.h new file mode 100644 index 00000000000..20f37a591ff --- /dev/null +++ b/src/Aptos/TransactionBuilder.h @@ -0,0 +1,100 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "HexCoding.h" +#include "TransactionPayload.h" +#include + +namespace TW::Aptos { + +class TransactionBuilder { +public: + TransactionBuilder() noexcept = default; + + static TransactionBuilder builder() noexcept { return {}; } + + TransactionBuilder& sender(Address sender) noexcept { + mSender = sender; + return *this; + } + + TransactionBuilder& sequenceNumber(std::uint64_t sequenceNumber) noexcept { + mSequenceNumber = sequenceNumber; + return *this; + } + + TransactionBuilder& payload(TransactionPayload payload) noexcept { + mPayload = std::move(payload); + return *this; + } + + TransactionBuilder& maxGasAmount(std::uint64_t maxGasAmount) noexcept { + mMaxGasAmount = maxGasAmount; + return *this; + } + + TransactionBuilder& gasUnitPrice(std::uint64_t gasUnitPrice) noexcept { + mGasUnitPrice = gasUnitPrice; + return *this; + } + + TransactionBuilder& expirationTimestampSecs(std::uint64_t expirationTimestampSecs) noexcept { + mExpirationTimestampSecs = expirationTimestampSecs; + return *this; + } + + TransactionBuilder& chainId(std::uint8_t chainId) noexcept { + mChainId = chainId; + return *this; + } + + TransactionBuilder& sign(const Proto::SigningInput& input, Proto::SigningOutput& output) noexcept { + BCS::Serializer serializer; + serializer << mSender << mSequenceNumber << mPayload << mMaxGasAmount << mGasUnitPrice << mExpirationTimestampSecs << mChainId; + auto privateKey = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); + output.set_raw_txn(serializer.bytes.data(), serializer.bytes.size()); + auto msgToSign = TW::Hash::sha3_256(gAptosSalt.data(), gAptosSalt.size()); + append(msgToSign, serializer.bytes); + auto signature = privateKey.sign(msgToSign, TWCurveED25519); + auto pubKeyData = privateKey.getPublicKey(TWPublicKeyTypeED25519).bytes; + output.mutable_authenticator()->set_public_key(pubKeyData.data(), pubKeyData.size()); + output.mutable_authenticator()->set_signature(signature.data(), signature.size()); + serializer << BCS::uleb128{.value = 0} << pubKeyData << signature; + output.set_encoded(serializer.bytes.data(), serializer.bytes.size()); + + // https://fullnode.devnet.aptoslabs.com/v1/spec#/operations/submit_transaction + // clang-format off + nlohmann::json json = { + {"sender", mSender.string()}, + {"sequence_number", std::to_string(mSequenceNumber)}, + {"max_gas_amount", std::to_string(mMaxGasAmount)}, + {"gas_unit_price", std::to_string(mGasUnitPrice)}, + {"expiration_timestamp_secs", std::to_string(mExpirationTimestampSecs)}, + {"payload", payloadToJson(mPayload)}, + {"signature", { + {"type", "ed25519_signature"}, + {"public_key", hexEncoded(pubKeyData)}, + {"signature", hexEncoded(signature)}} + } + }; + // clang-format on + output.set_json(json.dump()); + return *this; + } + +private: + Address mSender{}; + std::uint64_t mSequenceNumber{}; + TransactionPayload mPayload{}; + std::uint64_t mMaxGasAmount{}; + std::uint64_t mGasUnitPrice{}; + std::uint64_t mExpirationTimestampSecs{}; + std::uint8_t mChainId{}; +}; + +} // namespace TW::Aptos diff --git a/src/Aptos/TransactionPayload.cpp b/src/Aptos/TransactionPayload.cpp new file mode 100644 index 00000000000..a37a6f7c60d --- /dev/null +++ b/src/Aptos/TransactionPayload.cpp @@ -0,0 +1,57 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include + +namespace TW::Aptos { + +EntryFunction::EntryFunction(ModuleId module, Identifier function, std::vector tyArgs, std::vector args, nlohmann::json jsonArgs) noexcept + : mModule(std::move(module)), mFunction(std::move(function)), mTyArgs(std::move(tyArgs)), mArgs(std::move(args)), mJsonArgs(std::move(jsonArgs)) { +} + +BCS::Serializer& operator<<(BCS::Serializer& stream, const EntryFunction& entryFunction) noexcept { + stream << entryFunction.module() << entryFunction.function() << entryFunction.tyArgs() << entryFunction.args(); + return stream; +} + +nlohmann::json payloadToJson(const TransactionPayload& payload) { + auto visit_functor = [](const TransactionPayload& value) -> nlohmann::json { + if (auto* entryFunction = std::get_if(&value); entryFunction) { + return entryFunction->json(); + } else { + return {}; + } + }; + + return std::visit(visit_functor, payload); +} + +BCS::Serializer& operator<<(BCS::Serializer& stream, [[maybe_unused]] const Script& script) noexcept { + return stream; +} + +BCS::Serializer& operator<<(BCS::Serializer& stream, [[maybe_unused]] const ModuleBundle& moduleBundle) noexcept { + return stream; +} + +nlohmann::json EntryFunction::json() const noexcept { + nlohmann::json tyArgsJson = nlohmann::json::array(); + for (auto&& cur : mTyArgs) { + tyArgsJson.emplace_back(TypeTagToString(cur)); + } + // clang-format off + nlohmann::json out = { + {"type", "entry_function_payload"}, + {"function", mModule.shortString() + "::" + mFunction}, + {"type_arguments", tyArgsJson}, + {"arguments", mJsonArgs} + }; + // clang-format on + return out; +} + +} // namespace TW::Aptos diff --git a/src/Aptos/TransactionPayload.h b/src/Aptos/TransactionPayload.h new file mode 100644 index 00000000000..e52124f84ff --- /dev/null +++ b/src/Aptos/TransactionPayload.h @@ -0,0 +1,46 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include +#include + +namespace TW::Aptos { + +/// Call a Move entry function. +class EntryFunction { +public: + explicit EntryFunction(ModuleId module, Identifier function, std::vector tyArgs, std::vector args, nlohmann::json jsonArgs = {}) noexcept; + [[nodiscard]] const ModuleId& module() const noexcept { return mModule; } + [[nodiscard]] const Identifier& function() const noexcept { return mFunction; } + [[nodiscard]] const std::vector& tyArgs() const noexcept { return mTyArgs; } + [[nodiscard]] const std::vector& args() const noexcept { return mArgs; } + [[nodiscard]] nlohmann::json json() const noexcept; + +private: + ModuleId mModule; + Identifier mFunction; + std::vector mTyArgs; + std::vector mArgs; + nlohmann::json mJsonArgs; +}; + + +class Script { +}; + +class ModuleBundle { +}; + +BCS::Serializer& operator<<(BCS::Serializer& stream, const EntryFunction& entryFunction) noexcept; +BCS::Serializer& operator<<(BCS::Serializer& stream, const Script& script) noexcept; +BCS::Serializer& operator<<(BCS::Serializer& stream, const ModuleBundle& moduleBundle) noexcept; +using TransactionPayload = std::variant; +nlohmann::json payloadToJson(const TransactionPayload& payload); + +} // namespace TW::Aptos diff --git a/src/BCS.cpp b/src/BCS.cpp new file mode 100644 index 00000000000..1959ba83079 --- /dev/null +++ b/src/BCS.cpp @@ -0,0 +1,42 @@ +// Copyright © 2017-2022 Trust Wallet. +// Created by Clément Doumergue + +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "BCS.h" + +namespace TW::BCS { + +Serializer& operator<<(Serializer& stream, std::byte b) noexcept { + stream.add_byte(b); + return stream; +} + +Serializer& operator<<(Serializer& stream, uleb128 t) noexcept { + integral auto value = t.value; + + while (value >= 0x80) { + // Add the 7 lowest bits of data and set highest bit to 1 + stream << static_cast((value & 0x7f) | 0x80); + value >>= 7; + } + + // Add the remaining bits of data (highest bit is already 0 at this point) + stream << static_cast(value); + return stream; +} + +Serializer& operator<<(Serializer& stream, std::string_view sv) noexcept { + stream << uleb128{static_cast(sv.size())}; + stream.add_bytes(sv.begin(), sv.end()); + return stream; +} + +Serializer& operator<<(Serializer& stream, std::nullopt_t) noexcept { + stream << false; + return stream; +} + +} // namespace TW::BCS diff --git a/src/BCS.h b/src/BCS.h new file mode 100644 index 00000000000..5d795089649 --- /dev/null +++ b/src/BCS.h @@ -0,0 +1,222 @@ +// Copyright © 2017-2022 Trust Wallet. +// Created by Clément Doumergue + +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "Data.h" +#include "concepts/tw_concepts.h" + +namespace TW::BCS { + +/// Implementation of BCS encoding (as specified by the Diem project, see github.com/diem/bcs#detailed-specifications) + +struct Serializer { + Data bytes; + + void add_byte(std::byte b) noexcept { + bytes.emplace_back(static_cast(b)); + } + + template + void add_bytes(Iterator first, Iterator last) noexcept { + std::transform(first, last, std::back_inserter(bytes), [](auto&& c) { + return static_cast(c); + }); + } + + void clear() noexcept { + bytes.clear(); + } +}; + +struct uleb128 { + uint32_t value; +}; + +namespace details { + +template +concept aggregate_struct = std::is_class_v> && std::is_aggregate_v>; + +template +concept map_container = requires(T t) { + typename T::key_type; + typename T::mapped_type; + { std::declval().size() } -> std::same_as; + }; + +template + requires integral || + floating_point || + std::same_as || + std::same_as || + std::same_as || + aggregate_struct || + map_container +struct is_serializable { + static constexpr auto value = true; +}; + +template +struct is_serializable> { + static constexpr auto value = is_serializable::value; +}; + +template +struct is_serializable> { + static constexpr auto value = (is_serializable::value && ...); +}; + +template +struct is_serializable> { + static constexpr auto value = is_serializable::value && is_serializable::value; +}; + +template +struct is_serializable> { + static constexpr auto value = is_serializable::value; +}; + +template +struct is_serializable> { + static constexpr auto value = (is_serializable::value && ...); +}; + +template +Serializer& serialize_integral_impl(Serializer& stream, T t, std::index_sequence) noexcept { + const char* bytes = reinterpret_cast(&t); + // Add each byte in little-endian order + return (stream << ... << static_cast(bytes[Is])); +} + +template +Serializer& serialize_tuple_impl(Serializer& stream, const T& t, std::index_sequence) noexcept { + return (stream << ... << std::get(t)); +} + +template +struct dependent_false { + static constexpr auto value = false; +}; + +template +constexpr auto to_tuple(T&& t) { + if constexpr (std::is_empty_v) { + return std::make_tuple(); + } else if constexpr (requires { [&t] { auto&& [a0] = t; }; }) { + auto&& [a0] = std::forward(t); + return std::make_tuple(a0); + } else if constexpr (requires { [&t] { auto&& [a0, a1] = t; }; }) { + auto&& [a0, a1] = std::forward(t); + return std::make_tuple(a0, a1); + } else if constexpr (requires { [&t] { auto&& [a0, a1, a2] = t; }; }) { + auto&& [a0, a1, a2] = std::forward(t); + return std::make_tuple(a0, a1, a2); + } else if constexpr (requires { [&t] { auto&& [a0, a1, a2, a3] = t; }; }) { + auto&& [a0, a1, a2, a3] = std::forward(t); + return std::make_tuple(a0, a1, a2, a3); + } else if constexpr (requires { [&t] { auto&& [a0, a1, a2, a3, a4] = t; }; }) { + auto&& [a0, a1, a2, a3, a4] = std::forward(t); + return std::make_tuple(a0, a1, a2, a3, a4); + } else if constexpr (requires { [&t] { auto&& [a0, a1, a2, a3, a4, a5] = t; }; }) { + auto&& [a0, a1, a2, a3, a4, a5] = std::forward(t); + return std::make_tuple(a0, a1, a2, a3, a4, a5); + } else { + static_assert(dependent_false::value, "the structure has more than 6 members"); + } +} + +template +Serializer& serialize_struct_impl(Serializer& stream, const T& t) noexcept { + return stream << to_tuple(t); +} +} // namespace details + +template +concept PrimitiveSerializable = details::is_serializable::value; + +template +concept CustomSerializable = requires(T t) { + { std::declval() << t } -> std::same_as; + }; + +template +concept Serializable = PrimitiveSerializable || CustomSerializable; + +Serializer& operator<<(Serializer& stream, std::byte b) noexcept; + +template +Serializer& operator<<(Serializer& stream, T t) noexcept { + return details::serialize_integral_impl(stream, t, std::make_index_sequence{}); +} + +Serializer& operator<<(Serializer& stream, uleb128 t) noexcept; + +Serializer& operator<<(Serializer& stream, std::string_view sv) noexcept; + +template +Serializer& operator<<(Serializer& stream, const std::optional o) noexcept { + if (o.has_value()) { + stream << true; + stream << o.value(); + } else { + stream << false; + } + return stream; +} + +Serializer& operator<<(Serializer& stream, std::nullopt_t) noexcept; + +template +Serializer& operator<<(Serializer& stream, const std::tuple& t) noexcept { + return details::serialize_tuple_impl(stream, t, std::make_index_sequence{}); +} + +template +Serializer& operator<<(Serializer& stream, const std::pair& t) noexcept { + return details::serialize_tuple_impl(stream, t, std::make_index_sequence<2>{}); +} + +template +Serializer& operator<<(Serializer& stream, const T& t) noexcept { + return details::serialize_struct_impl(stream, t); +} + +template +Serializer& operator<<(Serializer& stream, const std::vector& t) noexcept { + stream << uleb128{static_cast(t.size())}; + for (auto&& cur: t) { + stream << cur; + } + return stream; +} + +template +Serializer& operator<<(Serializer& stream, const std::variant& t) noexcept { + stream << uleb128{static_cast(t.index())}; + std::visit([&stream](auto&& value) { stream << value; }, t); + return stream; +} + +template +Serializer& operator<<(Serializer& stream, const T& t) noexcept { + stream << uleb128{static_cast(t.size())}; + for (auto&& [k, v] : t) { + stream << std::make_tuple(k, v); + } + return stream; +} + +} // namespace TW::BCS diff --git a/src/Coin.cpp b/src/Coin.cpp index f22a8713fc1..b727c1488ed 100644 --- a/src/Coin.cpp +++ b/src/Coin.cpp @@ -16,6 +16,7 @@ #include "Aeternity/Entry.h" #include "Aion/Entry.h" #include "Algorand/Entry.h" +#include "Aptos/Entry.h" #include "Binance/Entry.h" #include "Bitcoin/Entry.h" #include "Cardano/Entry.h" @@ -63,6 +64,7 @@ using namespace std; Aeternity::Entry aeternityDP; Aion::Entry aionDP; Algorand::Entry algorandDP; +Aptos::Entry AptosDP; Binance::Entry binanceDP; Bitcoin::Entry bitcoinDP; Cardano::Entry cardanoDP; @@ -150,6 +152,7 @@ CoinEntry* coinDispatcher(TWCoinType coinType) { case TWBlockchainKusama: entry = &kusamaDP; break; case TWBlockchainNervos: entry = &NervosDP; break; case TWBlockchainEverscale: entry = &EverscaleDP; break; + case TWBlockchainAptos: entry = &AptosDP; break; // end_of_coin_dipatcher_switch_marker_do_not_modify default: entry = nullptr; break; diff --git a/src/concepts/tw_concepts.h b/src/concepts/tw_concepts.h new file mode 100644 index 00000000000..57e2455a078 --- /dev/null +++ b/src/concepts/tw_concepts.h @@ -0,0 +1,19 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include + +namespace TW { + +template +concept integral = std::is_integral_v; + +template +concept floating_point = std::is_floating_point_v; + +} // namespace TW diff --git a/src/proto/Aptos.proto b/src/proto/Aptos.proto new file mode 100644 index 00000000000..70d4f4eb598 --- /dev/null +++ b/src/proto/Aptos.proto @@ -0,0 +1,92 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +syntax = "proto3"; + +package TW.Aptos.Proto; +option java_package = "wallet.core.jni.proto"; + +// Necessary fields to process a TransferMessage +message TransferMessage { + // Destination Account address (string) + string to = 1; + // Amount to be transferred (uint64) + uint64 amount = 2; +} + +// Necessary tag for type function argument +message StructTag { + // Address of the account + string account_address = 1; + // Module name + string module = 2; + // Identifier + string name = 3; +} + +// Necessary fields to process a TokenTransferMessage +message TokenTransferMessage { + // Destination Account address (string) + string to = 1; + // Amount to be transferred (uint64) + uint64 amount = 2; + // token function to call, e.g BTC: 0x43417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b9::coins::BTC + StructTag function = 3; +} + +// Necessary fields to process a CreateAccountMessage +message CreateAccountMessage { + // auth account address to create + string auth_key = 1; +} + +// Input data necessary to create a signed transaction. +message SigningInput { + // Sender Account address (string) + string sender = 1; + // Sequence number, incremented atomically for each tx present on the account, start at 0 (int64) + int64 sequence_number = 2; + oneof transaction_payload { + TransferMessage transfer = 3; + TokenTransferMessage token_transfer = 4; + CreateAccountMessage create_account = 5; + } + // Max gas amount that the user is willing to pay (uint64) + uint64 max_gas_amount = 6; + // Gas unit price - queried through API (uint64) + uint64 gas_unit_price = 7; + // Expiration timestamp for the transaction, can't be in the past (uint64) + uint64 expiration_timestamp_secs = 8; + // Chain id 1 (mainnet) 32(devnet) (uint32 - casted in uint8_t later) + uint32 chain_id = 9; + // Private key to sign the transaction (bytes) + bytes private_key = 10; + // hex encoded function to sign, use it for smart contract approval (string) + string any_encoded = 11; +} + +// Information related to the signed transaction +message TransactionAuthenticator { + // Signature part of the signed transaction (bytes) + bytes signature = 1; + // Public key of the signer (bytes) + bytes public_key = 2; +} + +// Transaction signing output. +message SigningOutput { + /// The raw transaction (bytes) + bytes raw_txn = 1; + + /// Public key and signature to authenticate + TransactionAuthenticator authenticator = 2; + + /// Signed and encoded transaction bytes. + bytes encoded = 3; + + // Transaction json format for api broadcasting (string) + string json = 4; +} diff --git a/swift/Tests/Blockchains/AptosTests.swift b/swift/Tests/Blockchains/AptosTests.swift new file mode 100644 index 00000000000..d617c67db98 --- /dev/null +++ b/swift/Tests/Blockchains/AptosTests.swift @@ -0,0 +1,48 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import WalletCore +import XCTest + +class AptosTests: XCTestCase { + func testAddress() { + let anyAddress = AnyAddress(string: "0x6af7d07b8a541913dfa87a9f99628faa255c70241ef9ebd9b82a7e715ee13108", coin: .aptos) + + XCTAssertEqual(anyAddress?.description, "0x6af7d07b8a541913dfa87a9f99628faa255c70241ef9ebd9b82a7e715ee13108") + XCTAssertEqual(anyAddress?.coin, .aptos) + + let invalid = "MQqpqMQgCBuiPkoXfgZZsJvuzCeI1zc00z6vHJj4" + XCTAssertNil(Data(hexString: invalid)) + XCTAssertNil(AnyAddress(string: invalid, coin: .aptos)) + XCTAssertFalse(AnyAddress.isValid(string: invalid, coin: .aptos)) + } + + func testSign() { + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xbb3b3c33781c27e486afa2db854fb0a5c846d0967672feb2c6c3297a2b14e1ce?network=Devnet + let privateKeyData = Data(hexString: "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")! + let transferMsg = AptosTransferMessage.with { + $0.to = "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30" + $0.amount = 1000 + } + let input = AptosSigningInput.with { + $0.chainID = 32 + $0.sender = "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30" + $0.expirationTimestampSecs = 3664390082 + $0.gasUnitPrice = 100 + $0.maxGasAmount = 3296766 + $0.sequenceNumber = 15 + $0.transfer = transferMsg + $0.privateKey = privateKeyData + } + let output: AptosSigningOutput = AnySigner.sign(input: input, coin: .aptos) + let expectedRawTx = "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000020" + let expectedSignature = "2ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05" + let expectedSignedTx = "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000200020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c402ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05" + XCTAssertEqual(output.rawTxn.hexString, expectedRawTx) + XCTAssertEqual(output.authenticator.signature.hexString, expectedSignature) + XCTAssertEqual(output.encoded.hexString, expectedSignedTx) + } +} diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 8fdf3190737..789a9a6627d 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -252,6 +252,9 @@ class CoinAddressDerivationTests: XCTestCase { case .everscale: let expectedResult = "0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04"; assertCoinDerivation(coin, expectedResult, derivedAddress, address) + case .aptos: + let expectedResult = "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"; + assertCoinDerivation(coin, expectedResult, derivedAddress, address) @unknown default: fatalError() } diff --git a/tests/Aptos/AddressTests.cpp b/tests/Aptos/AddressTests.cpp new file mode 100644 index 00000000000..92f156d077e --- /dev/null +++ b/tests/Aptos/AddressTests.cpp @@ -0,0 +1,54 @@ +// Copyright © 2017-2022 Trust Wallet. +// Author: Clement Doumergue +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "Aptos/Address.h" +#include "PublicKey.h" +#include "PrivateKey.h" +#include +#include + +namespace TW::Aptos::tests { + +TEST(AptosAddress, Valid) { + ASSERT_TRUE(Address::isValid("0x1")); + ASSERT_TRUE(Address::isValid(gAddressOne.string())); + ASSERT_TRUE(Address::isValid(gAddressZero.string())); + ASSERT_TRUE(Address::isValid("0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b")); + ASSERT_TRUE(Address::isValid("eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b")); + ASSERT_TRUE(Address::isValid("19aadeca9388e009d136245b9a67423f3eee242b03142849eb4f81a4a409e59c")); +} + +TEST(AptosAddress, Invalid) { + ASSERT_FALSE(Address::isValid("Seff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b")); // Invalid hex character + ASSERT_FALSE(Address::isValid("eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175bb")); // Invalid length: too long + ASSERT_FALSE(Address::isValid("eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175")); // Invalid length: too short +} + +TEST(AptosAddress, FromPrivateKey) { + auto privateKey = PrivateKey(parse_hex("088baa019f081d6eab8dff5c447f9ce2f83c1babf3d03686299eaf6a1e89156e")); + auto address = Address(privateKey.getPublicKey(TWPublicKeyTypeED25519)); + ASSERT_EQ(address.string(), "0xe9c4d0b6fe32a5cc8ebd1e9ad5b54a0276a57f2d081dcb5e30342319963626c3"); +} + +TEST(AptosAddress, FromPublicKey) { + auto publicKey = PublicKey(parse_hex("ad0e293a56c9fc648d1872a00521d97e6b65724519a2676c2c47cb95d131cf5a"), TWPublicKeyTypeED25519); + auto address = Address(publicKey); + ASSERT_EQ(address.string(), "0xe9c4d0b6fe32a5cc8ebd1e9ad5b54a0276a57f2d081dcb5e30342319963626c3"); +} + +TEST(AptosAddress, FromString) { + auto address = Address("eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b"); + ASSERT_EQ(address.string(), "0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b"); +} + +TEST(AptosAddress, ShortString) { + ASSERT_EQ(gAddressOne.string(), "0x0000000000000000000000000000000000000000000000000000000000000001"); + ASSERT_EQ(gAddressOne.shortString(), "1"); +} + +} // namespace TW::Aptos::tests diff --git a/tests/Aptos/MoveTypesTests.cpp b/tests/Aptos/MoveTypesTests.cpp new file mode 100644 index 00000000000..c2cffeafa9a --- /dev/null +++ b/tests/Aptos/MoveTypesTests.cpp @@ -0,0 +1,59 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include +#include + +namespace TW::Aptos::tests { + +TEST(AptosMoveTypes, ModuleId) { + ModuleId module(gAddressOne, "coin"); + ASSERT_EQ(module.address(), gAddressOne); + ASSERT_EQ(module.name(), "coin"); + ASSERT_EQ(hex(module.accessVector()), "00000000000000000000000000000000000000000000000000000000000000000104636f696e"); + ASSERT_EQ(module.string(), "0x0000000000000000000000000000000000000000000000000000000000000001::coin"); + ASSERT_EQ(module.shortString(), "0x1::coin"); +} + +TEST(AptosMoveTypes, StructTag) { + auto functorTest = [](T value, const std::string expectedHex) { + TypeTag t{.tags = value}; + StructTag st(gAddressOne, "abc", "abc", std::vector{{t}}); + ASSERT_EQ(st.moduleID().name(), "abc"); + ASSERT_EQ(st.moduleID().address(), gAddressOne); + ASSERT_EQ(hex(st.serialize()), expectedHex); + }; + functorTest(Bool{}, "01000000000000000000000000000000000000000000000000000000000000000103616263036162630100"); + functorTest(U8{}, "01000000000000000000000000000000000000000000000000000000000000000103616263036162630101"); + functorTest(U64{}, "01000000000000000000000000000000000000000000000000000000000000000103616263036162630102"); + functorTest(U128{}, "01000000000000000000000000000000000000000000000000000000000000000103616263036162630103"); + functorTest(TAddress{}, "01000000000000000000000000000000000000000000000000000000000000000103616263036162630104"); + functorTest(TSigner{}, "01000000000000000000000000000000000000000000000000000000000000000103616263036162630105"); + functorTest(Vector{.tags = std::vector{{TypeTag{.tags = U8{}}}}}, "0100000000000000000000000000000000000000000000000000000000000000010361626303616263010601"); + StructTag stInner(gAddressOne, "foo", "bar", std::vector{{U8{}}}); + functorTest(TStructTag{stInner}, "01000000000000000000000000000000000000000000000000000000000000000103616263036162630107000000000000000000000000000000000000000000000000000000000000000103666f6f036261720101"); +} + +TEST(AptosMoveTypes, TypeTagDisplay) { + auto functorTest = [](const TypeTag &value, const std::string& expected) { + ASSERT_EQ(TypeTagToString(value), expected); + }; + functorTest(TypeTag{.tags = Bool{}}, "bool"); + functorTest(TypeTag{.tags = U8{}}, "u8"); + functorTest(TypeTag{.tags = U64{}}, "u64"); + functorTest(TypeTag{.tags = U128{}}, "u128"); + functorTest(TypeTag{.tags = TAddress{}}, "address"); + functorTest(TypeTag{.tags = TSigner{}}, "signer"); + TypeTag t{.tags = TypeTag::TypeTagVariant(Vector{.tags = {{U8{}}}})}; + functorTest(t, "vector"); + StructTag st(gAddressOne, "foo", "bar", std::vector{{U8{}}}); + TypeTag anotherT{.tags = TypeTag::TypeTagVariant(st)}; + functorTest(anotherT, "0x1::foo::bar"); + functorTest(gTransferTag, "0x1::aptos_coin::AptosCoin"); +} + +} // namespace TW::Aptos::tests diff --git a/tests/Aptos/SignerTests.cpp b/tests/Aptos/SignerTests.cpp new file mode 100644 index 00000000000..ece577f4e0b --- /dev/null +++ b/tests/Aptos/SignerTests.cpp @@ -0,0 +1,231 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Aptos/Address.h" +#include "Aptos/Signer.h" +#include "HexCoding.h" +#include "PrivateKey.h" +#include "PublicKey.h" +#include + +#include + +namespace TW::Aptos::tests { + +TEST(AptosSigner, DummyTxSign) { + Proto::SigningInput input; + input.set_sender("0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b"); + input.set_sequence_number(1); + auto& tf = *input.mutable_transfer(); + tf.set_to("0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b"); + tf.set_amount(1000); + input.set_max_gas_amount(1); + input.set_gas_unit_price(1); + input.set_expiration_timestamp_secs(1); + input.set_chain_id(1); + auto privateKey = PrivateKey(parse_hex("7f2634c0e2414a621e96e39c41d09021700cee12ee43328ed094c5580cd0bd6f")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.raw_txn()), "eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b010000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e000220eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b08e80300000000000001000000000000000100000000000000010000000000000001"); + ASSERT_EQ(hex(result.authenticator().signature()), "9d3bd902bd358364c43fa65ece335dd4411527e72e1c6deb9148744eaa24e39b6bd74ff6b0195114243bdd2ee3a98511ff05883d9e79161b2b8f5029d883c309"); + ASSERT_EQ(hex(result.encoded()), "eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b010000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e000220eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b08e803000000000000010000000000000001000000000000000100000000000000010020633e5c7e355bdd484706436ce1f06fdf280bd7c2229a7f9b6489684412c6967c409d3bd902bd358364c43fa65ece335dd4411527e72e1c6deb9148744eaa24e39b6bd74ff6b0195114243bdd2ee3a98511ff05883d9e79161b2b8f5029d883c309"); + nlohmann::json expectedJson = R"( + { + "sender": "0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b", + "sequence_number": "1", + "max_gas_amount": "1", + "gas_unit_price": "1", + "expiration_timestamp_secs": "1", + "payload": { + "type":"entry_function_payload", + "function": "0x1::coin::transfer", + "type_arguments":["0x1::aptos_coin::AptosCoin"], + "arguments": ["0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b", "1000"] + }, + "signature": { + "type": "ed25519_signature", + "public_key": "0x633e5c7e355bdd484706436ce1f06fdf280bd7c2229a7f9b6489684412c6967c", + "signature": "0x9d3bd902bd358364c43fa65ece335dd4411527e72e1c6deb9148744eaa24e39b6bd74ff6b0195114243bdd2ee3a98511ff05883d9e79161b2b8f5029d883c309" + } + } + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(result.json()); + ASSERT_EQ(expectedJson, parsedJson); +} + +TEST(AptosSigner, TxSign) { + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xbb3b3c33781c27e486afa2db854fb0a5c846d0967672feb2c6c3297a2b14e1ce?network=Devnet + Proto::SigningInput input; + input.set_sender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); + input.set_sequence_number(15); + auto& tf = *input.mutable_transfer(); + tf.set_to("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); + tf.set_amount(1000); + input.set_max_gas_amount(3296766); + input.set_gas_unit_price(100); + input.set_expiration_timestamp_secs(3664390082); + input.set_chain_id(32); + auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.raw_txn()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000020"); + ASSERT_EQ(hex(result.authenticator().signature()), "2ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05"); + ASSERT_EQ(hex(result.encoded()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000200020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c402ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05"); + nlohmann::json expectedJson = R"( + { + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": ["0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30","1000"], + "function": "0x1::coin::transfer", + "type": "entry_function_payload", + "type_arguments": ["0x1::aptos_coin::AptosCoin"] + }, + "sender": "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "15", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0x2ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05", + "type": "ed25519_signature" + } + } + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(result.json()); + ASSERT_EQ(expectedJson, parsedJson); +} + +TEST(AptosSigner, CreateAccount) { + // Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x477141736de6b0936a6c3734e4d6fd018c7d21f1f28f99028ef0bc6881168602?network=Devnet + Proto::SigningInput input; + input.set_sender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); + input.set_sequence_number(0); + auto& tf = *input.mutable_create_account(); + tf.set_auth_key("0x3aa1672641a4e17b3d913b4c0301e805755a80b12756fc729c5878f12344d30e"); + input.set_max_gas_amount(3296766); + input.set_gas_unit_price(100); + input.set_expiration_timestamp_secs(3664390082); + input.set_chain_id(33); + auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.raw_txn()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3000000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e740e6372656174655f6163636f756e740001203aa1672641a4e17b3d913b4c0301e805755a80b12756fc729c5878f12344d30efe4d3200000000006400000000000000c2276ada0000000021"); + ASSERT_EQ(hex(result.authenticator().signature()), "fcba3dfbec76721454ef414955f09f159660a13886b4edd8c579e3c779c29073afe7b25efa3fef9b21c2efb1cf16b4247fc0e5c8f63fdcd1c8d87f5d59f44501"); + ASSERT_EQ(hex(result.encoded()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3000000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e740e6372656174655f6163636f756e740001203aa1672641a4e17b3d913b4c0301e805755a80b12756fc729c5878f12344d30efe4d3200000000006400000000000000c2276ada00000000210020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c40fcba3dfbec76721454ef414955f09f159660a13886b4edd8c579e3c779c29073afe7b25efa3fef9b21c2efb1cf16b4247fc0e5c8f63fdcd1c8d87f5d59f44501"); + nlohmann::json expectedJson = R"( + { + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": ["0x3aa1672641a4e17b3d913b4c0301e805755a80b12756fc729c5878f12344d30e"], + "function": "0x1::aptos_account::create_account", + "type": "entry_function_payload", + "type_arguments": [] + }, + "sender": "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "0", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0xfcba3dfbec76721454ef414955f09f159660a13886b4edd8c579e3c779c29073afe7b25efa3fef9b21c2efb1cf16b4247fc0e5c8f63fdcd1c8d87f5d59f44501", + "type": "ed25519_signature" + } + } + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(result.json()); + ASSERT_EQ(expectedJson, parsedJson); +} + +TEST(AptosSigner, BlindSign) { + // successfully broadcasted https://explorer.aptoslabs.com/txn/0xd95857a9e644528708778a3a0a6e13986751944fca30eaac98853c1655de0422?network=Devnet + // encoded submission with: + // curl --location --request POST 'https://fullnode.devnet.aptoslabs.com/v1/transactions/encode_submission' \ + //--header 'Content-Type: application/json' \ + //--header 'Cookie: AWSALB=0zI2zWypvEr0I3sGM6vnyHSxYO1D0aaMXfyA/2VwhA291aJJ80Yz67Fur50sXPFBI8dKKID4p8DShj1KkEXPY/NGAylpOj1EG2M2Qjuu1B38Q5C+dZW2CHT+IAZ5; AWSALBCORS=0zI2zWypvEr0I3sGM6vnyHSxYO1D0aaMXfyA/2VwhA291aJJ80Yz67Fur50sXPFBI8dKKID4p8DShj1KkEXPY/NGAylpOj1EG2M2Qjuu1B38Q5C+dZW2CHT+IAZ5' \ + //--data-raw '{ + // "expiration_timestamp_secs": "3664390082", + // "gas_unit_price": "100", + // "max_gas_amount": "3296766", + // "payload": { + // "function": "0x4633134869a61c41ad42eaca028d71c5b8b4109ffd69e1aa99c35a621b298837::pool::swap_y_to_x", + // "type_arguments": [ + // "0xdeae46f81671e76f444e2ce5a299d9e1ea06a8fa26e81dfd49aa7fa5a5a60e01::devnet_coins::DevnetUSDT", + // "0x1::aptos_coin::AptosCoin" + // ], + // "arguments": [ + // "100000000", + // "0" + // ], + // "type": "entry_function_payload" + // }, + // "sender": "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + // "sequence_number": "2" + //}' + Proto::SigningInput input; + input.set_any_encoded("0xb5e97db07fa0bd0e5598aa3643a9bc6f6693bddc1a9fec9e674a461eaa00b19307968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300200000000000000024633134869a61c41ad42eaca028d71c5b8b4109ffd69e1aa99c35a621b29883704706f6f6c0b737761705f795f746f5f780207deae46f81671e76f444e2ce5a299d9e1ea06a8fa26e81dfd49aa7fa5a5a60e010c6465766e65745f636f696e730a4465766e657455534454000700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00020800e1f50500000000080000000000000000fe4d3200000000006400000000000000c2276ada0000000021"); + auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.raw_txn()), "b5e97db07fa0bd0e5598aa3643a9bc6f6693bddc1a9fec9e674a461eaa00b19307968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300200000000000000024633134869a61c41ad42eaca028d71c5b8b4109ffd69e1aa99c35a621b29883704706f6f6c0b737761705f795f746f5f780207deae46f81671e76f444e2ce5a299d9e1ea06a8fa26e81dfd49aa7fa5a5a60e010c6465766e65745f636f696e730a4465766e657455534454000700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00020800e1f50500000000080000000000000000fe4d3200000000006400000000000000c2276ada0000000021"); + ASSERT_EQ(hex(result.authenticator().signature()), "9e81026fdd43986f4d5588afdab875cd18b64dc15b3489fcc00ed46fc361915b27e23e0cefe6d23698ee76a562915fe85e99185dbc1dd29ba720f7fad144af0b"); + ASSERT_EQ(hex(result.encoded()), "b5e97db07fa0bd0e5598aa3643a9bc6f6693bddc1a9fec9e674a461eaa00b19307968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300200000000000000024633134869a61c41ad42eaca028d71c5b8b4109ffd69e1aa99c35a621b29883704706f6f6c0b737761705f795f746f5f780207deae46f81671e76f444e2ce5a299d9e1ea06a8fa26e81dfd49aa7fa5a5a60e010c6465766e65745f636f696e730a4465766e657455534454000700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00020800e1f50500000000080000000000000000fe4d3200000000006400000000000000c2276ada00000000210020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c409e81026fdd43986f4d5588afdab875cd18b64dc15b3489fcc00ed46fc361915b27e23e0cefe6d23698ee76a562915fe85e99185dbc1dd29ba720f7fad144af0b"); + nlohmann::json expectedJson = R"( + { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0x9e81026fdd43986f4d5588afdab875cd18b64dc15b3489fcc00ed46fc361915b27e23e0cefe6d23698ee76a562915fe85e99185dbc1dd29ba720f7fad144af0b", + "type": "ed25519_signature" + } + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(result.json()); + ASSERT_EQ(expectedJson, parsedJson); +} + +TEST(AptosSigner, TokenTxSign) { + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xb5b383a5c7f99b2edb3bed9533f8169a89051b149d65876a82f4c0b9bf78a15b?network=Devnet + Proto::SigningInput input; + input.set_sender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); + input.set_sequence_number(24); + auto& tf = *input.mutable_token_transfer(); + tf.set_to("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); + tf.set_amount(100000); + tf.mutable_function()->set_account_address("0x43417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b9"); + tf.mutable_function()->set_module("coins"); + tf.mutable_function()->set_name("BTC"); + input.set_max_gas_amount(3296766); + input.set_gas_unit_price(100); + input.set_expiration_timestamp_secs(3664390082); + input.set_chain_id(32); + auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.raw_txn()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30180000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010743417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b905636f696e730342544300022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008a086010000000000fe4d3200000000006400000000000000c2276ada0000000020"); + ASSERT_EQ(hex(result.authenticator().signature()), "7643ec8aae6198bd13ca6ea2962265859cba5a228e7d181131f6c022700dd02a7a04dc0345ad99a0289e5ab80b130b3864e6404079980bc226f1a13aee7d280a"); + ASSERT_EQ(hex(result.encoded()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30180000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010743417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b905636f696e730342544300022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008a086010000000000fe4d3200000000006400000000000000c2276ada00000000200020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c407643ec8aae6198bd13ca6ea2962265859cba5a228e7d181131f6c022700dd02a7a04dc0345ad99a0289e5ab80b130b3864e6404079980bc226f1a13aee7d280a"); + nlohmann::json expectedJson = R"( + { + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": ["0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30","100000"], + "function": "0x1::coin::transfer", + "type": "entry_function_payload", + "type_arguments": ["0x43417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b9::coins::BTC"] + }, + "sender": "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "24", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0x7643ec8aae6198bd13ca6ea2962265859cba5a228e7d181131f6c022700dd02a7a04dc0345ad99a0289e5ab80b130b3864e6404079980bc226f1a13aee7d280a", + "type": "ed25519_signature" + } + } + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(result.json()); + ASSERT_EQ(expectedJson, parsedJson); +} + +} // namespace TW::Aptos::tests diff --git a/tests/Aptos/TWAnySignerTests.cpp b/tests/Aptos/TWAnySignerTests.cpp new file mode 100644 index 00000000000..1caf524cc5c --- /dev/null +++ b/tests/Aptos/TWAnySignerTests.cpp @@ -0,0 +1,63 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Aptos/Address.h" +#include "Aptos/Signer.h" +#include "HexCoding.h" +#include "PrivateKey.h" +#include "PublicKey.h" +#include +#include +#include "../interface/TWTestUtilities.h" + +#include + +namespace TW::Aptos::tests { + +TEST(TWAnySignerAptos, TxSign) { + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xbb3b3c33781c27e486afa2db854fb0a5c846d0967672feb2c6c3297a2b14e1ce?network=Devnet + Proto::SigningInput input; + input.set_sender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); + input.set_sequence_number(15); + auto& tf = *input.mutable_transfer(); + tf.set_to("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); + tf.set_amount(1000); + input.set_max_gas_amount(3296766); + input.set_gas_unit_price(100); + input.set_expiration_timestamp_secs(3664390082); + input.set_chain_id(32); + auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeAptos); + ASSERT_EQ(hex(output.raw_txn()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000020"); + ASSERT_EQ(hex(output.authenticator().signature()), "2ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05"); + ASSERT_EQ(hex(output.encoded()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000200020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c402ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05"); + nlohmann::json expectedJson = R"( + { + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": ["0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30","1000"], + "function": "0x1::coin::transfer", + "type": "entry_function_payload", + "type_arguments": ["0x1::aptos_coin::AptosCoin"] + }, + "sender": "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "15", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0x2ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05", + "type": "ed25519_signature" + } + } + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(output.json()); + ASSERT_EQ(expectedJson, parsedJson); +} + +} // namespace TW::Aptos::tests diff --git a/tests/Aptos/TWAptosAddressTests.cpp b/tests/Aptos/TWAptosAddressTests.cpp new file mode 100644 index 00000000000..cc827933612 --- /dev/null +++ b/tests/Aptos/TWAptosAddressTests.cpp @@ -0,0 +1,34 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "../interface/TWTestUtilities.h" +#include +#include + +#include + +using namespace TW; + +namespace TW::Aptos::tests { + +TEST(TWAptosAddress, HDWallet) { + auto mnemonic = + "shoot island position soft burden budget tooth cruel issue economy destroy above"; + auto passphrase = ""; + + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(STRING(mnemonic).get(), STRING(passphrase).get())); + + auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKey(wallet.get(), TWCoinTypeAptos, WRAPS(TWCoinTypeDerivationPath(TWCoinTypeAptos)).get())); + + auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyEd25519(privateKey.get())); + auto address = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKey(publicKey.get(), TWCoinTypeAptos)); + auto addressStr = WRAPS(TWAnyAddressDescription(address.get())); + + assertStringsEqual(addressStr, "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); +} + +} // namespace TW::Aptos::tests diff --git a/tests/Aptos/TWCoinTypeTests.cpp b/tests/Aptos/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..e9f26f59987 --- /dev/null +++ b/tests/Aptos/TWCoinTypeTests.cpp @@ -0,0 +1,35 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "../interface/TWTestUtilities.h" +#include +#include + + +TEST(TWAptosCoinType, TWCoinType) { + const auto coin = TWCoinTypeAptos; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("91424546")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0x6af7d07b8a541913dfa87a9f99628faa255c70241ef9ebd9b82a7e715ee13108")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "aptos"); + assertStringsEqual(name, "Aptos"); + assertStringsEqual(symbol, "APT"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 8); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainAptos); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); + assertStringsEqual(txUrl, "https://explorer.aptoslabs.com/txn/91424546"); + assertStringsEqual(accUrl, "https://explorer.aptoslabs.com/account/0x6af7d07b8a541913dfa87a9f99628faa255c70241ef9ebd9b82a7e715ee13108"); +} diff --git a/tests/Aptos/TransactionPayloadTests.cpp b/tests/Aptos/TransactionPayloadTests.cpp new file mode 100644 index 00000000000..29fd5e3712a --- /dev/null +++ b/tests/Aptos/TransactionPayloadTests.cpp @@ -0,0 +1,32 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include +#include + +namespace TW::Aptos::tests { + +TEST(AptosTransactionPayload, PayLoadBasis) { + ModuleId module(gAddressOne, "coin"); + std::uint64_t amount{1000}; + Address to("0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b"); + BCS::Serializer serializer; + serializer << to; + std::vector args; + args.emplace_back(serializer.bytes); + serializer.clear(); + serializer << amount; + args.emplace_back(serializer.bytes); + TransactionPayload payload = EntryFunction(module, "transfer", {gTransferTag}, args); + ASSERT_EQ(std::get(payload).module().name(), "coin"); + ASSERT_EQ(std::get(payload).module().shortString(), "0x1::coin"); + serializer.clear(); + serializer << payload; + ASSERT_EQ(hex(serializer.bytes), "02000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e000220eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b08e803000000000000"); +} + +} // namespace TW::Aptos::tests diff --git a/tests/BCSTests.cpp b/tests/BCSTests.cpp new file mode 100644 index 00000000000..1182d6e2d87 --- /dev/null +++ b/tests/BCSTests.cpp @@ -0,0 +1,165 @@ +// Copyright © 2017-2022 Trust Wallet. +// Created by Clément Doumergue +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "BCS.h" +#include "HexCoding.h" + +#include + +namespace TW::BCS::tests { + +TEST(BCS, Integral) { + Serializer os; + os << uint32_t(0xAABBCCDD); + ASSERT_EQ(os.bytes, parse_hex("0xDDCCBBAA")); + + os.clear(); + os << int32_t(-305419896); + ASSERT_EQ(os.bytes, parse_hex("0x88A9CBED")); +} + +TEST(BCS, ULEB128) { + Serializer os; + os << uleb128{0x00000001}; + ASSERT_EQ(os.bytes, parse_hex("0x01")); + + os.clear(); + os << uleb128{0x00000080}; + ASSERT_EQ(os.bytes, parse_hex("0x8001")); + + os.clear(); + os << uleb128{0x00004000}; + ASSERT_EQ(os.bytes, parse_hex("0x808001")); + + os.clear(); + os << uleb128{0x00200000}; + ASSERT_EQ(os.bytes, parse_hex("0x80808001")); + + os.clear(); + os << uleb128{0x10000000}; + ASSERT_EQ(os.bytes, parse_hex("0x8080808001")); + + os.clear(); + os << uleb128{0x0000250F}; + ASSERT_EQ(os.bytes, parse_hex("0x8F4A")); +} + +TEST(BCS, String) { + Serializer os; + os << std::string_view("abcd"); + ASSERT_EQ(os.bytes, parse_hex("0x0461626364")); + + os.clear(); + os << std::string_view(""); + ASSERT_EQ(os.bytes, parse_hex("0x00")); +} + +TEST(BCS, Optional) { + Serializer os; + os << std::optional{0xBBCCDD}; + ASSERT_EQ(os.bytes, parse_hex("0x01DDCCBB00")); + + os.clear(); + os << std::optional{}; + ASSERT_EQ(os.bytes, parse_hex("0x00")); + + os.clear(); + os << std::nullopt; + ASSERT_EQ(os.bytes, parse_hex("0x00")); +} + +TEST(BCS, Tuple) { + Serializer os; + os << std::tuple{uint16_t(1), 'a'}; + ASSERT_EQ(os.bytes, parse_hex("0x010061")); + + os.clear(); + os << std::tuple{std::optional{123}, std::string_view("abcd"), uint8_t(0x0E)}; + ASSERT_EQ(os.bytes, parse_hex("0x017b00000004616263640e")); + + os.clear(); + os << std::tuple{}; + ASSERT_EQ(os.bytes, (Data{})); +} + +TEST(BCS, Pair) { + Serializer os; + os << std::pair{uint16_t(1), 'a'}; + ASSERT_EQ(os.bytes, parse_hex("0x010061")); + + os.clear(); + os << std::pair{std::optional{123}, std::string_view("abcd")}; + ASSERT_EQ(os.bytes, parse_hex("0x017b0000000461626364")); +} + +struct my_struct { + std::optional first; + std::string_view second; + uint8_t third; +}; + +TEST(BCS, Struct) { + Serializer os; + os << my_struct{{123}, "abcd", 0x0E}; + ASSERT_EQ(os.bytes, parse_hex("0x017b00000004616263640e")); +} + +TEST(BCS, Variant) { + using V = std::variant; + + Serializer os; + os << V{uint32_t(1)}; + ASSERT_EQ(os.bytes, parse_hex("0x0001000000")); + + os.clear(); + os << V{char('a')}; + ASSERT_EQ(os.bytes, parse_hex("0x0161")); + + os.clear(); + os << V{true}; + ASSERT_EQ(os.bytes, parse_hex("0x0201")); +} + +TEST(BCS, Map) { + Serializer os; + os << std::map{{'a', 0}, {'b', 1}, {'c', 2}}; + ASSERT_EQ(os.bytes, parse_hex("0x03610062016302")); +} + +class my_number { +private: + int value; + +public: + explicit my_number(int value) noexcept + : value(value) { + } + + [[nodiscard]] auto get_value() const { + return value; + } +}; + +Serializer& operator<<(Serializer& stream, my_number n) noexcept { + return stream << n.get_value(); +} + +static_assert(CustomSerializable, "my_number does not model the CustomSerializable concept"); + +TEST(BCS, Custom) { + Serializer os; + os << my_number{0xBBCCDD}; + ASSERT_EQ(os.bytes, parse_hex("0xDDCCBB00")); +} + +TEST(BCS, Vector) { + Serializer os; + os << std::vector{1}; + ASSERT_EQ(os.bytes, parse_hex("0101")); +} + +} diff --git a/tests/Cardano/TWCardanoAddressTests.cpp b/tests/Cardano/TWCardanoAddressTests.cpp index 4ce62f4e01a..e77f3e81520 100644 --- a/tests/Cardano/TWCardanoAddressTests.cpp +++ b/tests/Cardano/TWCardanoAddressTests.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "../interface/TWTestUtilities.h" #include "PrivateKey.h" diff --git a/tests/CoinAddressDerivationTests.cpp b/tests/CoinAddressDerivationTests.cpp index ed8d695148e..6d04e729eba 100644 --- a/tests/CoinAddressDerivationTests.cpp +++ b/tests/CoinAddressDerivationTests.cpp @@ -248,6 +248,9 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeNervos: EXPECT_EQ(address, "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqtsqfsf77ae0wn5a7795hs2ydv83g6hl4qleywxw"); break; + case TWCoinTypeAptos: + EXPECT_EQ(address, "0xce2fd04ac9efa74f17595e5785e847a2399d7e637f5e8179244f76191f653276"); + break; // no default branch here, intentionally, to better notice any missing coins } } diff --git a/tests/HDWallet/HDWalletTests.cpp b/tests/HDWallet/HDWalletTests.cpp index fdf70a687d2..893eefb3a5f 100644 --- a/tests/HDWallet/HDWalletTests.cpp +++ b/tests/HDWallet/HDWalletTests.cpp @@ -423,4 +423,15 @@ TEST(HDWallet, getKey) { } } +TEST(HDWallet, AptosKey) { + const auto derivPath = "m/44'/637'/0'/0'/0'"; + HDWallet wallet = HDWallet(mnemonic1, ""); + { + const auto privateKey = wallet.getKey(TWCoinTypeAptos, DerivationPath(derivPath)); + EXPECT_EQ(hex(privateKey.bytes), "7f2634c0e2414a621e96e39c41d09021700cee12ee43328ed094c5580cd0bd6f"); + EXPECT_EQ(hex(privateKey.getPublicKey(TWPublicKeyTypeED25519).bytes), "633e5c7e355bdd484706436ce1f06fdf280bd7c2229a7f9b6489684412c6967c"); + } +} + + } // namespace From 2bc44dabad0e2c2e7c582e0ac48d55866e650897 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Mon, 3 Oct 2022 13:35:15 +0200 Subject: [PATCH 099/497] [Comments] Add comments to Proto files (#2585) --- src/XRP/XAddress.h | 2 +- src/proto/Aeternity.proto | 7 +- src/proto/Aion.proto | 12 +- src/proto/Algorand.proto | 25 ++- src/proto/Binance.proto | 298 +++++++++++++++++++++++++-------- src/proto/Bitcoin.proto | 38 +++-- src/proto/Cardano.proto | 40 ++++- src/proto/Common.proto | 72 +++++--- src/proto/Cosmos.proto | 30 +++- src/proto/Decred.proto | 18 +- src/proto/EOS.proto | 13 +- src/proto/Elrond.proto | 41 ++++- src/proto/Ethereum.proto | 51 +++--- src/proto/Everscale.proto | 14 +- src/proto/FIO.proto | 23 ++- src/proto/Filecoin.proto | 11 +- src/proto/Harmony.proto | 66 ++++++-- src/proto/Icon.proto | 6 +- src/proto/IoTeX.proto | 267 +++++++++++++++++++---------- src/proto/NEAR.proto | 55 +++++- src/proto/NEO.proto | 37 +++- src/proto/NULS.proto | 73 +++++++- src/proto/Nano.proto | 9 +- src/proto/Nebulas.proto | 47 ++++-- src/proto/Nervos.proto | 10 +- src/proto/Nimiq.proto | 8 +- src/proto/Oasis.proto | 13 +- src/proto/Ontology.proto | 11 +- src/proto/Polkadot.proto | 53 +++++- src/proto/Ripple.proto | 12 +- src/proto/Solana.proto | 77 +++++++-- src/proto/Stellar.proto | 36 +++- src/proto/THORChainSwap.proto | 17 +- src/proto/Tezos.proto | 21 ++- src/proto/Theta.proto | 10 +- src/proto/Tron.proto | 57 ++++++- src/proto/VeChain.proto | 7 +- src/proto/Waves.proto | 31 +++- src/proto/Zilliqa.proto | 12 +- tests/FIO/TWFIOTests.cpp | 2 +- tools/doxygen_convert_comments | 2 +- 41 files changed, 1263 insertions(+), 371 deletions(-) diff --git a/src/XRP/XAddress.h b/src/XRP/XAddress.h index 75454734821..1d1e38a5271 100644 --- a/src/XRP/XAddress.h +++ b/src/XRP/XAddress.h @@ -20,7 +20,7 @@ class XAddress { /// Number of bytes in a X-address. static const size_t size = 31; - /// Publick key hash length. + /// Public key hash length. static const size_t keyHashSize = 20; /// Address data consisting of public key hash diff --git a/src/proto/Aeternity.proto b/src/proto/Aeternity.proto index 8a20764369a..fc501db4859 100644 --- a/src/proto/Aeternity.proto +++ b/src/proto/Aeternity.proto @@ -11,8 +11,10 @@ message SigningInput { // Address of the recipient with "ak_" prefix string to_address = 2; + // Amount (uint256, serialized little endian) bytes amount = 3; + // Fee amount (uint256, serialized little endian) bytes fee = 4; // Message, optional @@ -21,15 +23,18 @@ message SigningInput { // Time to live until block height uint64 ttl = 6; + // Nonce (should be larger than in the last transaction of the account) uint64 nonce = 7; + // The secret private key used for signing (32 bytes). bytes private_key = 8; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed and encoded transaction bytes, Base64 with checksum string encoded = 1; + // Signature, Base58 with checksum string signature = 2; } diff --git a/src/proto/Aion.proto b/src/proto/Aion.proto index 771e6774171..2b194fc0237 100644 --- a/src/proto/Aion.proto +++ b/src/proto/Aion.proto @@ -5,32 +5,32 @@ option java_package = "wallet.core.jni.proto"; // Input data necessary to create a signed transaction. message SigningInput { - // Nonce (256-bit number) + // Nonce (uint256, serialized little endian) bytes nonce = 1; - // Gas price (256-bit number) + // Gas price (uint256, serialized little endian) bytes gas_price = 2; - // Gas limit (256-bit number) + // Gas limit (uint256, serialized little endian) bytes gas_limit = 3; // Recipient's address. string to_address = 4; - // Amount to send in wei (256-bit number) + // Amount to send in wei (uint256, serialized little endian) bytes amount = 5; // Optional payload bytes payload = 6; - // Private key. + // The secret private key used for signing (32 bytes). bytes private_key = 7; // Timestamp uint64 timestamp = 8; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed and encoded transaction bytes. bytes encoded = 1; diff --git a/src/proto/Algorand.proto b/src/proto/Algorand.proto index 937493e51a9..167fc0f10ee 100644 --- a/src/proto/Algorand.proto +++ b/src/proto/Algorand.proto @@ -3,18 +3,30 @@ syntax = "proto3"; package TW.Algorand.Proto; option java_package = "wallet.core.jni.proto"; +// Simple transfer message, transfer an amount to an address message Transfer { + // Destination address (string) string to_address = 1; + + // Amount uint64 amount = 2; } +// Asset Transfer message, with assetID message AssetTransfer { + // Destination address (string) string to_address = 1; + + // Amount uint64 amount = 2; + + // ID of the asset being transferred uint64 asset_id = 3; } +// Opt-in message for an asset message AssetOptIn { + // ID of the asset uint64 asset_id = 1; } @@ -22,19 +34,26 @@ message AssetOptIn { message SigningInput { // network / chain id string genesis_id = 1; + // network / chain hash bytes genesis_hash = 2; + // binary note data bytes note = 3; - // private key + + // The secret private key used for signing (32 bytes). bytes private_key = 4; + // network / first round uint64 first_round = 5; + // network / last round uint64 last_round = 6; - // fee + + // fee amount uint64 fee = 7; + // message payload oneof message_oneof { Transfer transfer = 10; AssetTransfer asset_transfer = 11; @@ -42,7 +61,7 @@ message SigningInput { } } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed and encoded transaction bytes. bytes encoded = 1; diff --git a/src/proto/Binance.proto b/src/proto/Binance.proto index 375c1ec7586..00df9f21fd2 100644 --- a/src/proto/Binance.proto +++ b/src/proto/Binance.proto @@ -5,140 +5,258 @@ option java_package = "wallet.core.jni.proto"; import "Common.proto"; +// Transaction structure, used internally message Transaction { - // int64 SIZE-OF-ENCODED // varint encoded length of the structure after encoding - // 0xF0625DEE // prefix - repeated bytes msgs = 1; // array of size 1, containing the transaction message, which are one of the transaction type below - repeated bytes signatures = 2; // array of size 1, containing the standard signature structure of the transaction sender - string memo = 3; // a short sentence of remark for the transaction, only for `Transfer` transactions. - int64 source = 4; // an identifier for tools triggerring this transaction, set to zero if unwilling to disclose. - bytes data = 5; // reserved for future use + // array of size 1, containing the transaction message, which are one of the transaction type below + repeated bytes msgs = 1; + + // array of size 1, containing the standard signature structure of the transaction sender + repeated bytes signatures = 2; + + // a short sentence of remark for the transaction, only for `Transfer` transactions. + string memo = 3; + + // an identifier for tools triggering this transaction, set to zero if unwilling to disclose. + int64 source = 4; + + // reserved for future use + bytes data = 5; } +// Signature structure, used internally message Signature { - message PubKey { - // 0xEB5AE987 // prefix - // bytes // public key bytes - } - bytes pub_key = 1; // public key bytes of the signer address - bytes signature = 2; // signature bytes, please check chain access section for signature generation - int64 account_number = 3; // another identifier of signer, which can be read from chain by account REST API or RPC - int64 sequence = 4; // sequence number for the next transaction + // public key bytes of the signer address + bytes pub_key = 1; + + // signature bytes, please check chain access section for signature generation + bytes signature = 2; + + // another identifier of signer, which can be read from chain by account REST API or RPC + int64 account_number = 3; + + // sequence number for the next transaction + int64 sequence = 4; } +// Message for Trade order message TradeOrder { - // 0xCE6DC043 // prefix - bytes sender = 1; // originating address - string id = 2; // order id, optional - string symbol = 3; // symbol for trading pair in full name of the tokens - int64 ordertype = 4; // only accept 2 for now, meaning limit order - int64 side = 5; // 1 for buy and 2 fory sell - int64 price = 6; // price of the order, which is the real price multiplied by 1e8 (10^8) and rounded to integer - int64 quantity = 7; // quantity of the order, which is the real price multiplied by 1e8 (10^8) and rounded to integer - int64 timeinforce = 8; // 1 for Good Till Expire(GTE) order and 3 for Immediate Or Cancel (IOC) + // originating address + bytes sender = 1; + + // order id, optional + string id = 2; + + // symbol for trading pair in full name of the tokens + string symbol = 3; + + // only accept 2 for now, meaning limit order + int64 ordertype = 4; + + // 1 for buy and 2 for sell + int64 side = 5; + + // price of the order, which is the real price multiplied by 1e8 (10^8) and rounded to integer + int64 price = 6; + + // quantity of the order, which is the real price multiplied by 1e8 (10^8) and rounded to integer + int64 quantity = 7; + + // 1 for Good Till Expire(GTE) order and 3 for Immediate Or Cancel (IOC) + int64 timeinforce = 8; } +// Message for CancelTrade order message CancelTradeOrder { - // 0x166E681B // prefix - bytes sender = 1; // originating address - string symbol = 2; // symbol for trading pair in full name of the tokens - string refid = 3; // order id to cancel + // originating address + bytes sender = 1; + + // symbol for trading pair in full name of the tokens + string symbol = 2; + + // order id to cancel + string refid = 3; } +// Message for Send order message SendOrder { - // 0x2A2C87FA - // A symbol-amount pair. Could be moved out of SendOrder; kept here for backward compatibility. + // A token amount, symbol-amount pair. Could be moved out of SendOrder; kept here for backward compatibility. message Token { + // Token ID string denom = 1; + + // Amount int64 amount = 2; } + + // Transaction input message Input { + // source address bytes address = 1; + + // input coin amounts repeated Token coins = 2; } + + // Transaction output message Output { + // destination address bytes address = 1; + + // output coin amounts repeated Token coins = 2; } + + // Send inputs repeated Input inputs = 1; + + // Send outputs repeated Output outputs = 2; } +// Message for TokenIssue order message TokenIssueOrder { - // 0x17EFAB80 // prefix - bytes from = 1; // owner address - string name = 2; // token name - string symbol = 3; // token symbol, in full name with "-" suffix - int64 total_supply = 4; // total supply - bool mintable = 5; // mintable + // owner address + bytes from = 1; + + // token name + string name = 2; + + // token symbol, in full name with "-" suffix + string symbol = 3; + + // total supply + int64 total_supply = 4; + + // mintable + bool mintable = 5; } +// Message for TokenMint order message TokenMintOrder { - // 0x467E0829 // prefix - bytes from = 1; // owner address - string symbol = 2; // token symbol, in full name with "-" suffix - int64 amount = 3; // amount to mint + // owner address + bytes from = 1; + + // token symbol, in full name with "-" suffix + string symbol = 2; + + // amount to mint + int64 amount = 3; } +// Message for TokenBurn order message TokenBurnOrder { - // 0x7ED2D2A0 // prefix - bytes from = 1; // owner address - string symbol = 2; // token symbol, in full name with "-" suffix - int64 amount = 3; // amount to burn + // owner address + bytes from = 1; + + // token symbol, in full name with "-" suffix + string symbol = 2; + + // amount to burn + int64 amount = 3; } +// Message for TokenFreeze order message TokenFreezeOrder { - // 0xE774B32D // prefix - bytes from = 1; // owner address - string symbol = 2; // token symbol, in full name with "-" suffix - int64 amount = 3; // amount of token to freeze + // owner address + bytes from = 1; + + // token symbol, in full name with "-" suffix + string symbol = 2; + + // amount of token to freeze + int64 amount = 3; } +// Message for TokenUnfreeze order message TokenUnfreezeOrder { - // 0x6515FF0D // prefix - bytes from = 1; // owner address - string symbol = 2; // token symbol, in full name with "-" suffix - int64 amount = 3; // amount of token to unfreeze + // owner address + bytes from = 1; + + // token symbol, in full name with "-" suffix + string symbol = 2; + + // amount of token to unfreeze + int64 amount = 3; } +// Message for HashTimeLock order message HTLTOrder { - // 0xB33F9A24 // prefix - bytes from = 1; // signer address - bytes to = 2; // recipient address + // signer address + bytes from = 1; + + // recipient address + bytes to = 2; + + // source on other chain, optional string recipient_other_chain = 3; + + // recipient on other chain, optional string sender_other_chain = 4; - bytes random_number_hash = 5; //hash of a random number and timestamp, based on SHA256 + + // hash of a random number and timestamp, based on SHA256 + bytes random_number_hash = 5; + + // timestamp int64 timestamp = 6; + + // amounts repeated SendOrder.Token amount = 7; - string expected_income = 8; // expected gained token on the other chain + + // expected gained token on the other chain + string expected_income = 8; + + // period expressed in block heights int64 height_span = 9; + + // set for cross-chain send bool cross_chain = 10; } +// Message for Deposit HTLT order message DepositHTLTOrder { - // 0xB33F9A24 // prefix - bytes from = 1; // signer address + // signer address + bytes from = 1; + + // amounts repeated SendOrder.Token amount = 2; + + // swap ID bytes swap_id = 3; } +// Message for Claim HTLT order message ClaimHTLOrder { - // 0xC1665300 // prefix - bytes from = 1; // signer address + // signer address + bytes from = 1; + + // swap ID bytes swap_id = 2; + + // random number input bytes random_number = 3; } +// Message for Refund HTLT order message RefundHTLTOrder { - // 0x3454A27C // prefix - bytes from = 1; // signer address + // signer address + bytes from = 1; + + // swap ID bytes swap_id = 2; } +// Transfer message TransferOut { + // source address bytes from = 1; + + // recipient address bytes to = 2; + + // transfer amount SendOrder.Token amount = 3; + + // expiration time int64 expire_time = 4; } @@ -164,37 +282,73 @@ message SideChainUndelegate { string chain_id = 4; } +// Message for TimeLock order message TimeLockOrder { - bytes from_address = 1; // owner address + // owner address + bytes from_address = 1; + + // Description (optional) string description = 2; + // Array of symbol/amount pairs. see SDK https://github.com/binance-chain/javascript-sdk/blob/master/docs/api-docs/classes/tokenmanagement.md#timelock repeated SendOrder.Token amount = 3; + + // lock time int64 lock_time = 4; } +// Message for TimeRelock order message TimeRelockOrder { - bytes from_address = 1; // owner address - int64 id = 2; // order ID + // owner address + bytes from_address = 1; + + // order ID + int64 id = 2; + + // Description (optional) string description = 3; + // Array of symbol/amount pairs. repeated SendOrder.Token amount = 4; + + // lock time int64 lock_time = 5; } +// Message for TimeUnlock order message TimeUnlockOrder { - bytes from_address = 1; // owner address - int64 id = 2; // order ID + // owner address + bytes from_address = 1; + + // order ID + int64 id = 2; } -// Input data necessary to create a signed order. +// Input data necessary to create a signed transaction. message SigningInput { + // Chain ID string chain_id = 1; + + // Source account number int64 account_number = 2; + + // Sequence number (account specific) int64 sequence = 3; + + // Transaction source, see https://github.com/bnb-chain/BEPs/blob/master/BEP10.md + // Some important values: + // 0: Default source value (e.g. for Binance Chain Command Line, or SDKs) + // 1: Binance DEX Web Wallet + // 2: Trust Wallet int64 source = 4; + + // Optional memo string memo = 5; + + // The secret private key used for signing (32 bytes). bytes private_key = 6; + // Payload message oneof order_oneof { TradeOrder trade_order = 8; CancelTradeOrder cancel_trade_order = 9; @@ -218,14 +372,14 @@ message SigningInput { } } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed and encoded transaction bytes. bytes encoded = 1; - /// error code, 0 is ok, other codes will be treated as errors + // OK (=0) or other codes in case of error Common.Proto.SigningError error = 2; - /// error description + // error description in case of error string error_message = 3; } diff --git a/src/proto/Bitcoin.proto b/src/proto/Bitcoin.proto index 1e9e631284a..cb321e44a8a 100644 --- a/src/proto/Bitcoin.proto +++ b/src/proto/Bitcoin.proto @@ -5,6 +5,7 @@ option java_package = "wallet.core.jni.proto"; import "Common.proto"; +// A transaction, with its inputs and outputs message Transaction { // Transaction data format version. sint32 version = 1; @@ -15,7 +16,7 @@ message Transaction { // A list of 1 or more transaction inputs or sources for coins. repeated TransactionInput inputs = 3; - // A list of 1 or more transaction outputs or destinations for coins + // A list of 1 or more transaction outputs or destinations for coins. repeated TransactionOutput outputs = 4; } @@ -33,7 +34,7 @@ message TransactionInput { // Bitcoin transaction out-point reference. message OutPoint { - // The hash of the referenced transaction. + // The hash of the referenced transaction (network byte order, usually needs to be reversed). bytes hash = 1; // The index of the specific output in the transaction. @@ -74,31 +75,31 @@ message SigningInput { // If amount is equal or more than the available amount, also max amount will be used. int64 amount = 2; - // Transaction fee per byte. + // Transaction fee rate, satoshis per byte, used to compute required fee (when planning) int64 byte_fee = 3; - // Recipient's address. + // Recipient's address, as string. string to_address = 4; - // Change address. + // Change address, as string. string change_address = 5; - // Available private keys. + // The available secret private key or keys required for signing (32 bytes each). repeated bytes private_key = 6; // Available redeem scripts indexed by script hash. map scripts = 7; - // Available unspent transaction outputs. + // Available input unspent transaction outputs. repeated UnspentTransaction utxo = 8; - // If sending max amount. + // Set if sending max amount is requested. bool use_max_amount = 9; - // Coin type (forks). + // Coin type (used by forks). uint32 coin_type = 10; - // Optional transaction plan + // Optional transaction plan. If missing, plan will be computed. TransactionPlan plan = 11; // Optional lockTime, default value 0 means no time locking. @@ -117,16 +118,16 @@ message TransactionPlan { // Amount to be received at the other end. int64 amount = 1; - // Maximum available amount. + // Maximum available amount in all the input UTXOs. int64 available_amount = 2; // Estimated transaction fee. int64 fee = 3; - // Change. + // Remaining change int64 change = 4; - // Selected unspent transaction outputs. + // Selected unspent transaction outputs (subset of all input UTXOs) repeated UnspentTransaction utxos = 5; // Zcash branch id @@ -139,23 +140,26 @@ message TransactionPlan { bytes output_op_return = 8; }; -// Transaction signing output. +// Result containing the signed and encoded transaction. +// Note that the amount may be different than the requested amount to account for fees and available funds. message SigningOutput { - // Resulting transaction. Note that the amount may be different than the requested amount to account for fees and available funds. + // Resulting transaction. Transaction transaction = 1; // Signed and encoded transaction bytes. bytes encoded = 2; - // Transaction id + // Transaction ID (hash) string transaction_id = 3; // Optional error Common.Proto.SigningError error = 4; + // error description string error_message = 5; } +/// Pre-image hash to be used for signing message HashPublicKey { /// Pre-image data hash that will be used for signing bytes data_hash = 1; @@ -174,4 +178,4 @@ message PreSigningOutput { /// error description string error_message = 3; -} \ No newline at end of file +} diff --git a/src/proto/Cardano.proto b/src/proto/Cardano.proto index c3ceaa27df9..ffeec086591 100644 --- a/src/proto/Cardano.proto +++ b/src/proto/Cardano.proto @@ -5,30 +5,45 @@ option java_package = "wallet.core.jni.proto"; import "Common.proto"; +// A transaction output that can be used as input message OutPoint { + // The transaction ID bytes tx_hash = 1; + + // The index of this output within the transaction uint64 output_index = 2; } +// Represents a token and an amount. Token is identified by PolicyID and name. message TokenAmount { - string policy_id = 1; // as hex string (28x2 digits) + // Policy ID of the token, as hex string (28x2 digits) + string policy_id = 1; + + // The name of the asset (within the policy) string asset_name = 2; - bytes amount = 3; // 256-bit number + + // The amount (uint256, serialized little endian) + bytes amount = 3; } +// One input for a transaction message TxInput { + // The UTXO OutPoint out_point = 1; + // The owner address (string) string address = 2; - // ADA amount + // ADA amount in the UTXO uint64 amount = 3; - // optional token amounts + // optional token amounts in the UTXO repeated TokenAmount token_amount = 4; } +// One output for a transaction message TxOutput { + // Destination address (string) string address = 1; // ADA amount @@ -43,6 +58,7 @@ message TokenBundle { repeated TokenAmount token = 1; } +// Message for simple Transfer tx message Transfer { // Destination address as string string to_address = 1; @@ -66,7 +82,7 @@ message Transfer { uint64 force_fee = 6; } -// Register a staking key for the account, preprequisite for Staking. +// Register a staking key for the account, prerequisite for Staking. // Note: staking messages are typically used with a 1-output-to-self transaction. message RegisterStakingKey { // Staking address (as string) @@ -106,6 +122,7 @@ message Withdraw { uint64 withdraw_amount = 2; } +// Describes a preliminary transaction plan. message TransactionPlan { // total coins in the utxos uint64 available_amount = 1; @@ -134,16 +151,19 @@ message TransactionPlan { // tokens in the change (optional) repeated TokenAmount change_tokens = 7; + // The selected UTXOs, subset ot the input UTXOs repeated TxInput utxos = 8; + // Optional error Common.Proto.SigningError error = 9; } -// Input data necessary to create a signed transaction +// Input data necessary to create a signed transaction. message SigningInput { + // Available input UTXOs repeated TxInput utxos = 1; - // Available private keys (double extended keys); every input UTXO adress should be covered + // Available private keys (double extended keys); every input UTXO address should be covered // In case of Plan only, keys should be present, in correct number repeated bytes private_key = 2; @@ -162,14 +182,16 @@ message SigningInput { // Optional DeregisterStakingKey deregister_staking_key = 9; + // Time-to-live time of the TX uint64 ttl = 4; - // Optional plan + // Optional plan, if missing it will be computed TransactionPlan plan = 5; } -// Transaction signing output +// Result containing the signed and encoded transaction. message SigningOutput { + // Encoded transaction bytes bytes encoded = 1; // TxID, derived from transaction data, also needed for submission diff --git a/src/proto/Common.proto b/src/proto/Common.proto index 7b24800829d..cedf89feee4 100644 --- a/src/proto/Common.proto +++ b/src/proto/Common.proto @@ -3,36 +3,68 @@ syntax = "proto3"; package TW.Common.Proto; option java_package = "wallet.core.jni.proto"; +// Error codes, used in multiple blockchains. enum SigningError { - OK = 0; // OK - // chain-generic, generic + // This is the OK case, with value=0 + OK = 0; + + // Chain-generic codes: + // Generic error (used if there is no suitable specific error is adequate) Error_general = 1; + // Internal error, indicates some very unusual, unexpected case Error_internal = 2; - // chain-generic, input + + // Chain-generic codes, input related: + // Low balance: the sender balance is not enough to cover the send and other auxiliary amount such as fee, deposit, or minimal balance. Error_low_balance = 3; - Error_zero_amount_requested = 4; // Requested amount is zero + // Requested amount is zero, send of 0 makes no sense + Error_zero_amount_requested = 4; + // One required key is missing (too few or wrong keys are provided) Error_missing_private_key = 5; + // A private key provided is invalid (e.g. wrong size, usually should be 32 bytes) Error_invalid_private_key = 15; + // A provided address (e.g. destination address) is invalid Error_invalid_address = 16; + // A provided input UTXO is invalid Error_invalid_utxo = 17; + // The amount of an input UTXO is invalid Error_invalid_utxo_amount = 18; - // chain-generic, fee + + // Chain-generic, fee related: + // Wrong fee is given, probably it is too low to cover minimal fee for the transaction Error_wrong_fee = 6; - // chain-generic, signing + + // Chain-generic, signing related: + // General signing error Error_signing = 7; - Error_tx_too_big = 8; // [NEO] Transaction too big, fee in GAS needed or try send by parts - // UTXO-chain specific, inputs - Error_missing_input_utxos = 9; // No UTXOs provided [BTC] - Error_not_enough_utxos = 10; // Not enough non-dust input UTXOs to cover requested amount (dust UTXOs are filtered out) [BTC] - // UTXO-chain specific, script - Error_script_redeem = 11; // [BTC] Missing redeem script - Error_script_output = 12; // [BTC] Invalid output script - Error_script_witness_program = 13; // [BTC] Unrecognized witness program - - Error_invalid_memo = 14; // e.g. [XRP] Invalid tag - Error_input_parse = 19; // e.g. Invalid input data - Error_no_support_n2n = 20; // e.g. Not support multi-input and multi-output transaction - Error_signatures_count = 21; // Incorrect count of signatures passed to compile - Error_invalid_params = 22; // Incorrect parameters + // Resulting transaction is too large + // [NEO] Transaction too big, fee in GAS needed or try send by parts + Error_tx_too_big = 8; + + // UTXO-chain specific, input related: + // No input UTXOs provided [BTC] + Error_missing_input_utxos = 9; + // Not enough non-dust input UTXOs to cover requested amount (dust UTXOs are filtered out) [BTC] + Error_not_enough_utxos = 10; + + // UTXO-chain specific, script related: + // [BTC] Missing required redeem script + Error_script_redeem = 11; + // [BTC] Invalid required output script + Error_script_output = 12; + // [BTC] Unrecognized witness program + Error_script_witness_program = 13; + + // Invalid memo, e.g. [XRP] Invalid tag + Error_invalid_memo = 14; + // Some input field cannot be parsed + Error_input_parse = 19; + // Multi-input and multi-output transaction not supported + Error_no_support_n2n = 20; + // Incorrect count of signatures passed to compile + Error_signatures_count = 21; + // Incorrect input parameter + Error_invalid_params = 22; + // Invalid input token amount Error_invalid_requested_token_amount = 23; } diff --git a/src/proto/Cosmos.proto b/src/proto/Cosmos.proto index ddeacaa1f5a..e95b00daa37 100644 --- a/src/proto/Cosmos.proto +++ b/src/proto/Cosmos.proto @@ -3,13 +3,21 @@ syntax = "proto3"; package TW.Cosmos.Proto; option java_package = "wallet.core.jni.proto"; +// A denomination and an amount message Amount { + // name of the denomination string denom = 1; + + // amount, number as string string amount = 2; } +// Fee incl. gas message Fee { + // Fee amount(s) repeated Amount amounts = 1; + + // Gas price uint64 gas = 2; } @@ -22,12 +30,14 @@ message Height { uint64 revision_height = 2; } +// Transaction broadcast mode enum BroadcastMode { BLOCK = 0; // Wait for the tx to pass/fail CheckTx, DeliverTx, and be committed in a block SYNC = 1; // Wait for the tx to pass/fail CheckTx ASYNC = 2; // Don't wait for pass/fail CheckTx; send and return tx immediately } +// A transaction payload message message Message { // cosmos-sdk/MsgSend message Send { @@ -260,6 +270,7 @@ message Message { string msg_type_url = 3; } + // The payload message oneof message_oneof { Send send_coins_message = 1; Transfer transfer_tokens_message = 2; @@ -281,30 +292,43 @@ message Message { } } +// Options for transaction encoding: JSON (Amino, older) or Protobuf. enum SigningMode { JSON = 0; // JSON format, Pre-Stargate Protobuf = 1; // Protobuf-serialized (binary), Stargate } -// Input data necessary to create a signed order. +// Input data necessary to create a signed transaction. message SigningInput { - // Specify if Stargate or earlier serialization is used + // Specify if protobuf (a.k.a. Stargate) or earlier JSON serialization is used SigningMode signing_mode = 1; + // Source account number uint64 account_number = 2; + + // Chain ID (string) string chain_id = 3; + + // Transaction fee Fee fee = 4; + + // Optional memo string memo = 5; + + // Sequence number (account specific) uint64 sequence = 6; + // The secret private key used for signing (32 bytes). bytes private_key = 7; + // Payload message(s) repeated Message messages = 8; + // Broadcast mode (included in output, relevant when broadcasting) BroadcastMode mode = 9; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signature bytes signature = 1; diff --git a/src/proto/Decred.proto b/src/proto/Decred.proto index d8355f5e6b5..fe9a8ff5663 100644 --- a/src/proto/Decred.proto +++ b/src/proto/Decred.proto @@ -6,11 +6,12 @@ option java_package = "wallet.core.jni.proto"; import "Bitcoin.proto"; import "Common.proto"; +// A transfer transaction message Transaction { - /// Serialization format + // Serialization format uint32 serializeType = 1; - /// Transaction data format version + // Transaction data format version uint32 version = 2; // A list of 1 or more transaction inputs or sources for coins. @@ -19,10 +20,10 @@ message Transaction { // A list of 1 or more transaction outputs or destinations for coins repeated TransactionOutput outputs = 4; - /// The time when a transaction can be spent (usually zero, in which case it has no effect). + // The time when a transaction can be spent (usually zero, in which case it has no effect). uint32 lockTime = 5; - /// The block height at which the transaction expires and is no longer valid. + // The block height at which the transaction expires and is no longer valid. uint32 expiry = 6; } @@ -34,8 +35,13 @@ message TransactionInput { // Transaction version as defined by the sender. uint32 sequence = 2; + // The amount of the input int64 valueIn = 3; + + // Creation block height uint32 blockHeight = 4; + + // Index within the block uint32 blockIndex = 5; // Computational script for confirming transaction authorization. @@ -47,14 +53,14 @@ message TransactionOutput { // Transaction amount. int64 value = 1; - /// Transaction output version. + // Transaction output version. uint32 version = 2; // Usually contains the public key as a Decred script setting up conditions to claim this output. bytes script = 3; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Resulting transaction. Note that the amount may be different than the requested amount to account for fees and available funds. Transaction transaction = 1; diff --git a/src/proto/EOS.proto b/src/proto/EOS.proto index d6a09f94f41..7f32c0a75fd 100644 --- a/src/proto/EOS.proto +++ b/src/proto/EOS.proto @@ -13,17 +13,22 @@ enum KeyType { // Values for an Asset object. message Asset { + // Total amount int64 amount = 1; + + // Number of decimals defined uint32 decimals = 2; + + // Asset symbol string symbol = 3; } // Input data necessary to create a signed transaction. message SigningInput { - // Chain id (256-bit number) + // Chain id (uint256, serialized little endian) bytes chain_id = 1; - // Reference Block Id (256-bits) + // Reference Block Id (uint256, serialized little endian) bytes reference_block_id = 2; // Timestamp on the reference block @@ -44,14 +49,14 @@ message SigningInput { // Asset details and amount Asset asset = 8; - // Sender's private key's raw bytes + // Sender's secret private key used for signing (32 bytes). bytes private_key = 9; // Type of the private key KeyType private_key_type = 10; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // JSON of the packed transaction. string json_encoded = 1; diff --git a/src/proto/Elrond.proto b/src/proto/Elrond.proto index a2f4c59728a..9951055fde1 100644 --- a/src/proto/Elrond.proto +++ b/src/proto/Elrond.proto @@ -11,10 +11,18 @@ option java_package = "wallet.core.jni.proto"; // Generic action. Using one of the more specific actions (e.g. transfers, see below) is recommended. message GenericAction { + // Accounts involved Accounts accounts = 1; + + // amount string value = 2; + + // additional data string data = 3; + + // transaction version uint32 version = 4; + // Currently, the "options" field should be ignored (not set) by applications using TW Core. // In the future, TW Core will handle specific transaction options // (such as the "SignedWithHash" flag, as seen in https://github.com/ElrondNetwork/elrond-go-core/blob/main/core/versioning/txVersionChecker.go) @@ -24,41 +32,72 @@ message GenericAction { // EGLD transfer (move balance). message EGLDTransfer { + // Accounts involved Accounts accounts = 1; + + // Transfer amount (string) string amount = 2; } // ESDT transfer (transfer regular ESDTs - fungible tokens). message ESDTTransfer { + // Accounts involved Accounts accounts = 1; + + // Token ID string token_identifier = 2; + + // Transfer token amount (string) string amount = 3; } // ESDTNFT transfer (transfer NFTs, SFTs and Meta ESDTs). message ESDTNFTTransfer { + // Accounts involved Accounts accounts = 1; + + // tokens string token_collection = 2; + + // nonce of the token uint64 token_nonce = 3; + + // transfer amount string amount = 4; } // Transaction sender & receiver etc. message Accounts { + // Nonce of the sender uint64 sender_nonce = 1; + + // Sender address string sender = 2; + + // Sender username string sender_username = 3; + + // Receiver address string receiver = 4; + string receiver_username = 5; } // Input data necessary to create a signed transaction. message SigningInput { + // The secret private key used for signing (32 bytes). bytes private_key = 1; + + // Chain identifier, string string chain_id = 2; + + // Gas price uint64 gas_price = 3; + + // Limit for the gas used uint64 gas_limit = 4; + // transfer payload oneof message_oneof { GenericAction generic_action = 5; EGLDTransfer egld_transfer = 6; @@ -67,7 +106,7 @@ message SigningInput { } } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { string encoded = 1; string signature = 2; diff --git a/src/proto/Ethereum.proto b/src/proto/Ethereum.proto index f67ea7b4100..ce3ab148556 100644 --- a/src/proto/Ethereum.proto +++ b/src/proto/Ethereum.proto @@ -9,7 +9,7 @@ import "Common.proto"; message Transaction { // Native coin transfer transaction message Transfer { - // Amount to send in wei (256-bit number) + // Amount to send in wei (uint256, serialized little endian) bytes amount = 1; // Optional payload data @@ -18,40 +18,46 @@ message Transaction { // ERC20 token transfer transaction message ERC20Transfer { + // destination address (string) string to = 1; - // Amount to send (256-bit number) + // Amount to send (uint256, serialized little endian) bytes amount = 2; } // ERC20 approve transaction message ERC20Approve { + // Target of the approval string spender = 1; - // Amount to send (256-bit number) + // Amount to send (uint256, serialized little endian) bytes amount = 2; } // ERC721 NFT transfer transaction message ERC721Transfer { + // Source address string from = 1; + // Destination address string to = 2; - // ID of the token (256-bit number) + // ID of the token (uint256, serialized little endian) bytes token_id = 3; } // ERC1155 NFT transfer transaction message ERC1155Transfer { + // Source address string from = 1; + // Destination address string to = 2; - // ID of the token (256-bit number) + // ID of the token (uint256, serialized little endian) bytes token_id = 3; - // The amount of tokens being transferred + // The amount of tokens being transferred (uint256, serialized little endian) bytes value = 4; bytes data = 5; @@ -59,13 +65,14 @@ message Transaction { // Generic smart contract transaction message ContractGeneric { - // Amount to send in wei (256-bit number) + // Amount to send in wei (uint256, serialized little endian) bytes amount = 1; // Contract call payload data bytes data = 2; } + // Payload transfer oneof transaction_oneof { Transfer transfer = 1; ERC20Transfer erc20_transfer = 2; @@ -76,53 +83,59 @@ message Transaction { } } +// Transaction type enum TransactionMode { - Legacy = 0; // Legacy transaction, pre-EIP2718/EIP1559; for fee gasPrice/gasLimit is used - Enveloped = 1; // Enveloped transaction EIP2718 (with type 0x2), fee is according to EIP1559 (base fee, inclusion fee, ...) + // Legacy transaction, pre-EIP2718/EIP1559; for fee gasPrice/gasLimit is used + Legacy = 0; + + // Enveloped transaction EIP2718 (with type 0x2), fee is according to EIP1559 (base fee, inclusion fee, ...) + Enveloped = 1; } // Input data necessary to create a signed transaction. // Legacy and EIP2718/EIP1559 transactions supported, see TransactionMode. message SigningInput { - // Chain identifier (256-bit number) + // Chain identifier (uint256, serialized little endian) bytes chain_id = 1; - // Nonce (256-bit number) + // Nonce (uint256, serialized little endian) bytes nonce = 2; // Transaction version selector: Legacy or enveloped, has impact on fee structure. // Default is Legacy (value 0) TransactionMode tx_mode = 3; - // Gas price (256-bit number) + // Gas price (uint256, serialized little endian) // Relevant for legacy transactions only (disregarded for enveloped/EIP1559) bytes gas_price = 4; - // Gas limit (256-bit number) + // Gas limit (uint256, serialized little endian) bytes gas_limit = 5; - // Maxinmum optional inclusion fee (aka tip) (256-bit number) + // Maximum optional inclusion fee (aka tip) (uint256, serialized little endian) // Relevant for enveloped/EIP1559 transactions only, tx_mode=Enveloped, (disregarded for legacy) bytes max_inclusion_fee_per_gas = 6; - // Maxinmum fee (256-bit number) + // Maximum fee (uint256, serialized little endian) // Relevant for enveloped/EIP1559 transactions only, tx_mode=Enveloped, (disregarded for legacy) bytes max_fee_per_gas = 7; // Recipient's address. string to_address = 8; - // Private key. + // The secret private key used for signing (32 bytes). bytes private_key = 9; + // The payload transaction Transaction transaction = 10; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed and encoded transaction bytes. bytes encoded = 1; + // The V, R, S components of the resulting signature, (each uint256, serialized little endian) bytes v = 2; bytes r = 3; bytes s = 4; @@ -130,9 +143,9 @@ message SigningOutput { // The payload part, supplied in the input or assembled from input parameters bytes data = 5; - /// error code, 0 is ok, other codes will be treated as errors + // error code, 0 is ok, other codes will be treated as errors Common.Proto.SigningError error = 6; - /// error code description + // error code description string error_message = 7; } diff --git a/src/proto/Everscale.proto b/src/proto/Everscale.proto index c98841981c4..54ed4bb825c 100644 --- a/src/proto/Everscale.proto +++ b/src/proto/Everscale.proto @@ -9,11 +9,17 @@ syntax = "proto3"; package TW.Everscale.Proto; option java_package = "wallet.core.jni.proto"; + +// Message option enum MessageBehavior { - SimpleTransfer = 0; // Sends a message with the specified amount. The sender pays a fee from the account balance - SendAllBalance = 1; // Sends the entire account balance along with the message + // Sends a message with the specified amount. The sender pays a fee from the account balance + SimpleTransfer = 0; + + // Sends the entire account balance along with the message + SendAllBalance = 1; } +// Transfer message message Transfer { // If set to true, then the message will be returned if there is an error on the recipient's side. bool bounce = 1; @@ -37,14 +43,18 @@ message Transfer { } } +// Input data necessary to create a signed transaction. message SigningInput { + // The payload transfer oneof action_oneof { Transfer transfer = 1; } + // The secret private key used for signing (32 bytes). bytes private_key = 2; } +// Result containing the signed and encoded transaction. message SigningOutput { string encoded = 1; } diff --git a/src/proto/FIO.proto b/src/proto/FIO.proto index 5579cde39dd..e946dcf3fa7 100644 --- a/src/proto/FIO.proto +++ b/src/proto/FIO.proto @@ -52,6 +52,7 @@ message Action { } // Acion for adding public chain addresses to a FIO name; add_pub_address + // Note: actor is not needed, computed from private key message AddPubAddress { // The FIO name already registered to the owner. Ex.: "alice@trust" string fio_address = 1; @@ -60,12 +61,11 @@ message Action { repeated PublicAddress public_addresses = 2; // Max fee to spend, can be obtained using get_fee API. - uint64 fee = 3; - - // Note: actor is not needed, computed from private key + uint64 fee = 3; } - // Action for transfering FIO coins; transfer_tokens_pub_key + // Action for transferring FIO coins; transfer_tokens_pub_key + // Note: actor is not needed, computed from private key message Transfer { // FIO address of the payee. Ex.: "FIO6m1fMdTpRkRBnedvYshXCxLFiC5suRU8KDfx8xxtXp2hntxpnf" string payee_public_key = 1; @@ -75,11 +75,10 @@ message Action { // Max fee to spend, can be obtained using get_fee API. uint64 fee = 3; - - // Note: actor is not needed, computed from private key } // Action for renewing a FIO name; renew_fio_address + // Note: actor is not needed, computed from private key message RenewFioAddress { // The FIO name to be renewed. Ex.: "alice@trust" string fio_address = 1; @@ -89,11 +88,10 @@ message Action { // Max fee to spend, can be obtained using get_fee API. uint64 fee = 3; - - // Note: actor is not needed, computed from owner_fio_public_key } // Action for creating a new payment request; new_funds_request + // Note: actor is not needed, computed from private key message NewFundsRequest { // The FIO name of the requested payer. Ex.: "alice@trust" string payer_fio_name = 1; @@ -109,10 +107,9 @@ message Action { // Max fee to spend, can be obtained using get_fee API. uint64 fee = 5; - - // Note: actor is not needed, computed from private key } + // Payload message oneof message_oneof { RegisterFioAddress register_fio_address_message = 1; AddPubAddress add_pub_address_message = 2; @@ -134,7 +131,7 @@ message ChainParams { uint64 ref_block_prefix = 3; } -// Transaction signing input +// Input data necessary to create a signed transaction. message SigningInput { // Expiry for this message, in unix time. Can be 0, then it is taken from current time with default expiry uint32 expiry = 1; @@ -142,7 +139,7 @@ message SigningInput { // Current parameters of the FIO blockchain ChainParams chain_params = 2; - // The private key matching the address, needed for signing + // The secret private key matching the address, used for signing (32 bytes). bytes private_key = 3; // The FIO name of the originating wallet (project-wide constant) @@ -152,7 +149,7 @@ message SigningInput { Action action = 5; } -// Transaction signing output +// Result containing the signed and encoded transaction. message SigningOutput { // Signed transaction in JSON string json = 1; diff --git a/src/proto/Filecoin.proto b/src/proto/Filecoin.proto index 0c39da82c72..58ef6a156c0 100644 --- a/src/proto/Filecoin.proto +++ b/src/proto/Filecoin.proto @@ -5,7 +5,7 @@ option java_package = "wallet.core.jni.proto"; // Input data necessary to create a signed transaction. message SigningInput { - // Private key of sender account. + // The secret private key of the sender account, used for signing (32 bytes). bytes private_key = 1; // Recipient's address. @@ -14,20 +14,21 @@ message SigningInput { // Transaction nonce. uint64 nonce = 3; - // Transfer value. + // Transfer value (uint256, serialized little endian) bytes value = 4; // Gas limit. int64 gas_limit = 5; - // Gas fee cap. + // Gas fee cap (uint256, serialized little endian) bytes gas_fee_cap = 6; - // Gas premium. + // Gas premium (uint256, serialized little endian) bytes gas_premium = 7; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { + // Resulting transaction, in JSON. string json = 1; } diff --git a/src/proto/Harmony.proto b/src/proto/Harmony.proto index 72762c24acd..86647fad3bd 100644 --- a/src/proto/Harmony.proto +++ b/src/proto/Harmony.proto @@ -5,54 +5,58 @@ option java_package = "wallet.core.jni.proto"; // Input data necessary to create a signed transaction. message SigningInput { - // Chain identifier (256-bit number) + // Chain identifier (uint256, serialized little endian) bytes chain_id = 1; - // Private key. + // The secret private key used for signing (32 bytes). bytes private_key = 2; + // The payload message oneof message_oneof { TransactionMessage transaction_message = 3; StakingMessage staking_message = 4; } } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed and encoded transaction bytes. bytes encoded = 1; + // THE V,R,S components of the signature bytes v = 2; bytes r = 3; bytes s = 4; } +// A Transfer message message TransactionMessage { - // Nonce (256-bit number) + // Nonce (uint256, serialized little endian) bytes nonce = 1; - // Gas price (256-bit number) + // Gas price (uint256, serialized little endian) bytes gas_price = 2; - // Gas limit (256-bit number) + // Gas limit (uint256, serialized little endian) bytes gas_limit = 3; // Recipient's address. string to_address = 4; - // Amount to send in wei (256-bit number) + // Amount to send in wei (uint256, serialized little endian) bytes amount = 5; // Optional payload bytes payload = 6; - // From shard ID (256-bit number) + // From shard ID (uint256, serialized little endian) bytes from_shard_id = 7; - // To Shard ID (256-bit number) + // To Shard ID (uint256, serialized little endian) bytes to_shard_id = 8; } +// A Staking message. message StakingMessage { // StakeMsg oneof stake_msg { @@ -63,16 +67,17 @@ message StakingMessage { DirectiveCollectRewards collect_rewards = 5; } - // Nonce (256-bit number) + // Nonce (uint256, serialized little endian) bytes nonce = 6; - // Gas price (256-bit number) + // Gas price (uint256, serialized little endian) bytes gas_price = 7; - // Gas limit (256-bit number) + // Gas limit (uint256, serialized little endian) bytes gas_limit = 8; } +// Description for a validator message Description { string name = 1; string identity = 2; @@ -81,21 +86,38 @@ message Description { string details = 5; } +// A variable precision number message Decimal { + // The 'raw' value bytes value = 1; + + // The precision (number of decimals) bytes precision = 2; } +// Represents validator commission rule message CommissionRate { + // The rate Decimal rate = 1; + + // Maximum rate Decimal max_rate = 2; + + // Maximum of rate change Decimal max_change_rate = 3; } +// Create Validator directive message DirectiveCreateValidator { + // Address of validator string validator_address = 1; + + // Description, name etc. Description description = 2; + + // Rates CommissionRate commission_rates = 3; + bytes min_self_delegation = 4; bytes max_total_delegation = 5; repeated bytes slot_pub_keys = 6; @@ -103,7 +125,10 @@ message DirectiveCreateValidator { bytes amount = 8; } + +// Edit Validator directive message DirectiveEditValidator { + // Validator address string validator_address = 1; Description description = 2; Decimal commission_rate = 3; @@ -115,18 +140,33 @@ message DirectiveEditValidator { bytes active = 9; } +// Delegate directive message DirectiveDelegate { + // Delegator address string delegator_address = 1; + + // Validator address string validator_address = 2; + + // Delegate amount (uint256, serialized little endian) bytes amount = 3; } +// Undelegate directive message DirectiveUndelegate { + // Delegator address string delegator_address = 1; + + // Validator address string validator_address = 2; + + // Undelegate amount (uint256, serialized little endian) bytes amount = 3; } + +// Collect reward message DirectiveCollectRewards { + // Delegator address string delegator_address = 1; -} \ No newline at end of file +} diff --git a/src/proto/Icon.proto b/src/proto/Icon.proto index 8319b026d7c..fc39efc3ee8 100644 --- a/src/proto/Icon.proto +++ b/src/proto/Icon.proto @@ -11,7 +11,7 @@ message SigningInput { // Recipient address. string to_address = 2; - // Transfer amount. + // Transfer amount (uint256, serialized little endian) bytes value = 3; // The amount of step to send with the transaction. @@ -26,11 +26,11 @@ message SigningInput { // Network identifier bytes network_id = 7; - // Private key. + // The secret private key used for signing (32 bytes). bytes private_key = 8; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // JSON-encoded transaction parameters. string encoded = 1; diff --git a/src/proto/IoTeX.proto b/src/proto/IoTeX.proto index 1df337cf627..275dd40d8ab 100644 --- a/src/proto/IoTeX.proto +++ b/src/proto/IoTeX.proto @@ -3,96 +3,159 @@ syntax = "proto3"; package TW.IoTeX.Proto; option java_package = "wallet.core.jni.proto"; +// A transfer message Transfer { + // Amount (as string) string amount = 1; + + // Destination address string recipient = 2; + + // Payload data bytes payload = 3; } +// A Staking message message Staking { - // create stake - message Create { - string candidateName = 1; - string stakedAmount = 2; - uint32 stakedDuration = 3; - bool autoStake = 4; - bytes payload = 5; - } - - // unstake or withdraw - message Reclaim { - uint64 bucketIndex = 1; - bytes payload = 2; - } - - // add the amount of bucket - message AddDeposit { - uint64 bucketIndex = 1; - string amount = 2; - bytes payload = 3; - } - - // restake the duration and autoStake flag of bucket - message Restake { - uint64 bucketIndex = 1; - uint32 stakedDuration = 2; - bool autoStake = 3; - bytes payload = 4; - } - - // move the bucket to vote for another candidate or transfer the ownership of bucket to another voters - message ChangeCandidate { - uint64 bucketIndex = 1; - string candidateName = 2; - bytes payload = 3; - } - - message TransferOwnership { - uint64 bucketIndex = 1; - string voterAddress = 2; - bytes payload = 3; - } - - message CandidateBasicInfo { - string name = 1; - string operatorAddress = 2; - string rewardAddress = 3; - } - - message CandidateRegister { - CandidateBasicInfo candidate = 1; - string stakedAmount = 2; - uint32 stakedDuration = 3; - bool autoStake = 4; - string ownerAddress = 5; // if ownerAddress is absent, owner of candidate is the sender - bytes payload = 6; - } - oneof message { - Create stakeCreate = 1; - Reclaim stakeUnstake = 2; - Reclaim stakeWithdraw = 3; - AddDeposit stakeAddDeposit = 4; - Restake stakeRestake = 5; - ChangeCandidate stakeChangeCandidate = 6; - TransferOwnership stakeTransferOwnership = 7; - CandidateRegister candidateRegister = 8; - CandidateBasicInfo candidateUpdate = 9; - } + // create stake + message Create { + // validator name + string candidateName = 1; + + // amount to be staked + string stakedAmount = 2; + + // duration + uint32 stakedDuration = 3; + + // auto-restake + bool autoStake = 4; + + // payload data + bytes payload = 5; + } + + // unstake or withdraw + message Reclaim { + // index to claim + uint64 bucketIndex = 1; + + // payload data + bytes payload = 2; + } + + // add the amount of bucket + message AddDeposit { + // index + uint64 bucketIndex = 1; + + // amount to add + string amount = 2; + + // payload data + bytes payload = 3; + } + + // restake the duration and autoStake flag of bucket + message Restake { + // index + uint64 bucketIndex = 1; + + // stake duration + uint32 stakedDuration = 2; + + // auto re-stake + bool autoStake = 3; + + // payload data + bytes payload = 4; + } + + // move the bucket to vote for another candidate or transfer the ownership of bucket to another voters + message ChangeCandidate { + // index + uint64 bucketIndex = 1; + + // validator name + string candidateName = 2; + + // payload data + bytes payload = 3; + } + + // transfer ownserhip of stake + message TransferOwnership { + // index + uint64 bucketIndex = 1; + + // address of voter + string voterAddress = 2; + + // payload data + bytes payload = 3; + } + + // Candidate (validator) info + message CandidateBasicInfo { + string name = 1; + string operatorAddress = 2; + string rewardAddress = 3; + } + + // Register a Candidate + message CandidateRegister { + CandidateBasicInfo candidate = 1; + string stakedAmount = 2; + uint32 stakedDuration = 3; + bool autoStake = 4; + string ownerAddress = 5; // if ownerAddress is absent, owner of candidate is the sender + bytes payload = 6; + } + + // the payload message + oneof message { + Create stakeCreate = 1; + Reclaim stakeUnstake = 2; + Reclaim stakeWithdraw = 3; + AddDeposit stakeAddDeposit = 4; + Restake stakeRestake = 5; + ChangeCandidate stakeChangeCandidate = 6; + TransferOwnership stakeTransferOwnership = 7; + CandidateRegister candidateRegister = 8; + CandidateBasicInfo candidateUpdate = 9; + } } +// Arbitrary contract call message ContractCall { + // amount string amount = 1; + + // contract address string contract = 2; + + // payload data bytes data = 3; } -// transaction signing input +// Input data necessary to create a signed transaction. message SigningInput { + // Transaction version uint32 version = 1; + + // Nonce (should be larger than in the last transaction of the account) uint64 nonce = 2; + + // Limit for the gas used uint64 gasLimit = 3; + + // Gas price string gasPrice = 4; + + // The secret private key used for signing (32 bytes). bytes privateKey = 5; + + // Payload transfer oneof action { Transfer transfer = 10; ContractCall call = 12; @@ -106,10 +169,10 @@ message SigningInput { Staking.TransferOwnership stakeTransferOwnership = 46; Staking.CandidateRegister candidateRegister = 47; Staking.CandidateBasicInfo candidateUpdate = 48; - } + } } -// transaction signing output +// Result containing the signed and encoded transaction. message SigningOutput { // Signed and encoded Action bytes bytes encoded = 1; @@ -118,29 +181,47 @@ message SigningOutput { bytes hash = 2; } +// An Action structure +// Used internally message ActionCore { - uint32 version = 1; - uint64 nonce = 2; - uint64 gasLimit = 3; - string gasPrice = 4; - oneof action { - Transfer transfer = 10; - ContractCall execution = 12; - // Native staking - Staking.Create stakeCreate = 40; - Staking.Reclaim stakeUnstake = 41; - Staking.Reclaim stakeWithdraw = 42; - Staking.AddDeposit stakeAddDeposit = 43; - Staking.Restake stakeRestake = 44; - Staking.ChangeCandidate stakeChangeCandidate = 45; - Staking.TransferOwnership stakeTransferOwnership = 46; - Staking.CandidateRegister candidateRegister = 47; - Staking.CandidateBasicInfo candidateUpdate = 48; - } + // version number + uint32 version = 1; + + // Nonce (should be larger than in the last transaction of the account) + uint64 nonce = 2; + + // Gas limit + uint64 gasLimit = 3; + + // Gas price + string gasPrice = 4; + + // action payload + oneof action { + Transfer transfer = 10; + ContractCall execution = 12; + // Native staking + Staking.Create stakeCreate = 40; + Staking.Reclaim stakeUnstake = 41; + Staking.Reclaim stakeWithdraw = 42; + Staking.AddDeposit stakeAddDeposit = 43; + Staking.Restake stakeRestake = 44; + Staking.ChangeCandidate stakeChangeCandidate = 45; + Staking.TransferOwnership stakeTransferOwnership = 46; + Staking.CandidateRegister candidateRegister = 47; + Staking.CandidateBasicInfo candidateUpdate = 48; + } } +// Signed Action +// Used internally message Action { - ActionCore core = 1; - bytes senderPubKey = 2; - bytes signature = 3; -} \ No newline at end of file + // Action details + ActionCore core = 1; + + // public key + bytes senderPubKey = 2; + + // the signature + bytes signature = 3; +} diff --git a/src/proto/NEAR.proto b/src/proto/NEAR.proto index 6a2641a2a45..a55a9079f94 100644 --- a/src/proto/NEAR.proto +++ b/src/proto/NEAR.proto @@ -3,64 +3,97 @@ syntax = "proto3"; package TW.NEAR.Proto; option java_package = "wallet.core.jni.proto"; +// Public key with type message PublicKey { + // Key type uint32 key_type = 1; + + // The public key data bytes data = 2; } +// Permissions for a function call message FunctionCallPermission { - bytes allowance = 1; // uint128 / little endian byte order + // uint128 / little endian byte order + bytes allowance = 1; + string receiver_id = 2; + repeated string method_names = 3; } +// Full access message FullAccessPermission { } +// Access key: nonce + permission message AccessKey { + // Nonce uint64 nonce = 1; + + // Permission oneof permission { FunctionCallPermission function_call = 2; FullAccessPermission full_access = 3; } } +// Create Account message CreateAccount { } +// Deploying a contract message DeployContract { bytes code = 1; } +// A method/function call message FunctionCall { + // Method/function name string method_name = 1; + + // input arguments bytes args = 2; + + // gas uint64 gas = 3; - bytes deposit = 4; // uint128 / little endian byte order + + // uint128 / little endian byte order + bytes deposit = 4; } +// Transfer message Transfer { - bytes deposit = 1; // uint128 / little endian byte order + // amount; uint128 / little endian byte order + bytes deposit = 1; } +// Stake message Stake { - bytes stake = 1; // uint128 / little endian byte order + // amount; uint128 / little endian byte order + bytes stake = 1; + + // owner public key PublicKey public_key = 2; } +// Add a key message AddKey { PublicKey public_key = 1; AccessKey access_key = 2; } +// Delete a key message DeleteKey { PublicKey public_key = 1; } +// Delete account message DeleteAccount { string beneficiary_id = 1; } +// Represents an action message Action { oneof payload { CreateAccount create_account = 1; @@ -76,18 +109,30 @@ message Action { // Input data necessary to create a signed order. message SigningInput { + // ID of the sender string signer_id = 1; + + // Nonce (should be larger than in the last transaction of the account) uint64 nonce = 2; + + // ID of the receiver string receiver_id = 3; + + // Recent block hash bytes block_hash = 4; + + // Payload action(s) repeated Action actions = 5; + // The secret private key used for signing (32 bytes). bytes private_key = 6; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed transaction blob bytes signed_transaction = 1; + + // Hash of the transaction bytes hash = 2; } diff --git a/src/proto/NEO.proto b/src/proto/NEO.proto index 0093145f29f..096327cbc51 100644 --- a/src/proto/NEO.proto +++ b/src/proto/NEO.proto @@ -5,35 +5,61 @@ option java_package = "wallet.core.jni.proto"; import "Common.proto"; +// Input for a transaction (output of a prev tx) message TransactionInput { + // Previous tx hash bytes prev_hash = 1; + + // Output index fixed32 prev_index = 2; // unspent value of UTXO int64 value = 3; + // Asset string asset_id = 4; } +// Output of a transaction message TransactionOutput { + // Asset string asset_id = 1; + + // Amount (as string) sint64 amount = 2; + + // destination address string to_address = 3; + + // change address string change_address = 4; } // Input data necessary to create a signed transaction. message SigningInput { + // Available transaction inputs repeated TransactionInput inputs = 1; + + // Transaction outputs repeated TransactionOutput outputs = 2; + + // The secret private key used for signing (32 bytes). bytes private_key = 3; + + // Fee int64 fee = 4; + + // Asset ID for gas string gas_asset_id = 5; + + // Address for the change string gas_change_address = 6; + + // Optional transaction plan (if missing it will be computed) TransactionPlan plan = 7; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed and encoded transaction bytes. bytes encoded = 1; @@ -50,9 +76,16 @@ message TransactionOutputPlan { // Maximum available amount. int64 available_amount = 2; + // Amount that is left as change int64 change = 3; + + // Asset string asset_id = 4; + + // Destination address string to_address = 5; + + // Address for the change string change_address = 6; }; @@ -69,4 +102,4 @@ message TransactionPlan { // Optional error Common.Proto.SigningError error = 4; -}; \ No newline at end of file +}; diff --git a/src/proto/NULS.proto b/src/proto/NULS.proto index 2bcfd9d7a2e..51ed1806919 100644 --- a/src/proto/NULS.proto +++ b/src/proto/NULS.proto @@ -3,65 +3,122 @@ syntax = "proto3"; package TW.NULS.Proto; option java_package = "wallet.core.jni.proto"; +// Transaction from address message TransactionCoinFrom { + // Source address string from_address = 1; + + // Chain ID uint32 assets_chainid = 2; + + // ID of the asset uint32 assets_id = 3; - //tranaction out amount (256-bit number) + + // transaction out amount (256-bit number) bytes id_amount = 4; - //8 bytes + + // Nonce, 8 bytes bytes nonce = 5; - //lock status: 1 locked; 0 unlocked + + // lock status: 1 locked; 0 unlocked uint32 locked = 6; } +// Transaction to a destination message TransactionCoinTo { + // destination address string to_address = 1; + + // Chain ID uint32 assets_chainid = 2; + + // ID of the asset uint32 assets_id = 3; - // tranaction amount (256-bit number) + + // transaction amount (uint256, serialized little endian) bytes id_amount = 4; + + // lock time uint32 lock_time = 5; } +// A signature message Signature { + // Length of public key data uint32 pkey_len = 1; + + // The public key bytes public_key = 2; + + // The length of the signature uint32 sig_len = 3; + + // The signature data bytes signature = 4; } +// A transaction message Transaction { + // transaction type uint32 type = 1; + + // Timestamp of the transaction uint32 timestamp = 2; + + // Optional string remark string remark = 3; + + // The raw data bytes tx_data = 4; - //CoinFrom + + // CoinFrom TransactionCoinFrom input = 5; - //CoinTo + + // CoinTo TransactionCoinTo output = 6; + // Signature Signature tx_sigs = 7; + + // Tx hash uint32 hash = 8; } // Input data necessary to create a signed order. message SigningInput { + // The secret private key used for signing (32 bytes). bytes private_key = 1; + + // Source address string from = 2; + + // Destination address string to = 3; + + // Transfer amount (uint256, serialized little endian) bytes amount = 4; + + // Chain ID uint32 chain_id = 5; + + // Asset ID uint32 idassets_id = 6; - //The last 8 bytes of latest transaction hash + + // The last 8 bytes of latest transaction hash bytes nonce = 7; + + // Optional memo remark string remark = 8; + // Account balance bytes balance = 9; + // time, accurate to the second uint32 timestamp = 10; } +// Result containing the signed and encoded transaction. message SigningOutput { + // Encoded transaction bytes encoded = 1; -} \ No newline at end of file +} diff --git a/src/proto/Nano.proto b/src/proto/Nano.proto index 954c7930e28..9bd7a7a26bd 100644 --- a/src/proto/Nano.proto +++ b/src/proto/Nano.proto @@ -5,12 +5,13 @@ option java_package = "wallet.core.jni.proto"; // Input data necessary to create a signed transaction. message SigningInput { - // Private key + // The secret private key used for signing (32 bytes). bytes private_key = 1; // Optional parent block hash bytes parent_block = 2; + // Receive/Send reference oneof link_oneof { // Hash of a block to receive from bytes link_block = 3; @@ -28,12 +29,14 @@ message SigningInput { string work = 7; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signature bytes signature = 1; + // Block hash bytes block_hash = 2; - // Json representation of the block + + // JSON representation of the block string json = 3; } diff --git a/src/proto/Nebulas.proto b/src/proto/Nebulas.proto index fc8e7e9acf9..ea915410d59 100644 --- a/src/proto/Nebulas.proto +++ b/src/proto/Nebulas.proto @@ -8,42 +8,47 @@ message SigningInput { // sender's address. string from_address = 1; - // Chain identifier (256-bit number) + // Chain identifier (uint256, serialized little endian) bytes chain_id = 2; - // Nonce (256-bit number) + // Nonce (uint256, serialized little endian) bytes nonce = 3; - // Gas price (256-bit number) + // Gas price (uint256, serialized little endian) bytes gas_price = 4; - // Gas limit (256-bit number) + // Gas limit (uint256, serialized little endian) bytes gas_limit = 5; // Recipient's address. string to_address = 6; - // Amount to send in wei, 1 NAS = 10^18 Wei (256-bit number) + // Amount to send in wei, 1 NAS = 10^18 Wei (uint256, serialized little endian) bytes amount = 7; - // Timestamp to create transaction (256-bit number) + // Timestamp to create transaction (uint256, serialized little endian) bytes timestamp = 8; // Optional payload string payload = 9; - // Private key. + // The secret private key used for signing (32 bytes). bytes private_key = 10; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { + // Algorithm code uint32 algorithm = 1; + + // The signature bytes signature = 2; + + // Encoded transaction string raw = 3; } -// +// Generic data message Data { string type = 1; bytes payload = 2; @@ -51,17 +56,39 @@ message Data { // Raw transaction data message RawTransaction { + // tx hash bytes hash = 1; + + // source address bytes from = 2; + + // destination address bytes to = 3; + + // amount (uint256, serialized little endian) bytes value = 4; + + // Nonce (should be larger than in the last transaction of the account) uint64 nonce = 5; + + // transaction timestamp int64 timestamp = 6; + + // generic data Data data = 7; + + // chain ID (4 bytes) uint32 chain_id = 8; + + // gas price (uint256, serialized little endian) bytes gas_price = 9; + + // gas limit (uint256, serialized little endian) bytes gas_limit = 10; + // algorithm uint32 alg = 11; + + // signature bytes sign = 12; -} \ No newline at end of file +} diff --git a/src/proto/Nervos.proto b/src/proto/Nervos.proto index fd7c92afc6f..07cc53060d0 100644 --- a/src/proto/Nervos.proto +++ b/src/proto/Nervos.proto @@ -22,7 +22,7 @@ message TransactionPlan { // A list of 1 or more selected cells for this transaction repeated Cell selected_cells = 3; - // A list of 1 or more outputs by this transaciton + // A list of 1 or more outputs by this transaction repeated CellOutput outputs = 4; // A list of outputs data. @@ -74,6 +74,7 @@ message Script { bytes args = 3; } +// Transfer of native asset message NativeTransfer { // Recipient's address. string to_address = 1; @@ -88,6 +89,7 @@ message NativeTransfer { bool use_max_amount = 4; } +// Token transfer (SUDT) message SudtTransfer { // Recipient's address. string to_address = 1; @@ -105,6 +107,7 @@ message SudtTransfer { bool use_max_amount = 5; } +// Deposit message DaoDeposit { // Recipient's address. string to_address = 1; @@ -140,7 +143,7 @@ message SigningInput { // Transaction fee per byte. uint64 byte_fee = 1; - // Available private keys. + // The available secret private keys used for signing (32 bytes each). repeated bytes private_key = 2; // Available unspent cell outputs. @@ -149,6 +152,7 @@ message SigningInput { // Optional transaction plan TransactionPlan plan = 4; + // The payload transfer oneof operation_oneof { NativeTransfer native_transfer = 5; SudtTransfer sudt_transfer = 6; @@ -191,7 +195,7 @@ message Cell { bytes output_type = 10; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Resulting transaction. Note that the amount may be different than the requested amount to account for fees and available funds. string transaction_json = 1; diff --git a/src/proto/Nimiq.proto b/src/proto/Nimiq.proto index 6c96981278d..76d00dd903e 100644 --- a/src/proto/Nimiq.proto +++ b/src/proto/Nimiq.proto @@ -5,18 +5,24 @@ option java_package = "wallet.core.jni.proto"; // Input data necessary to create a signed transaction. message SigningInput { + // The secret private key used for signing (32 bytes). bytes private_key = 1; + // Destination address string destination = 2; + // Amount of the transfer uint64 value = 3; + // Fee amount uint64 fee = 4; + // Validity start, in block height uint32 validity_start_height = 5; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { + // The encoded transaction bytes encoded = 1; } diff --git a/src/proto/Oasis.proto b/src/proto/Oasis.proto index 6b327044b58..316f6e295df 100644 --- a/src/proto/Oasis.proto +++ b/src/proto/Oasis.proto @@ -9,28 +9,39 @@ syntax = "proto3"; package TW.Oasis.Proto; option java_package = "wallet.core.jni.proto"; +// Transfer message TransferMessage { + // destination address string to = 1; + + // Gas price uint64 gas_price = 2; // Amount values strings prefixed by zero. e.g. "\u000010000000" string gas_amount = 3; + // Amount values strings prefixed by zero string amount = 4; + // Nonce (should be larger than in the last transaction of the account) uint64 nonce = 5; + + // Context, see https://docs.oasis.dev/oasis-core/common-functionality/crypto#domain-separation string context = 6; } +// Input data necessary to create a signed transaction. message SigningInput { + // The secret private key used for signing (32 bytes). bytes private_key = 1; + // Transfer payload oneof message { TransferMessage transfer = 2; } } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed and encoded transaction bytes. bytes encoded = 1; diff --git a/src/proto/Ontology.proto b/src/proto/Ontology.proto index 28992aacfcf..9496537dd18 100644 --- a/src/proto/Ontology.proto +++ b/src/proto/Ontology.proto @@ -5,32 +5,39 @@ option java_package = "wallet.core.jni.proto"; // Input data necessary to create a signed transaction. message SigningInput { - + // Contract ID, e.g. "ONT" string contract = 1; + // Method, e.g. "transfer" string method = 2; + // The secret private key used for signing (32 bytes). bytes owner_private_key = 3; // base58 encode address string (160-bit number) string to_address = 4; + // Transfer amount uint64 amount = 5; + // Private key of the payer bytes payer_private_key = 6; + // Gas price uint64 gas_price = 7; + // Limit for gas used uint64 gas_limit = 8; // base58 encode address string (160-bit number) string query_address = 9; + // Nonce (should be larger than in the last transaction of the account) uint32 nonce = 10; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed and encoded transaction bytes. bytes encoded = 1; diff --git a/src/proto/Polkadot.proto b/src/proto/Polkadot.proto index d46afa39725..178a26485de 100644 --- a/src/proto/Polkadot.proto +++ b/src/proto/Polkadot.proto @@ -3,17 +3,20 @@ syntax = "proto3"; package TW.Polkadot.Proto; option java_package = "wallet.core.jni.proto"; +// Known networks enum Network { POLKADOT = 0; KUSAMA = 2; } +// Destination options for reward enum RewardDestination { STAKED = 0; STASH = 1; CONTROLLER = 2; } +// An era, a period defined by a starting block and length message Era { // recent block number (called phase in polkadot code), should match block hash uint64 block_number = 1; @@ -22,52 +25,84 @@ message Era { uint64 period = 2; } +// Balance transfer transaction message Balance { + // transfer message Transfer { + // destination address string to_address = 1; - bytes value = 2; // big integer + + // amount (uint256, serialized little endian) + bytes value = 2; } oneof message_oneof { Transfer transfer = 1; } } +// Staking transaction message Staking { + // Bond to a controller message Bond { + // controller ID string controller = 1; + + // amount (uint256, serialized little endian) bytes value = 2; + + // destination for rewards RewardDestination reward_destination = 3; } + // Bond to a controller, with nominators message BondAndNominate { + // controller ID string controller = 1; + + // amount (uint256, serialized little endian) bytes value = 2; + + // destination for rewards RewardDestination reward_destination = 3; + + // list of nominators repeated string nominators = 4; } + // Bond extra amount message BondExtra { + // amount (uint256, serialized little endian) bytes value = 1; } + // Unbond message Unbond { + // amount (uint256, serialized little endian) bytes value = 1; } + // Withdraw unbonded amounts message WithdrawUnbonded { int32 slashing_spans = 1; } + // Nominate message Nominate { + // list of nominators repeated string nominators = 1; } + // Chill and unbound message ChillAndUnbond { + // amount (uint256, serialized little endian) bytes value = 1; } - message Chill {} + // Chill + message Chill { + } + // Payload messsage oneof message_oneof { Bond bond = 1; BondAndNominate bond_and_nominate = 2; @@ -85,28 +120,38 @@ message SigningInput { // Recent block hash, or genesis hash if era is not set bytes block_hash = 1; + // Genesis block hash (identifies the chain) bytes genesis_hash = 2; // Current account nonce uint64 nonce = 3; + // Specification version, e.g. 26. uint32 spec_version = 4; + + // Transaction version, e.g. 5. uint32 transaction_version = 5; - bytes tip = 6; // big integer + + // Optional tip to pay, big integer + bytes tip = 6; // Optional time validity limit, recommended, for replay-protection. Empty means Immortal. Era era = 7; + // The secret private key used for signing (32 bytes). bytes private_key = 8; + + // Network type Network network = 9; + // Payload message oneof message_oneof { Balance balance_call = 10; Staking staking_call = 11; } } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed and encoded transaction bytes. bytes encoded = 1; diff --git a/src/proto/Ripple.proto b/src/proto/Ripple.proto index 82f7ebd39a4..ffbb863741c 100644 --- a/src/proto/Ripple.proto +++ b/src/proto/Ripple.proto @@ -7,27 +7,37 @@ import "Common.proto"; // Input data necessary to create a signed transaction. message SigningInput { + // Transfer amount int64 amount = 1; + // Transfer fee int64 fee = 2; + // Account sequence number int32 sequence = 3; + // Ledger sequence number int32 last_ledger_sequence = 4; + // Source account string account = 5; + // Target account string destination = 6; + // A Destination Tag int64 destination_tag = 7; + // Transaction flags, optional int64 flags = 8; + // The secret private key used for signing (32 bytes). bytes private_key = 9; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { + // Encoded transaction bytes encoded = 1; // Optional error diff --git a/src/proto/Solana.proto b/src/proto/Solana.proto index 45ac259f631..0f7280b5da3 100644 --- a/src/proto/Solana.proto +++ b/src/proto/Solana.proto @@ -3,41 +3,62 @@ syntax = "proto3"; package TW.Solana.Proto; option java_package = "wallet.core.jni.proto"; +// Transfer transaction message Transfer { + // destination address string recipient = 1; + + // amount uint64 value = 2; - string memo = 3; // optional - repeated string references = 4; // optional referenced public keys + + // optional memo + string memo = 3; + + // optional referenced public keys + repeated string references = 4; } // Create and initialize a stake account, and delegate amount to it. // Recommendation behavior is to not specify a stake account, and a new unique account will be created each time. // Optionally a stake account pubkey can be specified, but it should not exist on chain. message DelegateStake { + // Validator's public key string validator_pubkey = 1; + + // delegation amount uint64 value = 2; + + // staking account string stake_account = 3; } // Deactivate staking on stake account message DeactivateStake { + // staking account string stake_account = 1; } // Deactivate staking on multiple stake account message DeactivateAllStake { + // staking accounts repeated string stake_accounts = 1; } // Withdraw amount from stake account message WithdrawStake { + // staking account string stake_account = 1; + + // withdrawal amount uint64 value = 2; } -// Techinical structure to group a staking account and an amount +// Technical structure to group a staking account and an amount message StakeAccountValue { + // staking account string stake_account = 1; + + // amount uint64 value = 2; } @@ -50,39 +71,74 @@ message WithdrawAllStake { message CreateTokenAccount { // main account -- can be same as signer, or other main account (if done on some other account's behalf) string main_address = 1; + + // Token minting address string token_mint_address = 2; + + // Token address string token_address = 3; } // Transfer tokens message TokenTransfer { + // Mint address of the token string token_mint_address = 1; + + // Source address string sender_token_address = 2; + + // Destination address string recipient_token_address = 3; + + // Amount uint64 amount = 4; - uint32 decimals = 5; // Note: 8-bit value - string memo = 6; // optional - repeated string references = 7; // optional referenced public keys + + // Note: 8-bit value + uint32 decimals = 5; + + // optional memo§ + string memo = 6; + + // optional referenced public keys + repeated string references = 7; } // CreateTokenAccount and TokenTransfer combined message CreateAndTransferToken { // main account -- can be same as signer, or other main account (if done on some other account's behalf) string recipient_main_address = 1; + + // Mint address of the token string token_mint_address = 2; + // Token address for the recipient, will be created first string recipient_token_address = 3; + + // Sender's token address string sender_token_address = 4; + + // amount uint64 amount = 5; - uint32 decimals = 6; // Note: 8-bit value - string memo = 7; // optional - repeated string references = 8; // optional referenced public keys + + // Note: 8-bit value + uint32 decimals = 6; + + // optional + string memo = 7; + + // optional referenced public keys + repeated string references = 8; } // Input data necessary to create a signed transaction. message SigningInput { + // The secret private key used for signing (32 bytes). bytes private_key = 1; + + // Relatively recent block hash string recent_blockhash = 2; + + // Payload message oneof transaction_type { Transfer transfer_transaction = 3; DelegateStake delegate_stake_transaction = 4; @@ -96,7 +152,8 @@ message SigningInput { } } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { + // The encoded transaction string encoded = 1; } diff --git a/src/proto/Stellar.proto b/src/proto/Stellar.proto index 0849f07097f..44a67e3672f 100644 --- a/src/proto/Stellar.proto +++ b/src/proto/Stellar.proto @@ -3,24 +3,28 @@ syntax = "proto3"; package TW.Stellar.Proto; option java_package = "wallet.core.jni.proto"; +// Represents an asset +// Note: alphanum12 currently not supported message Asset { // Optional in case of non-native asset; the asset issuer address string issuer = 1; // Optional in case of non-native asset; the asset alphanum4 code. string alphanum4 = 2; - - // Note: alphanum12 currently not supported } +// Create a new account message OperationCreateAccount { + // address string destination = 1; // Amount (*10^7) int64 amount = 2; } +// Perform payment message OperationPayment { + // Destination address string destination = 1; // Optional, can be left empty for native asset @@ -30,24 +34,32 @@ message OperationPayment { int64 amount = 3; } +// Change trust message OperationChangeTrust { + // The asset Asset asset = 1; // Validity (time bound to), unix time. Set to (now() + 2 * 365 * 86400) for 2 years; set to 0 for missing. int64 valid_before = 2; } +// A predicate (used in claim) +// Rest of predicates not currently supported +// See https://github.com/stellar/stellar-protocol/blob/master/core/cap-0023.md enum ClaimPredicate { Predicate_unconditional = 0; - // Rest of predicates not currently supported - // See https://github.com/stellar/stellar-protocol/blob/master/core/cap-0023.md } +// Claimant: account & predicate message Claimant { + // Claimant account string account = 1; + + // predicate ClaimPredicate predicate = 2; } +// Create a claimable balance (2-phase transfer) message OperationCreateClaimableBalance { // Optional, can be left empty for native asset Asset asset = 1; @@ -55,42 +67,53 @@ message OperationCreateClaimableBalance { // Amount (*10^7) int64 amount = 2; + // One or more claimants repeated Claimant claimants = 3; } +// Claim a claimable balance message OperationClaimClaimableBalance { // 32-byte balance ID hash bytes balance_id = 1; } +// Empty memo (placeholder) message MemoVoid { } +// Memo with text message MemoText { string text = 1; } +// Memo with an ID message MemoId { int64 id = 1; } +// Memo with a hash message MemoHash { bytes hash = 1; } // Input data necessary to create a signed transaction. message SigningInput { + // Transaction fee int32 fee = 1; + // Account sequence int64 sequence = 2; + // Source account string account = 3; - // Private key. + // The secret private key used for signing (32 bytes). bytes private_key = 4; + // Wellknown passphrase, specific to the chain string passphrase = 5; + // Payload message oneof operation_oneof { OperationCreateAccount op_create_account = 6; OperationPayment op_payment = 7; @@ -99,6 +122,7 @@ message SigningInput { OperationClaimClaimableBalance op_claim_claimable_balance = 15; } + // Memo oneof memo_type_oneof { MemoVoid memo_void = 9; MemoText memo_text = 10; @@ -108,7 +132,7 @@ message SigningInput { } } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signature. string signature = 1; diff --git a/src/proto/THORChainSwap.proto b/src/proto/THORChainSwap.proto index a5c943b4a65..7f3a20396c0 100644 --- a/src/proto/THORChainSwap.proto +++ b/src/proto/THORChainSwap.proto @@ -17,7 +17,8 @@ enum Chain { // Predefined error codes enum ErrorCode { - OK = 0; // OK + // OK + OK = 0; Error_general = 1; Error_Input_proto_deserialization = 2; Error_Unsupported_from_chain = 13; @@ -30,14 +31,22 @@ enum ErrorCode { // An error code + a free text message Error { + // code of the error ErrorCode code = 1; + + // optional error message string message = 2; } // Represents an asset. Examples: BNB.BNB, RUNE.RUNE, BNB.RUNE-67C message Asset { + // Chain ID Chain chain = 1; + + // Symbol string symbol = 2; + + // The ID of the token (blockchain-specific format) string token_id = 3; } @@ -68,11 +77,15 @@ message SwapInput { string to_amount_limit = 8; } +// Result of the swap, a SigningInput struct for the specific chain message SwapOutput { + // Source chain Chain from_chain = 1; + + // Destination chain Chain to_chain = 2; - // Error code, filled in case of error, OK&"" on success + // Error code, filled in case of error, OK/empty on success Error error = 3; // Prepared unsigned transaction input, on the source chain, to THOR. Some fields must be completed, and it has to be signed. diff --git a/src/proto/Tezos.proto b/src/proto/Tezos.proto index f5d9240e1e7..7a56c4d2ab5 100644 --- a/src/proto/Tezos.proto +++ b/src/proto/Tezos.proto @@ -6,32 +6,49 @@ option java_package = "wallet.core.jni.proto"; // Input data necessary to create a signed Tezos transaction. // Next field: 3 message SigningInput { + // One or more operations OperationList operation_list = 1; + + // The secret private key used for signing (32 bytes). bytes private_key = 2; } -// Transaction signing output. +// Result containing the signed and encoded transaction. // Next field: 2 message SigningOutput { + // The encoded transaction bytes encoded = 1; } // A list of operations and a branch. // Next field: 3 message OperationList { + // branch string branch = 1; + + // list of operations repeated Operation operations = 2; } // An operation that can be applied to the Tezos blockchain. // Next field: 12 message Operation { + // counter int64 counter = 1; + + // source account string source = 2; + + // fee int64 fee = 3; + + // gas limit int64 gas_limit = 4; + + // storage limit int64 storage_limit = 5; + // Operation types enum OperationKind { // Note: Proto3 semantics require a zero value. ENDORSEMENT = 0; @@ -40,6 +57,7 @@ message Operation { TRANSACTION = 108; DELEGATION = 110; } + // Operation type OperationKind kind = 7; // Operation specific data depending on the type of the operation. @@ -73,6 +91,7 @@ message FA2Parameters { repeated TxObject txs_object = 2; } +// Generic operation parameters message OperationParameters { oneof parameters { FA12Parameters fa12_parameters = 1; diff --git a/src/proto/Theta.proto b/src/proto/Theta.proto index f779c0b5b0d..4647d89ba83 100644 --- a/src/proto/Theta.proto +++ b/src/proto/Theta.proto @@ -11,23 +11,23 @@ message SigningInput { /// Recipient address string to_address = 2; - /// Theta token amount to send in wei (256-bit number) + /// Theta token amount to send in wei (uint256, serialized little endian) bytes theta_amount = 3; - /// TFuel token amount to send in wei (256-bit number) + /// TFuel token amount to send in wei (uint256, serialized little endian) bytes tfuel_amount = 4; /// Sequence number of the transaction for the sender address uint64 sequence = 5; - /// Fee amount in TFuel wei for the transaction (256-bit number) + /// Fee amount in TFuel wei for the transaction (uint256, serialized little endian) bytes fee = 6; - /// Private key + /// The secret private key used for signing (32 bytes). bytes private_key = 7; } -/// Transaction signing output +// Result containing the signed and encoded transaction. message SigningOutput { /// Signed and encoded transaction bytes bytes encoded = 1; diff --git a/src/proto/Tron.proto b/src/proto/Tron.proto index 3a6b635b169..7ed7ce37723 100644 --- a/src/proto/Tron.proto +++ b/src/proto/Tron.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package TW.Tron.Proto; option java_package = "wallet.core.jni.proto"; +// A transfer transaction message TransferContract { // Sender address. string owner_address = 1; @@ -14,6 +15,7 @@ message TransferContract { int64 amount = 3; } +// Asset transfer message TransferAssetContract { // Asset name. string asset_name = 1; @@ -28,6 +30,7 @@ message TransferAssetContract { int64 amount = 4; } +// TRC20 token transfer message TransferTRC20Contract { // Contract name. string contract_address = 1; @@ -38,79 +41,125 @@ message TransferTRC20Contract { // Recipient address. string to_address = 3; - // Amount to send, uint256, big-endian. + // Amount to send, (uint256, serialized big endian) bytes amount = 4; } +// Freeze balance message FreezeBalanceContract { // Sender address. string owner_address = 1; + // Frozen balance. Minimum 1 int64 frozen_balance = 2; + // Frozen duration int64 frozen_duration = 3; + // Resource type: BANDWIDTH | ENERGY string resource = 10; + // Receiver address string receiver_address = 15; } +// Unfreeze balance message UnfreezeBalanceContract { // Sender address string owner_address = 1; + // Resource type: BANDWIDTH | ENERGY string resource = 10; + // Receiver address string receiver_address = 15; } +// Unfreeze asset message UnfreezeAssetContract { // Sender address string owner_address = 1; } +// Vote asset message VoteAssetContract { // Sender address string owner_address = 1; + // Vote addresses repeated string vote_address = 2; + bool support = 3; + int32 count = 5; } +// Vote witness message VoteWitnessContract { + // A vote message Vote { + // address string vote_address = 1; + + // vote count int64 vote_count = 2; } + + // Owner string owner_address = 1; + + // The votes repeated Vote votes = 2; + bool support = 3; } +// Withdraw balance message WithdrawBalanceContract { // Sender address string owner_address = 1; } +// Smart contract call message TriggerSmartContract { + // Owner string owner_address = 1; + + // Contract address string contract_address = 2; + + // amount int64 call_value = 3; + + // call data bytes data = 4; + + // token value int64 call_token_value = 5; + + // ID of the token int64 token_id = 6; } +// Info from block header message BlockHeader { + // creation timestamp int64 timestamp = 1; + + // root bytes tx_trie_root = 2; + + // hash of the parent bytes parent_hash = 3; + int64 number = 7; + bytes witness_address = 9; + int32 version = 10; } +// Transaction message Transaction { // Transaction timestamp in milliseconds. int64 timestamp = 1; @@ -139,15 +188,16 @@ message Transaction { } } +// Input data necessary to create a signed transaction. message SigningInput { // Transaction. Transaction transaction = 1; - // Private key. + // The secret private key used for signing (32 bytes). bytes private_key = 2; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Transaction identifier. bytes id = 1; @@ -158,5 +208,6 @@ message SigningOutput { bytes ref_block_bytes = 3; bytes ref_block_hash = 4; + // Result in JSON string json = 5; } diff --git a/src/proto/VeChain.proto b/src/proto/VeChain.proto index c89d9f0bfc5..2b2b7e151c2 100644 --- a/src/proto/VeChain.proto +++ b/src/proto/VeChain.proto @@ -3,11 +3,12 @@ syntax = "proto3"; package TW.VeChain.Proto; option java_package = "wallet.core.jni.proto"; +// A clause, between a sender and destination message Clause { /// Recipient address. string to = 1; - /// Transaction amount. + /// Transaction amount (uint256, serialized little endian) bytes value = 2; /// Payload data. @@ -43,11 +44,11 @@ message SigningInput { /// Number set by user. uint64 nonce = 8; - // Private key. + /// The secret private key used for signing (32 bytes). bytes private_key = 9; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed and encoded transaction bytes. bytes encoded = 1; diff --git a/src/proto/Waves.proto b/src/proto/Waves.proto index 011fcf1138b..a2acc2ef599 100644 --- a/src/proto/Waves.proto +++ b/src/proto/Waves.proto @@ -3,29 +3,45 @@ syntax = "proto3"; package TW.Waves.Proto; option java_package = "wallet.core.jni.proto"; -//Transfer transaction +// Transfer transaction message TransferMessage { + // amount int64 amount = 1; + + // asset ID string asset = 2; + // minimum 0.001 Waves (100000 Wavelets) for now int64 fee = 3; + + // asset of the fee string fee_asset = 4; + + // destination address string to = 5; + // any 140 bytes payload, will be displayed to the client as utf-8 string bytes attachment = 6; } -//Lease transaction +// Lease transaction message LeaseMessage { + // amount int64 amount = 1; + + // destination string to = 2; + // minimum 0.001 Waves (100000 Wavelets) for now int64 fee = 3; } -//Lease transaction +// Cancel Lease transaction message CancelLeaseMessage { + // Lease ID to cancel string lease_id = 1; + + // Fee used int64 fee = 2; } @@ -34,7 +50,11 @@ message CancelLeaseMessage { message SigningInput { // in millis int64 timestamp = 1; + + // The secret private key used for signing (32 bytes). bytes private_key = 2; + + // Payload message oneof message_oneof { TransferMessage transfer_message = 3; LeaseMessage lease_message = 4; @@ -42,9 +62,12 @@ message SigningInput { } } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { + // signature data bytes signature = 1; + + // transaction in JSON format string json = 2; } diff --git a/src/proto/Zilliqa.proto b/src/proto/Zilliqa.proto index ea5d3eff4c9..03e5e2167fa 100644 --- a/src/proto/Zilliqa.proto +++ b/src/proto/Zilliqa.proto @@ -3,14 +3,17 @@ syntax = "proto3"; package TW.Zilliqa.Proto; option java_package = "wallet.core.jni.proto"; +// Generic transaction message Transaction { + // Transfer transaction message Transfer { - // Amount to send (256-bit number) + // Amount to send (uint256, serialized little endian) bytes amount = 1; } + // Generic contract call message Raw { - // Amount to send (256-bit number) + // Amount to send (uint256, serialized little endian) bytes amount = 1; // Smart contract code @@ -43,13 +46,14 @@ message SigningInput { // GasLimit uint64 gas_limit = 5; - // Private Key + // The secret private key used for signing (32 bytes). bytes private_key = 6; + // The payload transaction Transaction transaction = 7; } -// Transaction signing output. +// Result containing the signed and encoded transaction. message SigningOutput { // Signed signature bytes. bytes signature = 1; diff --git a/tests/FIO/TWFIOTests.cpp b/tests/FIO/TWFIOTests.cpp index acbdf2e889a..4460eff762a 100644 --- a/tests/FIO/TWFIOTests.cpp +++ b/tests/FIO/TWFIOTests.cpp @@ -146,7 +146,7 @@ TEST(TWFIO, NewFundsRequest) { Proto::SigningOutput output; ANY_SIGN(input, TWCoinTypeFIO); - // Packed transacton varies, as there is no way to control encryption IV parameter from this level. + // Packed transaction varies, as there is no way to control encryption IV parameter from this level. // Therefore full equality cannot be checked, tail is cut off. The first N chars are checked, works in this case. EXPECT_EQ( R"({"compression":"none","packed_context_free_data":"","packed_trx":"289b295ec99b904215ff000000000100403ed4aa0ba85b00acba384dbdb89a01102b2f46fca756b200000000a8ed32328802106d6172696f4066696f746573746)", diff --git a/tools/doxygen_convert_comments b/tools/doxygen_convert_comments index 3c76e250487..91870ffb466 100755 --- a/tools/doxygen_convert_comments +++ b/tools/doxygen_convert_comments @@ -16,7 +16,7 @@ function process_swift_comments() { function swift_convert() { - echo "Processing swift convertion" + echo "Processing swift conversion" for d in $SWIFT_FOLDER_PATH ; do process_swift_comments $d From 0fdab0adfebfb85b737cd909b87fe7137455d16e Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Mon, 3 Oct 2022 15:32:59 +0100 Subject: [PATCH 100/497] Add zkSync v2 evm (#2605) * Add zkSync v2 evm --- .../blockchains/CoinAddressDerivationTests.kt | 2 +- docs/registry.md | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 30 ++++++++++++++++ swift/Tests/CoinAddressDerivationTests.swift | 1 + tests/CoinAddressDerivationTests.cpp | 1 + tests/ZkSyncV2/TWCoinTypeTests.cpp | 36 +++++++++++++++++++ 7 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 tests/ZkSyncV2/TWCoinTypeTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 34765728c77..98f69f55d1b 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -40,7 +40,7 @@ class CoinAddressDerivationTests { CALLISTO -> assertEquals("0x3E6FFC80745E6669135a76F4A7ce6BCF02436e04", address) DASH -> assertEquals("XqHiz8EXYbTAtBEYs4pWTHh7ipEDQcNQeT", address) DIGIBYTE -> assertEquals("dgb1qtjgmerfqwdffyf8ghcrkgy52cghsqptynmyswu", address) - ETHEREUM, SMARTCHAIN, POLYGON, OPTIMISM, ARBITRUM, ECOCHAIN, AVALANCHECCHAIN, XDAI, + ETHEREUM, SMARTCHAIN, POLYGON, OPTIMISM, ZKSYNC, ARBITRUM, ECOCHAIN, AVALANCHECCHAIN, XDAI, FANTOM, CELO, CRONOSCHAIN, SMARTBITCOINCASH, KUCOINCOMMUNITYCHAIN, BOBA, METIS, AURORA, EVMOS, MOONRIVER, MOONBEAM, KAVAEVM, KLAYTN, METER, OKXCHAIN -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address) RONIN -> assertEquals("ronin:8f348F300873Fd5DA36950B2aC75a26584584feE", address) diff --git a/docs/registry.md b/docs/registry.md index 2bc175c03ad..5d89f556a91 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -80,6 +80,7 @@ This list is generated from [./registry.json](../registry.json) | 10000118 | Osmosis | OSMO | | | | 10000145 | Smart Bitcoin Cash | BCH | | | | 10000250 | Fantom | FTM | | | +| 10000280 | zkSync v2 | ETH | | | | 10000288 | Boba | BOBAETH | | | | 10000321 | KuCoin Community Chain | KCS | | | | 10000330 | Terra | LUNA | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 831f9c3124a..52e5f2d50f5 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -90,6 +90,7 @@ enum TWCoinType { TWCoinTypeTHORChain = 931, TWCoinTypeBluzelle = 483, TWCoinTypeOptimism = 10000070, + TWCoinTypeZksync = 10000280, TWCoinTypeArbitrum = 10042221, TWCoinTypeECOChain = 10000553, TWCoinTypeAvalancheCChain = 10009000, diff --git a/registry.json b/registry.json index 2c8dcb73ebe..a2e07e2c29b 100644 --- a/registry.json +++ b/registry.json @@ -2061,6 +2061,36 @@ "documentation": "https://eth.wiki/json-rpc/API" } }, + { + "id": "zksync", + "name": "Zksync", + "displayName": "zkSync v2", + "coinId": 10000280, + "slip44": 60, + "symbol": "ETH", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "280", + "addressHasher": "keccak256", + "explorer": { + "url": "https://zksync2-testnet.zkscan.io", + "txPath": "/tx/", + "accountPath": "/address/" + }, + "info": { + "url": "https://portal.zksync.io/", + "source": "https://github.com/matter-labs/zksync", + "rpc": "https://zksync2-testnet.zksync.dev", + "documentation": "https://v2-docs.zksync.io" + } + }, { "id": "arbitrum", "name": "Arbitrum", diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 789a9a6627d..5dd2b6d4ef4 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -74,6 +74,7 @@ class CoinAddressDerivationTests: XCTestCase { .smartChain, .polygon, .optimism, + .zksync, .arbitrum, .ecochain, .avalancheCChain, diff --git a/tests/CoinAddressDerivationTests.cpp b/tests/CoinAddressDerivationTests.cpp index 6d04e729eba..5bd9acd5d63 100644 --- a/tests/CoinAddressDerivationTests.cpp +++ b/tests/CoinAddressDerivationTests.cpp @@ -57,6 +57,7 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeMoonbeam: case TWCoinTypeMoonriver: case TWCoinTypeOptimism: + case TWCoinTypeZksync: case TWCoinTypeOKXChain: case TWCoinTypePOANetwork: case TWCoinTypePolygon: diff --git a/tests/ZkSyncV2/TWCoinTypeTests.cpp b/tests/ZkSyncV2/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..9b00c8112a6 --- /dev/null +++ b/tests/ZkSyncV2/TWCoinTypeTests.cpp @@ -0,0 +1,36 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "../interface/TWTestUtilities.h" +#include +#include + +namespace TW::TWZksync::tests { + +TEST(TWZksyncCoinType, TWCoinType) { + const auto coin = TWCoinTypeZksync; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto chainId = WRAPS(TWCoinTypeChainId(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("0xb526861291c0335435e3c976e672a464b70762e54d7167409fb4f66e374ed708")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0x970978989a51790ee591b2a54f92c7cd9cdc2f88")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "zksync"); + assertStringsEqual(name, "zkSync v2"); + assertStringsEqual(symbol, "ETH"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 18); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainEthereum); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); + assertStringsEqual(chainId, "280"); + assertStringsEqual(txUrl, "https://zksync2-testnet.zkscan.io/tx/0xb526861291c0335435e3c976e672a464b70762e54d7167409fb4f66e374ed708"); + assertStringsEqual(accUrl, "https://zksync2-testnet.zkscan.io/address/0x970978989a51790ee591b2a54f92c7cd9cdc2f88"); +} + +} // namespace TW::TWZksync::tests From 61157af882b24b74310f72745fd2598568a965ba Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Tue, 4 Oct 2022 14:10:07 +0100 Subject: [PATCH 101/497] fix(codegen): correct swift template for _Nullable string parameter handling (#2609) --- codegen/lib/templates/swift/parameter_access.erb | 8 +++++--- include/TrustWalletCore/TWBase32.h | 12 ++++++------ src/interface/TWBase32.cpp | 14 ++++++-------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/codegen/lib/templates/swift/parameter_access.erb b/codegen/lib/templates/swift/parameter_access.erb index 8521c18bb4a..ddf4335753f 100644 --- a/codegen/lib/templates/swift/parameter_access.erb +++ b/codegen/lib/templates/swift/parameter_access.erb @@ -10,12 +10,14 @@ let <%= param.name %>String: UnsafeRawPointer? if let s = <%= param.name %> { <%= param.name %>String = TWStringCreateWithNSString(s) - defer { - TWStringDelete(s) - } } else { <%= param.name %>String = nil } + defer { + if let s = <%= param.name %>String { + TWStringDelete(s) + } + } <% else -%> let <%= param.name %>String = TWStringCreateWithNSString(<%= param.name %>) defer { diff --git a/include/TrustWalletCore/TWBase32.h b/include/TrustWalletCore/TWBase32.h index 871bbf8b561..e65c67e5890 100644 --- a/include/TrustWalletCore/TWBase32.h +++ b/include/TrustWalletCore/TWBase32.h @@ -19,34 +19,34 @@ struct TWBase32; /// Decode a Base32 input with the given alphabet /// /// \param string Encoded base32 input to be decoded -/// \param alphabet Decode with the given alphabet, if empty ALPHABET_RFC4648 is used by default +/// \param alphabet Decode with the given alphabet, if nullptr ALPHABET_RFC4648 is used by default /// \return The decoded data, can be null. /// \note ALPHABET_RFC4648 doesn't support padding in the default alphabet TW_EXPORT_STATIC_METHOD -TWData* _Nullable TWBase32DecodeWithAlphabet(TWString* _Nonnull string, TWString* _Nonnull alphabet); +TWData* _Nullable TWBase32DecodeWithAlphabet(TWString* _Nonnull string, TWString* _Nullable alphabet); /// Decode a Base32 input with the default alphabet (ALPHABET_RFC4648) /// /// \param string Encoded input to be decoded /// \return The decoded data -/// \note Call TWBase32DecodeWithAlphabet with empty string. +/// \note Call TWBase32DecodeWithAlphabet with nullptr. TW_EXPORT_STATIC_METHOD TWData* _Nullable TWBase32Decode(TWString* _Nonnull string); /// Encode an input to Base32 with the given alphabet /// /// \param data Data to be encoded (raw bytes) -/// \param alphabet Encode with the given alphabet, if empty ALPHABET_RFC4648 is used by default +/// \param alphabet Encode with the given alphabet, if nullptr ALPHABET_RFC4648 is used by default /// \return The encoded data /// \note ALPHABET_RFC4648 doesn't support padding in the default alphabet TW_EXPORT_STATIC_METHOD -TWString *_Nonnull TWBase32EncodeWithAlphabet(TWData *_Nonnull data, TWString* _Nonnull alphabet); +TWString *_Nonnull TWBase32EncodeWithAlphabet(TWData *_Nonnull data, TWString* _Nullable alphabet); /// Encode an input to Base32 with the default alphabet (ALPHABET_RFC4648) /// /// \param data Data to be encoded (raw bytes) /// \return The encoded data -/// \note Call TWBase32EncodeWithAlphabet with empty string. +/// \note Call TWBase32EncodeWithAlphabet with nullptr. TW_EXPORT_STATIC_METHOD TWString *_Nonnull TWBase32Encode(TWData *_Nonnull data); diff --git a/src/interface/TWBase32.cpp b/src/interface/TWBase32.cpp index 11fd93093c8..6d2e89c342c 100644 --- a/src/interface/TWBase32.cpp +++ b/src/interface/TWBase32.cpp @@ -12,11 +12,11 @@ using namespace TW; -TWData* TWBase32DecodeWithAlphabet(TWString* _Nonnull string, TWString* _Nonnull alphabet) { +TWData* TWBase32DecodeWithAlphabet(TWString* _Nonnull string, TWString* _Nullable alphabet) { Data decodedOut; auto cppString = *reinterpret_cast(string); const char* alphabetRaw = nullptr; - if (TWStringSize(alphabet) > 0) { + if (alphabet != nullptr) { alphabetRaw = TWStringUTF8Bytes(alphabet); } auto result = Base32::decode(cppString, decodedOut, alphabetRaw); @@ -24,14 +24,13 @@ TWData* TWBase32DecodeWithAlphabet(TWString* _Nonnull string, TWString* _Nonnull } TWData* _Nullable TWBase32Decode(TWString* _Nonnull string) { - std::string empty; - return TWBase32DecodeWithAlphabet(string, &empty); + return TWBase32DecodeWithAlphabet(string, nullptr); } -TWString* _Nonnull TWBase32EncodeWithAlphabet(TWData* _Nonnull data, TWString* _Nonnull alphabet) { +TWString* _Nonnull TWBase32EncodeWithAlphabet(TWData* _Nonnull data, TWString* _Nullable alphabet) { auto cppData = *reinterpret_cast(data); const char* alphabetRaw = nullptr; - if (TWStringSize(alphabet) > 0) { + if (alphabet != nullptr) { alphabetRaw = TWStringUTF8Bytes(alphabet); } auto result = Base32::encode(cppData, alphabetRaw); @@ -39,6 +38,5 @@ TWString* _Nonnull TWBase32EncodeWithAlphabet(TWData* _Nonnull data, TWString* _ } TWString* _Nonnull TWBase32Encode(TWData* _Nonnull data) { - std::string empty; - return TWBase32EncodeWithAlphabet(data, &empty); + return TWBase32EncodeWithAlphabet(data, nullptr); } From 269dd3aca8f9db7e2cb17299c8cf4c36969fff97 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Fri, 7 Oct 2022 00:13:18 +0200 Subject: [PATCH 102/497] Support Bitcoin testnet address (#2621) * Support Bitcoin testnet address * Put prefix in constant --- registry.json | 6 ++++ src/Bitcoin/Entry.cpp | 3 ++ src/Bitcoin/SegwitAddress.h | 6 ++++ tests/Bitcoin/SegwitAddressTests.cpp | 42 ++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) diff --git a/registry.json b/registry.json index a2e07e2c29b..d77105beebe 100644 --- a/registry.json +++ b/registry.json @@ -18,6 +18,12 @@ "path": "m/44'/0'/0'/0/0", "xpub": "xpub", "xprv": "xprv" + }, + { + "name": "testnet", + "path": "m/84'/1'/0'/0/0", + "xpub": "zpub", + "xprv": "zprv" } ], "curve": "secp256k1", diff --git a/src/Bitcoin/Entry.cpp b/src/Bitcoin/Entry.cpp index 26816b632b7..36ee93a94f6 100644 --- a/src/Bitcoin/Entry.cpp +++ b/src/Bitcoin/Entry.cpp @@ -72,6 +72,9 @@ std::string Entry::deriveAddress(TWCoinType coin, TWDerivation derivation, const case TWDerivationLitecoinLegacy: return Address(publicKey, p2pkh).string(); + case TWDerivationBitcoinTestnet: + return SegwitAddress::createTestnetFromPublicKey(publicKey).string(); + case TWDerivationBitcoinSegwit: case TWDerivationDefault: default: diff --git a/src/Bitcoin/SegwitAddress.h b/src/Bitcoin/SegwitAddress.h index 8a073b6f1fa..54803acb7ba 100644 --- a/src/Bitcoin/SegwitAddress.h +++ b/src/Bitcoin/SegwitAddress.h @@ -31,6 +31,9 @@ class SegwitAddress { /// Witness program. Data witnessProgram; + // Prefix for Bitcoin Testnet Segwit addresses + static constexpr auto TestnetPrefix = "tb"; + /// Determines whether a string makes a valid Bech32 address. static bool isValid(const std::string& string); @@ -47,6 +50,9 @@ class SegwitAddress { /// Taproot (v>=1) is not supported by this method. SegwitAddress(const PublicKey& publicKey, std::string hrp); + /// Create a testnet address + static SegwitAddress createTestnetFromPublicKey(const PublicKey& publicKey) { return SegwitAddress(publicKey, TestnetPrefix); } + /// Decodes a SegWit address. /// /// \returns a tuple with the address, hrp, and a success flag. diff --git a/tests/Bitcoin/SegwitAddressTests.cpp b/tests/Bitcoin/SegwitAddressTests.cpp index 4545ff9dc86..3180eef8337 100644 --- a/tests/Bitcoin/SegwitAddressTests.cpp +++ b/tests/Bitcoin/SegwitAddressTests.cpp @@ -6,6 +6,7 @@ #include "Bech32.h" #include "Bitcoin/SegwitAddress.h" +#include "HDWallet.h" #include "HexCoding.h" #include @@ -208,4 +209,45 @@ TEST(SegwitAddress, Equals) { ASSERT_FALSE(addr1 == addr2); } +TEST(SegwitAddress, TestnetAddress) { + const auto mnemonic1 = "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal"; + const auto passphrase = ""; + const auto coin = TWCoinTypeBitcoin; + HDWallet wallet = HDWallet(mnemonic1, passphrase); + + // default + { + const auto privKey = wallet.getKey(coin, TWDerivationDefault); + const auto pubKey = privKey.getPublicKey(TWPublicKeyTypeSECP256k1); + EXPECT_EQ(hex(pubKey.bytes), "02df9ef2a7a5552765178b181e1e1afdefc7849985c7dfe9647706dd4fa40df6ac"); + EXPECT_EQ(SegwitAddress(pubKey, "bc").string(), "bc1qpsp72plnsqe6e2dvtsetxtww2cz36ztmfxghpd"); + } + + // testnet: different derivation path and hrp + { + const auto privKey = wallet.getKey(coin, TW::DerivationPath("m/84'/1'/0'/0/0")); + const auto pubKey = privKey.getPublicKey(TWPublicKeyTypeSECP256k1); + EXPECT_EQ(hex(pubKey.bytes), "03eb1a535b59f03894b99319f850c784cf4164f4de07620695c5cf0dc5c1ab2a54"); + EXPECT_EQ(SegwitAddress::createTestnetFromPublicKey(pubKey).string(), "tb1qq8p994ak933c39d2jaj8n4sg598tnkhnyk5sg5"); + // alternative with custom hrp + EXPECT_EQ(SegwitAddress(pubKey, "tb").string(), "tb1qq8p994ak933c39d2jaj8n4sg598tnkhnyk5sg5"); + } + + EXPECT_TRUE(SegwitAddress::isValid("tb1qq8p994ak933c39d2jaj8n4sg598tnkhnyk5sg5")); +} + +TEST(SegwitAddress, SegwitDerivationHDWallet) { + const auto mnemonic1 = "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal"; + const auto passphrase = ""; + const auto coin = TWCoinTypeBitcoin; + HDWallet wallet = HDWallet(mnemonic1, passphrase); + + // addresses with different derivations + EXPECT_EQ(wallet.deriveAddress(coin), "bc1qpsp72plnsqe6e2dvtsetxtww2cz36ztmfxghpd"); + EXPECT_EQ(wallet.deriveAddress(coin, TWDerivationDefault), "bc1qpsp72plnsqe6e2dvtsetxtww2cz36ztmfxghpd"); + EXPECT_EQ(wallet.deriveAddress(coin, TWDerivationBitcoinSegwit), "bc1qpsp72plnsqe6e2dvtsetxtww2cz36ztmfxghpd"); + EXPECT_EQ(wallet.deriveAddress(coin, TWDerivationBitcoinLegacy), "1GVb4mfQrvymPLz7zeZ3LnQ8sFv3NedZXe"); + EXPECT_EQ(wallet.deriveAddress(coin, TWDerivationBitcoinTestnet), "tb1qq8p994ak933c39d2jaj8n4sg598tnkhnyk5sg5"); +} + } // namespace TW::Bitcoin::tests From 22bfd4303f149dda1ddef83b3bb3204812b9b167 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Fri, 7 Oct 2022 12:09:24 +0200 Subject: [PATCH 103/497] [Devconsole] Add missing walletXxx utilities to help (#2616) * Add missing wallet* utilities to help * Fix return types (review comment) --- samples/typescript/devconsole.ts/src/index.ts | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/samples/typescript/devconsole.ts/src/index.ts b/samples/typescript/devconsole.ts/src/index.ts index fd994c1f539..f08c79bd6c8 100644 --- a/samples/typescript/devconsole.ts/src/index.ts +++ b/samples/typescript/devconsole.ts/src/index.ts @@ -132,9 +132,9 @@ async function main() { autoFillName(name: string): string { return (name === '') ? `Wallet${(this.storeWallets.length + 1).toString()}` : name; } - async create(strength: number, name: string): Promise { + async create(strength: number, name: string): Promise { this.wallet = null; - if (!this.keystore) { return; } + if (!this.keystore) { return null; } try { if (name === '') { name = this.autoFillName(name); } const hdWallet = WC.HDWallet.create(strength, this.HDWalletPassord); @@ -150,11 +150,12 @@ async function main() { return this.wallet; } catch (err) { console.log(`Exception: ${err}`); + return null; } } - async import(mnemonic: string, name: string): Promise { + async import(mnemonic: string, name: string): Promise { this.wallet = null; - if (!this.keystore) { return; } + if (!this.keystore) { return null; } try { if (!WC.Mnemonic.isValid(mnemonic)) { console.error(`Mnemonic is not valid ${mnemonic}`); @@ -171,16 +172,18 @@ async function main() { return this.wallet; } catch (err) { console.log(`Exception: ${err}`); + return null; } } - async addCoin(coin: string): Promise { + async addCoin(coin: string): Promise { if (this.wallet == null) { console.error('No wallet open, see walletCreate() / walletLoad() / walletsList()'); - return; + return null; } - if (!this.keystore) { return; } + if (!this.keystore) { return null; } const wallet = await this.keystore.addAccounts(this.wallet?.wallet.identifier(), this.StoreFixedPassword, [coin]); this.wallet = new StoredKeyWallet(this.keystore.mapStoredKey(wallet)); + return this.wallet; } // Delete loaded wallet async delete(param: string): Promise { @@ -248,9 +251,9 @@ async function main() { async function walletsList() { await wallets.list(); } async function walletLoad(index: number) { await wallets.load(index); } async function walletsDeleteAll(param: string) { await wallets.deleteAll(param); } - async function walletCreate(strength: number = 256, name: string = ''): Promise { return await wallets.create(strength, name); } - async function walletImport(mnemonic: string, name: string = ''): Promise { return wallets.import(mnemonic, name); } - async function walletAddCoin(coin: string): Promise { return wallets.addCoin(coin); } + async function walletCreate(strength: number = 256, name: string = ''): Promise { return await wallets.create(strength, name); } + async function walletImport(mnemonic: string, name: string = ''): Promise { return await wallets.import(mnemonic, name); } + async function walletAddCoin(coin: string): Promise { return await wallets.addCoin(coin); } function walletDump(): void { wallets.dump(); } async function walletDelete(param: string) { await wallets.delete(param); } @@ -276,6 +279,11 @@ async function main() { console.log(" walletCreate([strength], [name]) walletCreate(128)"); console.log(" walletImport(mnemonic, [name]) walletImport('ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal', 'Test1')"); console.log(" walletDump() walletDump()"); + console.log(" walletAddCoin(symbol) walletAddCoin(CoinType.solana)"); + console.log(" walletsList() walletsList()"); + console.log(" walletLoad() walletLoad(0)"); + console.log(" walletDelete() walletDelete('delete')"); + console.log(" walletsDeleteAll() walletsDeleteAll('deleteall')"); console.log(); console.log("See examples in samplescripts folder, e.g.: cat samplescripts/protoeth.sampleinput.txt | npm run start"); console.log(); From 871c4d51d32dddfb6003f8fc204925cd039c068d Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 7 Oct 2022 12:46:25 +0200 Subject: [PATCH 104/497] [Aptos]: Aptos NFT capabilities (#2613) --- src/Aptos/Address.h | 1 + src/Aptos/MoveTypes.h | 1 + src/Aptos/Signer.cpp | 107 ++++++++++++++++++-- src/proto/Aptos.proto | 65 +++++++++++-- tests/Aptos/SignerTests.cpp | 156 +++++++++++++++++++++++++++++- tests/interface/TWTestUtilities.h | 7 +- 6 files changed, 315 insertions(+), 22 deletions(-) diff --git a/src/Aptos/Address.h b/src/Aptos/Address.h index 52b995fa3be..45fe27aa011 100644 --- a/src/Aptos/Address.h +++ b/src/Aptos/Address.h @@ -52,6 +52,7 @@ constexpr inline bool operator==(const Address& lhs, const Address& rhs) noexcep inline const Address gAddressZero = Address("0x0"); inline const Address gAddressOne = Address("0x1"); +inline const Address gAddressThree = Address("0x3"); BCS::Serializer& operator<<(BCS::Serializer& stream, Address) noexcept; diff --git a/src/Aptos/MoveTypes.h b/src/Aptos/MoveTypes.h index d3810f300a3..7f77f9995ca 100644 --- a/src/Aptos/MoveTypes.h +++ b/src/Aptos/MoveTypes.h @@ -97,5 +97,6 @@ BCS::Serializer& operator<<(BCS::Serializer& stream, const Vector& t) noexcept; BCS::Serializer& operator<<(BCS::Serializer& stream, const TStructTag& t) noexcept; BCS::Serializer& operator<<(BCS::Serializer& stream, const TypeTag& t) noexcept; static const TypeTag gTransferTag = {TypeTag::TypeTagVariant(TStructTag{.st = StructTag(gAddressOne, "aptos_coin", "AptosCoin", {})})}; +static const TypeTag gOfferNftTag = {TypeTag::TypeTagVariant(TStructTag{.st = StructTag(gAddressThree, "token_transfers", "offer_script", {})})}; } // namespace TW::Aptos diff --git a/src/Aptos/Signer.cpp b/src/Aptos/Signer.cpp index eb1e05424d4..e734c34edc4 100644 --- a/src/Aptos/Signer.cpp +++ b/src/Aptos/Signer.cpp @@ -11,17 +11,22 @@ #include "TransactionBuilder.h" #include "TransactionPayload.h" +namespace { +template +void serializeToArgs(std::vector& args, T&& toSerialize) { + TW::BCS::Serializer serializer; + serializer << std::forward(toSerialize); + args.emplace_back(serializer.bytes); +} +} // namespace + namespace TW::Aptos { template std::pair, nlohmann::json> commonTransferPayload(const TPayload& input) { - BCS::Serializer aSerializer; - aSerializer << Address(input.to()); std::vector args; - args.emplace_back(aSerializer.bytes); - aSerializer.clear(); - aSerializer << input.amount(); - args.emplace_back(aSerializer.bytes); + serializeToArgs(args, Address(input.to())); + serializeToArgs(args, input.amount()); nlohmann::json argsJson = nlohmann::json::array({input.to(), std::to_string(input.amount())}); return std::make_pair(args, argsJson); } @@ -35,15 +40,81 @@ TransactionPayload transferPayload(const Proto::SigningInput& input) { TransactionPayload createAccountPayload(const Proto::SigningInput& input) { ModuleId module(gAddressOne, "aptos_account"); - BCS::Serializer aSerializer; - aSerializer << Address(input.create_account().auth_key()); std::vector args; - args.emplace_back(aSerializer.bytes); + serializeToArgs(args, Address(input.create_account().auth_key())); nlohmann::json argsJson = nlohmann::json::array({input.create_account().auth_key()}); TransactionPayload payload = EntryFunction(module, "create_account", {}, args, argsJson); return payload; } +TransactionPayload claimNftPayload(const Proto::ClaimNftMessage& msg) { + std::vector args; + ModuleId module(gAddressThree, "token_transfers"); + serializeToArgs(args, Address(msg.sender())); + serializeToArgs(args, Address(msg.creator())); + serializeToArgs(args, msg.collectionname()); + serializeToArgs(args, msg.name()); + serializeToArgs(args, msg.property_version()); + // clang-format off + nlohmann::json argsJson = nlohmann::json::array( + { + msg.sender(), + msg.creator(), + msg.collectionname(), + msg.name(), + std::to_string(msg.property_version()), + }); + // clang-format on + TransactionPayload payload = EntryFunction(module, "claim_script", {}, args, argsJson); + return payload; +} + +TransactionPayload nftOfferPayload(const Proto::OfferNftMessage& msg) { + std::vector args; + ModuleId module(gAddressThree, "token_transfers"); + serializeToArgs(args, Address(msg.receiver())); + serializeToArgs(args, Address(msg.creator())); + serializeToArgs(args, msg.collectionname()); + serializeToArgs(args, msg.name()); + serializeToArgs(args, msg.property_version()); + serializeToArgs(args, msg.amount()); + // clang-format off + nlohmann::json argsJson = nlohmann::json::array( + { + msg.receiver(), + msg.creator(), + msg.collectionname(), + msg.name(), + std::to_string(msg.property_version()), + std::to_string(msg.amount()) + }); + // clang-format on + TransactionPayload payload = EntryFunction(module, "offer_script", {}, args, argsJson); + return payload; +} + +TransactionPayload cancelNftOfferPayload(const Proto::CancelOfferNftMessage& msg) { + std::vector args; + ModuleId module(gAddressThree, "token_transfers"); + serializeToArgs(args, Address(msg.receiver())); + serializeToArgs(args, Address(msg.creator())); + serializeToArgs(args, msg.collectionname()); + serializeToArgs(args, msg.name()); + serializeToArgs(args, msg.property_version()); + // clang-format off + nlohmann::json argsJson = nlohmann::json::array( + { + msg.receiver(), + msg.creator(), + msg.collectionname(), + msg.name(), + std::to_string(msg.property_version()), + }); + // clang-format on + TransactionPayload payload = EntryFunction(module, "cancel_offer_script", {}, args, argsJson); + return payload; +} + TransactionPayload tokenTransferPayload(const Proto::SigningInput& input) { auto&& [args, argsJson] = commonTransferPayload(input.token_transfer()); @@ -86,7 +157,19 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) { if (!input.any_encoded().empty()) { return blindSign(input); } - auto payloadFunctor = [&input]() { + auto nftPayloadFunctor = [](const Proto::NftMessage& nftMessage) { + switch (nftMessage.nft_transaction_payload_case()) { + case Proto::NftMessage::kOfferNft: + return nftOfferPayload(nftMessage.offer_nft()); + case Proto::NftMessage::kCancelOfferNft: + return cancelNftOfferPayload(nftMessage.cancel_offer_nft()); + case Proto::NftMessage::kClaimNft: + return claimNftPayload(nftMessage.claim_nft()); + case Proto::NftMessage::NFT_TRANSACTION_PAYLOAD_NOT_SET: + throw std::runtime_error("Nft message payload not set"); + } + }; + auto payloadFunctor = [&input, &nftPayloadFunctor]() { switch (input.transaction_payload_case()) { case Proto::SigningInput::kTransfer: { return transferPayload(input); @@ -94,8 +177,12 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) { case Proto::SigningInput::kTokenTransfer: { return tokenTransferPayload(input); } + case Proto::SigningInput::kNftMessage: { + return nftPayloadFunctor(input.nft_message()); + } case Proto::SigningInput::kCreateAccount: return createAccountPayload(input); + case Proto::SigningInput::TRANSACTION_PAYLOAD_NOT_SET: throw std::runtime_error("Transaction payload should be set"); } diff --git a/src/proto/Aptos.proto b/src/proto/Aptos.proto index 70d4f4eb598..4d28f034868 100644 --- a/src/proto/Aptos.proto +++ b/src/proto/Aptos.proto @@ -43,6 +43,58 @@ message CreateAccountMessage { string auth_key = 1; } +// Necessary fields to process an OfferNftMessage +message OfferNftMessage { + // Receiver address + string receiver = 1; + // Creator address + string creator = 2; + // Name of the collection + string collectionName = 3; + // Name of the NFT + string name = 4; + // Property version (should be often 0) + uint64 property_version = 5; + // Amount of NFT's to transfer (should be often 1) + uint64 amount = 6; +} + +// Necessary fields to process an CancelOfferNftMessage +message CancelOfferNftMessage { + // Receiver address + string receiver = 1; + // Creator address + string creator = 2; + // Name of the collection + string collectionName = 3; + // Name of the NFT + string name = 4; + // Property version (should be often 0) + uint64 property_version = 5; +} + +// Necessary fields to process an ClaimNftMessage +message ClaimNftMessage { + // Sender address + string sender = 1; + // Creator address + string creator = 2; + // Name of the collection + string collectionName = 3; + // Name of the NFT + string name = 4; + // Property version (should be often 0) + uint64 property_version = 5; +} + +message NftMessage { + oneof nft_transaction_payload { + OfferNftMessage offer_nft = 1; + CancelOfferNftMessage cancel_offer_nft = 2; + ClaimNftMessage claim_nft = 3; + } +} + // Input data necessary to create a signed transaction. message SigningInput { // Sender Account address (string) @@ -53,19 +105,20 @@ message SigningInput { TransferMessage transfer = 3; TokenTransferMessage token_transfer = 4; CreateAccountMessage create_account = 5; + NftMessage nft_message = 6; } // Max gas amount that the user is willing to pay (uint64) - uint64 max_gas_amount = 6; + uint64 max_gas_amount = 7; // Gas unit price - queried through API (uint64) - uint64 gas_unit_price = 7; + uint64 gas_unit_price = 8; // Expiration timestamp for the transaction, can't be in the past (uint64) - uint64 expiration_timestamp_secs = 8; + uint64 expiration_timestamp_secs = 9; // Chain id 1 (mainnet) 32(devnet) (uint32 - casted in uint8_t later) - uint32 chain_id = 9; + uint32 chain_id = 10; // Private key to sign the transaction (bytes) - bytes private_key = 10; + bytes private_key = 11; // hex encoded function to sign, use it for smart contract approval (string) - string any_encoded = 11; + string any_encoded = 12; } // Information related to the signed transaction diff --git a/tests/Aptos/SignerTests.cpp b/tests/Aptos/SignerTests.cpp index ece577f4e0b..1ebb97cfcc3 100644 --- a/tests/Aptos/SignerTests.cpp +++ b/tests/Aptos/SignerTests.cpp @@ -9,6 +9,7 @@ #include "HexCoding.h" #include "PrivateKey.h" #include "PublicKey.h" +#include "../interface/TWTestUtilities.h" #include #include @@ -53,7 +54,152 @@ TEST(AptosSigner, DummyTxSign) { } )"_json; nlohmann::json parsedJson = nlohmann::json::parse(result.json()); - ASSERT_EQ(expectedJson, parsedJson); + assertJSONEqual(expectedJson, parsedJson); +} + +TEST(AptosSigner, ClaimNftTxSign) { + // Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x60b51e15140ec0b7650334e948fb447ce3cb13ae63492260461ebfa9d02e85c4?network=testnet + Proto::SigningInput input; + input.set_sender("0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); + input.set_sequence_number(19); + auto& tf = *input.mutable_nft_message()->mutable_claim_nft(); + tf.set_sender("0x783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee"); + tf.set_creator("0x9125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac"); + tf.set_collectionname("Topaz Troopers"); + tf.set_name("Topaz Trooper #20068"); + tf.set_property_version(0); + input.set_max_gas_amount(3296766); + input.set_gas_unit_price(100); + input.set_expiration_timestamp_secs(3664390082); + input.set_chain_id(2); + auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.raw_txn()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3013000000000000000200000000000000000000000000000000000000000000000000000000000000030f746f6b656e5f7472616e73666572730c636c61696d5f736372697074000520783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee209125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac0f0e546f70617a2054726f6f706572731514546f70617a2054726f6f70657220233230303638080000000000000000fe4d3200000000006400000000000000c2276ada0000000002"); + ASSERT_EQ(hex(result.authenticator().signature()), "ede1ffb5f8f663741c2ca9597af44af81c98f7a910261bb4125f758fd0c0ebbf5bacb34f1196ad45153177729eb6d478676b364ab747da17602713f65ca2dd0a"); + ASSERT_EQ(hex(result.encoded()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3013000000000000000200000000000000000000000000000000000000000000000000000000000000030f746f6b656e5f7472616e73666572730c636c61696d5f736372697074000520783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee209125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac0f0e546f70617a2054726f6f706572731514546f70617a2054726f6f70657220233230303638080000000000000000fe4d3200000000006400000000000000c2276ada00000000020020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c40ede1ffb5f8f663741c2ca9597af44af81c98f7a910261bb4125f758fd0c0ebbf5bacb34f1196ad45153177729eb6d478676b364ab747da17602713f65ca2dd0a"); + nlohmann::json expectedJson = R"( + { + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": [ + "0x783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee", + "0x9125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac", + "Topaz Troopers", "Topaz Trooper #20068", "0"], + "function": "0x3::token_transfers::claim_script", + "type": "entry_function_payload", + "type_arguments": [] + }, + "sender": "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "19", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0xede1ffb5f8f663741c2ca9597af44af81c98f7a910261bb4125f758fd0c0ebbf5bacb34f1196ad45153177729eb6d478676b364ab747da17602713f65ca2dd0a", + "type": "ed25519_signature" + } + } + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(result.json()); + assertJSONEqual(expectedJson, parsedJson); +} + +TEST(AptosSigner, NftOfferTxSign) { + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0x514e473618bd3cb89a2b110b7c473db9a2e10532f98eb42d02d86fb31c00525d?network=testnet + Proto::SigningInput input; + input.set_sender("0x783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee"); + input.set_sequence_number(1); + auto& tf = *input.mutable_nft_message()->mutable_offer_nft(); + tf.set_receiver("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); + tf.set_creator("0x9125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac"); + tf.set_collectionname("Topaz Troopers"); + tf.set_name("Topaz Trooper #20068"); + tf.set_property_version(0); + tf.set_amount(1); + input.set_max_gas_amount(3296766); + input.set_gas_unit_price(100); + input.set_expiration_timestamp_secs(3664390082); + input.set_chain_id(2); + auto privateKey = PrivateKey(parse_hex("7bebb6d543d17f6fe4e685cfab239fa37896edd594ff859f1df32f244fb707e2")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.raw_txn()), "783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee01000000000000000200000000000000000000000000000000000000000000000000000000000000030f746f6b656e5f7472616e73666572730c6f666665725f73637269707400062007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30209125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac0f0e546f70617a2054726f6f706572731514546f70617a2054726f6f70657220233230303638080000000000000000080100000000000000fe4d3200000000006400000000000000c2276ada0000000002"); + ASSERT_EQ(hex(result.authenticator().signature()), "af5c7357a83c69e3f425beb23eaf232f8bb36dea3b7cad4a7ab8d735cee999c8ec5285005adf69dc85a6c34b042dd0308fe92b76dad5d6ac88c7b9259902c10f"); + ASSERT_EQ(hex(result.encoded()), "783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee01000000000000000200000000000000000000000000000000000000000000000000000000000000030f746f6b656e5f7472616e73666572730c6f666665725f73637269707400062007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30209125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac0f0e546f70617a2054726f6f706572731514546f70617a2054726f6f70657220233230303638080000000000000000080100000000000000fe4d3200000000006400000000000000c2276ada00000000020020d1d99b67e37b483161a0fa369c46f34a3be4863c20e20fc7cdc669c0826a411340af5c7357a83c69e3f425beb23eaf232f8bb36dea3b7cad4a7ab8d735cee999c8ec5285005adf69dc85a6c34b042dd0308fe92b76dad5d6ac88c7b9259902c10f"); + nlohmann::json expectedJson = R"( + { + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": [ + "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "0x9125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac", + "Topaz Troopers", "Topaz Trooper #20068", "0", "1"], + "function": "0x3::token_transfers::offer_script", + "type": "entry_function_payload", + "type_arguments": [] + }, + "sender": "0x783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee", + "sequence_number": "1", + "signature": { + "public_key": "0xd1d99b67e37b483161a0fa369c46f34a3be4863c20e20fc7cdc669c0826a4113", + "signature": "0xaf5c7357a83c69e3f425beb23eaf232f8bb36dea3b7cad4a7ab8d735cee999c8ec5285005adf69dc85a6c34b042dd0308fe92b76dad5d6ac88c7b9259902c10f", + "type": "ed25519_signature" + } + } + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(result.json()); + assertJSONEqual(expectedJson, parsedJson); +} + +TEST(AptosSigner, CancelNftOfferTxSign) { + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0x0b8c64e6847c368e4c6bd2cce0e9eab378971b0ef2e3bc40cbd292910a80201d?network=testnet + Proto::SigningInput input; + input.set_sender("0x7968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); + input.set_sequence_number(21); + auto& tf = *input.mutable_nft_message()->mutable_cancel_offer_nft(); + tf.set_receiver("0x783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee"); + tf.set_creator("0x9125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac"); + tf.set_collectionname("Topaz Troopers"); + tf.set_name("Topaz Trooper #20068"); + tf.set_property_version(0); + input.set_max_gas_amount(3296766); + input.set_gas_unit_price(100); + input.set_expiration_timestamp_secs(3664390082); + input.set_chain_id(2); + auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.raw_txn()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3015000000000000000200000000000000000000000000000000000000000000000000000000000000030f746f6b656e5f7472616e73666572731363616e63656c5f6f666665725f736372697074000520783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee209125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac0f0e546f70617a2054726f6f706572731514546f70617a2054726f6f70657220233230303638080000000000000000fe4d3200000000006400000000000000c2276ada0000000002"); + ASSERT_EQ(hex(result.authenticator().signature()), "826722d374e276f618123e77da3ac024c89a3f97db9e09e19aa8ed06c3cdfc57d4a21c7890137f9a7c0447cc303447ba10ca5b1908e889071e0a68f48c0f260a"); + ASSERT_EQ(hex(result.encoded()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3015000000000000000200000000000000000000000000000000000000000000000000000000000000030f746f6b656e5f7472616e73666572731363616e63656c5f6f666665725f736372697074000520783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee209125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac0f0e546f70617a2054726f6f706572731514546f70617a2054726f6f70657220233230303638080000000000000000fe4d3200000000006400000000000000c2276ada00000000020020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c40826722d374e276f618123e77da3ac024c89a3f97db9e09e19aa8ed06c3cdfc57d4a21c7890137f9a7c0447cc303447ba10ca5b1908e889071e0a68f48c0f260a"); + nlohmann::json expectedJson = R"( + { + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "3296766", + "payload": { + "arguments": [ + "0x783135e8b00430253a22ba041d860c373d7a1501ccf7ac2d1ad37a8ed2775aee", + "0x9125e4054d884fdc7296b66e12c0d63a7baa0d88c77e8e784987c0a967c670ac", + "Topaz Troopers", "Topaz Trooper #20068", "0"], + "function": "0x3::token_transfers::cancel_offer_script", + "type": "entry_function_payload", + "type_arguments": [] + }, + "sender": "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "21", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0x826722d374e276f618123e77da3ac024c89a3f97db9e09e19aa8ed06c3cdfc57d4a21c7890137f9a7c0447cc303447ba10ca5b1908e889071e0a68f48c0f260a", + "type": "ed25519_signature" + } + } + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(result.json()); + assertJSONEqual(expectedJson, parsedJson); } TEST(AptosSigner, TxSign) { @@ -95,7 +241,7 @@ TEST(AptosSigner, TxSign) { } )"_json; nlohmann::json parsedJson = nlohmann::json::parse(result.json()); - ASSERT_EQ(expectedJson, parsedJson); + assertJSONEqual(expectedJson, parsedJson); } TEST(AptosSigner, CreateAccount) { @@ -136,7 +282,7 @@ TEST(AptosSigner, CreateAccount) { } )"_json; nlohmann::json parsedJson = nlohmann::json::parse(result.json()); - ASSERT_EQ(expectedJson, parsedJson); + assertJSONEqual(expectedJson, parsedJson); } TEST(AptosSigner, BlindSign) { @@ -180,7 +326,7 @@ TEST(AptosSigner, BlindSign) { } )"_json; nlohmann::json parsedJson = nlohmann::json::parse(result.json()); - ASSERT_EQ(expectedJson, parsedJson); + assertJSONEqual(expectedJson, parsedJson); } TEST(AptosSigner, TokenTxSign) { @@ -225,7 +371,7 @@ TEST(AptosSigner, TokenTxSign) { } )"_json; nlohmann::json parsedJson = nlohmann::json::parse(result.json()); - ASSERT_EQ(expectedJson, parsedJson); + assertJSONEqual(expectedJson, parsedJson); } } // namespace TW::Aptos::tests diff --git a/tests/interface/TWTestUtilities.h b/tests/interface/TWTestUtilities.h index a03691dc7e4..78c0d89cb39 100644 --- a/tests/interface/TWTestUtilities.h +++ b/tests/interface/TWTestUtilities.h @@ -30,10 +30,15 @@ inline void assertHexEqual(const std::shared_ptr& data, const char* expe assertStringsEqual(hex, expected); } + +inline void assertJSONEqual(const nlohmann::json& lhs, const nlohmann::json& rhs) { + ASSERT_EQ(lhs, rhs); +} + inline void assertJSONEqual(const std::string& lhs, const char* expected) { auto lhsJson = nlohmann::json::parse(lhs); auto rhsJson = nlohmann::json::parse(std::string(expected)); - ASSERT_EQ(lhsJson, rhsJson); + return assertJSONEqual(lhsJson, rhsJson); } inline std::vector* dataFromTWData(TWData* data) { From 817798f7f67e055ece3db4aac85d483d23b80ee6 Mon Sep 17 00:00:00 2001 From: Klimov Sergey Date: Mon, 10 Oct 2022 07:34:18 +0300 Subject: [PATCH 105/497] Update Extrinsic.cpp (#2625) --- src/Polkadot/Extrinsic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Polkadot/Extrinsic.cpp b/src/Polkadot/Extrinsic.cpp index 6ce75c13c8d..8cab2fb5cef 100644 --- a/src/Polkadot/Extrinsic.cpp +++ b/src/Polkadot/Extrinsic.cpp @@ -17,7 +17,7 @@ static constexpr uint32_t multiAddrSpecVersion = 28; static constexpr uint32_t multiAddrSpecVersionKsm = 2028; static const std::string balanceTransfer = "Balances.transfer"; -static const std::string utilityBatch = "Utility.batch"; +static const std::string utilityBatch = "Utility.batch_all"; static const std::string stakingBond = "Staking.bond"; static const std::string stakingBondExtra = "Staking.bond_extra"; static const std::string stakingUnbond = "Staking.unbond"; From 637fae2a08266ac2bfd2c87cb7610723c6c63656 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Mon, 10 Oct 2022 06:34:48 +0200 Subject: [PATCH 106/497] Bitcoin Message Signing and Verification (#2623) --- .../TrustWalletCore/TWBitcoinMessageSigner.h | 43 +++++ src/Bitcoin/MessageSigner.cpp | 111 ++++++++++++ src/Bitcoin/MessageSigner.h | 61 +++++++ src/PublicKey.cpp | 32 +++- src/PublicKey.h | 19 +- src/interface/TWBitcoinMessageSigner.cpp | 22 +++ ...TWBitcoin.cpp => TWBitcoinSigHashType.cpp} | 0 swift/Tests/Blockchains/BitcoinTests.swift | 9 + tests/Bitcoin/MessageSignerTests.cpp | 167 ++++++++++++++++++ tests/PublicKeyTests.cpp | 52 ++++++ 10 files changed, 506 insertions(+), 10 deletions(-) create mode 100644 include/TrustWalletCore/TWBitcoinMessageSigner.h create mode 100644 src/Bitcoin/MessageSigner.cpp create mode 100644 src/Bitcoin/MessageSigner.h create mode 100644 src/interface/TWBitcoinMessageSigner.cpp rename src/interface/{TWBitcoin.cpp => TWBitcoinSigHashType.cpp} (100%) create mode 100644 tests/Bitcoin/MessageSignerTests.cpp diff --git a/include/TrustWalletCore/TWBitcoinMessageSigner.h b/include/TrustWalletCore/TWBitcoinMessageSigner.h new file mode 100644 index 00000000000..d0fcd2e17bd --- /dev/null +++ b/include/TrustWalletCore/TWBitcoinMessageSigner.h @@ -0,0 +1,43 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" +#include "TWPrivateKey.h" + +TW_EXTERN_C_BEGIN + +/// Bitcoin message signing and verification. +/// +/// Bitcoin Core and some other wallets support a message signing & verification format, to create a proof (a signature) +/// that someone has access to the private keys of a specific address. +/// This feature currently works on old legacy addresses only. +TW_EXPORT_CLASS +struct TWBitcoinMessageSigner; + +/// Sign a message. +/// +/// \param privateKey: the private key used for signing +/// \param address: the address that matches the privateKey, must be a legacy address (P2PKH) +/// \param message: A custom message which is input to the signing. +/// \note Address is derived assuming compressed public key format. +/// \returns the signature, Base64-encoded. On invalid input empty string is returned. Returned object needs to be deleteed after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWBitcoinMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull address, TWString* _Nonnull message); + +/// Verify signature for a message. +/// +/// \param address: address to use, only legacy is supported +/// \param message: the message signed (without prefix) +/// \param signature: in Base64-encoded form. +/// \returns false on any invalid input (does not throw). +TW_EXPORT_STATIC_METHOD +bool TWBitcoinMessageSignerVerifyMessage(TWString* _Nonnull address, TWString* _Nonnull message, TWString* _Nonnull signature); + +TW_EXTERN_C_END diff --git a/src/Bitcoin/MessageSigner.cpp b/src/Bitcoin/MessageSigner.cpp new file mode 100644 index 00000000000..21f3ca90de7 --- /dev/null +++ b/src/Bitcoin/MessageSigner.cpp @@ -0,0 +1,111 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "MessageSigner.h" +#include "Address.h" + +#include "Base64.h" +#include "BinaryCoding.h" +#include "Coin.h" +#include "Data.h" +#include "HexCoding.h" + +using namespace TW; + +namespace TW::Bitcoin { + +// lenght-encode a message string +Data messageToData(const std::string& message) { + Data d; + TW::encodeVarInt(message.size(), d); + TW::append(d, TW::data(message)); + return d; +} + +// append prefix and length-encode message string +Data messageToFullData(const std::string& message) { + Data d = messageToData(MessageSigner::MessagePrefix); + TW::append(d, messageToData(message)); + return d; +} + +Data MessageSigner::messageToHash(const std::string& message) { + Data d = messageToFullData(message); + return Hash::sha256d(d.data(), d.size()); +} + +std::string MessageSigner::signMessage(const PrivateKey& privateKey, const std::string& address, const std::string& message, bool compressed) { + if (!Address::isValid(address)) { + throw std::invalid_argument("Address is not valid (legacy) address"); + } + std::string addrFromKey; + if (compressed) { + const auto pubKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); + addrFromKey = Address(pubKey, TW::p2pkhPrefix(TWCoinTypeBitcoin)).string(); + } else { + const auto pubKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended); + const auto keyHash = pubKey.hash(Data{TW::p2pkhPrefix(TWCoinTypeBitcoin)}, Hash::HasherSha256ripemd); + addrFromKey = Address(keyHash).string(); + } + if (addrFromKey != address) { + throw std::invalid_argument("Address does not match key"); + } + const auto messageHash = messageToHash(message); + const auto signature = privateKey.sign(messageHash, TWCurveSECP256k1); + + // The V value: add 31 (or 27 for compressed), and move to the first byte + const byte v = signature[SignatureRSLength] + PublicKey::SignatureVOffset + (compressed ? 4ul : 0ul); + auto sigAdjusted = Data{v}; + TW::append(sigAdjusted, TW::subData(signature, 0, SignatureRSLength)); + return Base64::encode(sigAdjusted); +} + +std::string MessageSigner::recoverAddressFromMessage(const std::string& message, const Data& signature) { + if (signature.size() < SignatureRSVLength) { + throw std::invalid_argument("signature too short"); + } + const auto messageHash = MessageSigner::messageToHash(message); + auto recId = signature[0]; + auto compressed = false; + if (recId >= PublicKey::SignatureVOffset + 4) { + recId -= 4; + compressed = true; + } + if (recId >= PublicKey::SignatureVOffset) { + recId -= PublicKey::SignatureVOffset; + } + + const auto publicKeyRecovered = PublicKey::recoverRaw(TW::subData(signature, 1), recId, messageHash); + + if (!compressed) { + // uncompressed public key + const auto keyHash = publicKeyRecovered.hash(Data{TW::p2pkhPrefix(TWCoinTypeBitcoin)}, Hash::HasherSha256ripemd); + return Bitcoin::Address(keyHash).string(); + } + // compressed + const auto publicKeyRecoveredCompressed = publicKeyRecovered.compressed(); + return Bitcoin::Address(publicKeyRecoveredCompressed, TW::p2pkhPrefix(TWCoinTypeBitcoin)).string(); +} + +bool MessageSigner::verifyMessage(const std::string& address, const std::string& message, const std::string& signature) noexcept { + try { + const auto signatureData = Base64::decode(signature); + return verifyMessage(address, message, signatureData); + } catch (...) { + return false; + } +} + +/// May throw +bool MessageSigner::verifyMessage(const std::string& address, const std::string& message, const Data& signature) { + if (!Bitcoin::Address::isValid(address)) { + throw std::invalid_argument("Input address invalid, must be valid legacy"); + } + const auto addressRecovered = recoverAddressFromMessage(message, signature); + return (addressRecovered == address); +} + +} // namespace TW::Bitcoin diff --git a/src/Bitcoin/MessageSigner.h b/src/Bitcoin/MessageSigner.h new file mode 100644 index 00000000000..6779bfaf52d --- /dev/null +++ b/src/Bitcoin/MessageSigner.h @@ -0,0 +1,61 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" +#include "PrivateKey.h" + +#include + +namespace TW::Bitcoin { + +/// Class for message signing and verification. +/// +/// Bitcoin Core and some other wallets support a message signing & verification format, to create a proof (a signature) +/// that someone has access to the private keys of a specific address. +/// This feature currently works on old legacy addresses only. +class MessageSigner { + public: + /// Sign a message. + /// privateKey: the private key used for signing + /// address: the address that matches the privateKey, must be a legacy address (P2PKH) + /// message: A custom message which is input to the signing. + /// compressed: True by default, as addresses are generated from the hash of the compressed public key. + /// However, in some instances key hash is generated from the hash of the extended public key, + /// that's also supported here as well for compatibility. + /// Returns the signature, Base64-encoded. + /// Throws on invalid input. + static std::string signMessage(const PrivateKey& privateKey, const std::string& address, const std::string& message, bool compressed = true); + + /// Verify signature for a message. + /// address: address to use, only legacy is supported + /// message: the message signed (without prefix) + /// signature: in Base64-encoded form. + /// Returns false on any invalid input (does not throw). + static bool verifyMessage(const std::string& address, const std::string& message, const std::string& signature) noexcept; + + /// Verify signature for a message. + /// Address: address to use, only legacy is supported + /// message: the message signed (without prefix) + /// signature: in binary form. + /// May throw + static bool verifyMessage(const std::string& address, const std::string& message, const Data& signature); + + /// Recover address from signature and message. May throw. + static std::string recoverAddressFromMessage(const std::string& message, const Data& signature); + + /// Append prefix and compute hash for a message + static Data messageToHash(const std::string& message); + + static constexpr auto MessagePrefix = "Bitcoin Signed Message:\n"; + static const byte DigestLength = 32; + static const byte SignatureRSLength = 64; + static constexpr byte SignatureRSVLength = SignatureRSLength + 1; + static const byte VOffset = 27; +}; + +} // namespace TW::Bitcoin diff --git a/src/PublicKey.cpp b/src/PublicKey.cpp index 10c2e59d88a..0fcd53c3a3b 100644 --- a/src/PublicKey.cpp +++ b/src/PublicKey.cpp @@ -5,6 +5,7 @@ // file LICENSE at the root of the source code distribution tree. #include "PublicKey.h" +#include "PrivateKey.h" #include "Data.h" #include @@ -206,22 +207,35 @@ Data PublicKey::hash(const Data& prefix, Hash::Hasher hasher, bool skipTypeByte) return result; } -PublicKey PublicKey::recover(const Data& signature, const Data& message) { - if (signature.size() < 65) { +PublicKey PublicKey::recoverRaw(const Data& signatureRS, byte recId, const Data& messageDigest) { + if (signatureRS.size() < 2 * PrivateKey::_size) { throw std::invalid_argument("signature too short"); } - auto v = signature[64]; - // handle EIP155 Eth encoding of V, of the form 27+v, or 35+chainID*2+v - if (v >= 27) { - v = !(v & 0x01); + if (recId >= 4) { + throw std::invalid_argument("Invalid recId (>=4)"); + } + if (messageDigest.size() < PrivateKey::_size) { + throw std::invalid_argument("digest too short"); } - TW::Data result(65); - if (ecdsa_recover_pub_from_sig(&secp256k1, result.data(), signature.data(), message.data(), v) != 0) { - throw std::invalid_argument("recover failed"); + TW::Data result(secp256k1SignatureSize); + if (auto ret = ecdsa_recover_pub_from_sig(&secp256k1, result.data(), signatureRS.data(), messageDigest.data(), recId); ret != 0) { + throw std::invalid_argument("recover failed " + std::to_string(ret)); } return PublicKey(result, TWPublicKeyTypeSECP256k1Extended); } +PublicKey PublicKey::recover(const Data& signature, const Data& messageDigest) { + if (signature.size() < secp256k1SignatureSize) { + throw std::invalid_argument("signature too short"); + } + auto v = signature[secp256k1SignatureSize - 1]; + // handle EIP155 Eth encoding of V, of the form 27+v, or 35+chainID*2+v + if (v >= PublicKey::SignatureVOffset) { + v = !(v & 0x01); + } + return recoverRaw(signature, v, messageDigest); +} + bool PublicKey::isValidED25519() const { if (type != TWPublicKeyTypeED25519) { return false; diff --git a/src/PublicKey.h b/src/PublicKey.h index 3b4691cac35..111f0fdf306 100644 --- a/src/PublicKey.h +++ b/src/PublicKey.h @@ -30,6 +30,12 @@ class PublicKey { /// The number of bytes in a secp256k1 and nist256p1 extended public key. static const size_t secp256k1ExtendedSize = 65; + /// The number of bytes in a secp256k1 signature. + static const size_t secp256k1SignatureSize = 65; + + /// Magic number used in V compnent encoding + static const byte SignatureVOffset = 27; + /// The public key bytes. Data bytes; @@ -74,8 +80,19 @@ class PublicKey { /// bytes and then prepending the prefix. Data hash(const Data& prefix, Hash::Hasher hasher = Hash::HasherSha256ripemd, bool skipTypeByte = false) const; + /// Recover public key (SECP256k1Extended) from signature R, S, V values + /// signatureRS: 2x32 bytes with the R and S values + /// recId: the recovery ID, a.k.a. V value, 0 <= v < 4 + /// messageDigest: message digest (hash) to be signed + /// Throws on invalid data. + static PublicKey recoverRaw(const Data& signatureRS, byte recId, const Data& messageDigest); + /// Recover public key from signature (SECP256k1Extended) - static PublicKey recover(const Data& signature, const Data& message); + /// signature: 65-byte signature (R, S, and V). V can have higher value bits, as used by Ethereum (for values over 27 the negated last bit is taken). + /// messageDigest: message digest (hash) to be signed + /// Throws on invalid data. + /// Naming is kept for backwards compatibility. + static PublicKey recover(const Data& signature, const Data& messageDigest); /// Check if this key makes a valid ED25519 key (it is on the curve) bool isValidED25519() const; diff --git a/src/interface/TWBitcoinMessageSigner.cpp b/src/interface/TWBitcoinMessageSigner.cpp new file mode 100644 index 00000000000..d5b0985fbb1 --- /dev/null +++ b/src/interface/TWBitcoinMessageSigner.cpp @@ -0,0 +1,22 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include + +#include "Bitcoin/MessageSigner.h" + +TWString* _Nonnull TWBitcoinMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull address, TWString* _Nonnull message) { + try { + const auto signature = TW::Bitcoin::MessageSigner::signMessage(privateKey->impl, TWStringUTF8Bytes(address), TWStringUTF8Bytes(message), true); + return TWStringCreateWithUTF8Bytes(signature.c_str()); + } catch (...) { + return TWStringCreateWithUTF8Bytes(""); + } +} + +bool TWBitcoinMessageSignerVerifyMessage(TWString* _Nonnull address, TWString* _Nonnull message, TWString* _Nonnull signature) { + return TW::Bitcoin::MessageSigner::verifyMessage(TWStringUTF8Bytes(address), TWStringUTF8Bytes(message), TWStringUTF8Bytes(signature)); +} diff --git a/src/interface/TWBitcoin.cpp b/src/interface/TWBitcoinSigHashType.cpp similarity index 100% rename from src/interface/TWBitcoin.cpp rename to src/interface/TWBitcoinSigHashType.cpp diff --git a/swift/Tests/Blockchains/BitcoinTests.swift b/swift/Tests/Blockchains/BitcoinTests.swift index e4b7255fc76..4ace92e08e5 100644 --- a/swift/Tests/Blockchains/BitcoinTests.swift +++ b/swift/Tests/Blockchains/BitcoinTests.swift @@ -174,4 +174,13 @@ class BitcoinTransactionSignerTests: XCTestCase { XCTAssertEqual(output.error, .ok) XCTAssertEqual(output.encoded.hexString, "01000000026c90312e53a3411347a197bfd637c2583d617dd2317262a70e1b5245d2f1e36a000000008a47304402201a631068ea5ddea19467ef7c932a0f3b04f366ca2beaf70e18958e47456124980220614816c449e39cf6acc6625e1cf3100db1db7c0b755bdbb6804d4fa3c4b735d10141041b3937fac1f14074447cde9d3a324ed292d2865ed0d7a7da26cb43558ce4db4ef33c47e820e53031ae16bb0c39205def059a5ca8e1d617650eabc72c5206a81dffffffff13bf27945c669cf3c1d70cf3048f4ab14f1ab6acf06d10d425e8288217a81efd000000008a473044022051d381d8f48a9a4866ca4109f12647922514604a4733e8da8aac046e19275f700220797c3ebf20df7d2a9fed283f9d0ad14cbd656cafb5ec70a2b1c85646ea7485190141041b3937fac1f14074447cde9d3a324ed292d2865ed0d7a7da26cb43558ce4db4ef33c47e820e53031ae16bb0c39205def059a5ca8e1d617650eabc72c5206a81dffffffff0194590000000000001976a914a0c0a50f986924e65ae9bd18eafae448f83117ed88ac00000000") } + + func testBitcoinMessageSigner() { + let verifyResult = BitcoinMessageSigner.verifyMessage( + address: "1B8Qea79tsxmn4dTiKKRVvsJpHwL2fMQnr", + message: "test signature", + signature: "H+3L5IbSVcejp4S2VwLXCxLEMQAWDvKbE8lQyq0ocdvyM1aoEudkzN/S/qLI3vnNOFY6V13BXWSFrPr3OjGa5Dk=" + ) + XCTAssertTrue(verifyResult) + } } diff --git a/tests/Bitcoin/MessageSignerTests.cpp b/tests/Bitcoin/MessageSignerTests.cpp new file mode 100644 index 00000000000..e8df4e56631 --- /dev/null +++ b/tests/Bitcoin/MessageSignerTests.cpp @@ -0,0 +1,167 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Bitcoin/MessageSigner.h" +#include +#include "Bitcoin/Address.h" +#include "HexCoding.h" +#include "PrivateKey.h" +#include "PublicKey.h" +#include "Base64.h" +#include "Coin.h" +#include "Data.h" + +#include +#include + +#include +#include +#include // TODO remove + +namespace TW::Bitcoin::MessageSignerTests { + +const auto gPrivateKey = PrivateKey(parse_hex("afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5")); + +TEST(BitcoinMessageSigner, VerifyMessage) { + EXPECT_TRUE(MessageSigner::verifyMessage( + "1B8Qea79tsxmn4dTiKKRVvsJpHwL2fMQnr", + "test signature", + "H+3L5IbSVcejp4S2VwLXCxLEMQAWDvKbE8lQyq0ocdvyM1aoEudkzN/S/qLI3vnNOFY6V13BXWSFrPr3OjGa5Dk=" + )); + EXPECT_TRUE(MessageSigner::verifyMessage( + "1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN", + "This is an example of a signed message.", + "G39Qf0XrZHICWbz3r5gOkcgTRw3vM4leGjiR3refr/K1OezcKmmXaLn4zc8ji2rjbBUIMrIhH/jc5Z2qEEz7qVk=" + )); + EXPECT_TRUE(MessageSigner::verifyMessage( + "1H8X4u6CVZRTLLNbUQTKAnc5vCkqWMpwfF", + "compressed key", + "IKUI9v2xbHogJe8HKXI2M5KEhMKaW6fjNxtyEy27Mf+3/e1ht4jZoc85e4F8stPsxt4Xcg8Yr42S28O6L/Qx9fE=" + )); + EXPECT_TRUE(MessageSigner::verifyMessage( + "19cAJn4Ms8jodBBGtroBNNpCZiHAWGAq7X", + "test signature", + "ILH5K7JQLaRGaKGXXH5mYM6FIIy9IWyY4JUPI+PHYY4WaupxUbg+zy0bhBCrDuehy9x4WidwjkRR1GSLnWvOXBo=" + )); + EXPECT_TRUE(MessageSigner::verifyMessage( + "19cAJn4Ms8jodBBGtroBNNpCZiHAWGAq7X", + "another text", + "H7vrF2C+TlFiHyegAw3QLv6SK0myuEEXUOgfx0+Qio1YVDuSa6p/OHpoQVlUt3F8QJdbdZN9M1h/fYEAnEz16V0=" + )); + EXPECT_TRUE(MessageSigner::verifyMessage( + "1E4T9JZ3mq6cdgiRJEWzHqDXb9t322fE6d", + "test signature", + "HLH5K7JQLaRGaKGXXH5mYM6FIIy9IWyY4JUPI+PHYY4WaupxUbg+zy0bhBCrDuehy9x4WidwjkRR1GSLnWvOXBo=" + )); +} + +TEST(BitcoinMessageSigner, SignAndVerify) { + const auto pubKey = gPrivateKey.getPublicKey(TWPublicKeyTypeSECP256k1); + EXPECT_EQ(hex(pubKey.bytes), "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1"); + const auto address = Address(pubKey, TW::p2pkhPrefix(TWCoinTypeBitcoin)).string(); + EXPECT_EQ(address, "19cAJn4Ms8jodBBGtroBNNpCZiHAWGAq7X"); + + { + const auto msg = "test signature"; + const auto signature = MessageSigner::signMessage(gPrivateKey, address, msg); + EXPECT_EQ(signature, "ILH5K7JQLaRGaKGXXH5mYM6FIIy9IWyY4JUPI+PHYY4WaupxUbg+zy0bhBCrDuehy9x4WidwjkRR1GSLnWvOXBo="); + + EXPECT_TRUE(MessageSigner::verifyMessage(address, msg, signature)); + } + { + const auto msg = "another text"; + const auto signature = MessageSigner::signMessage(gPrivateKey, address, msg); + EXPECT_EQ(signature, "H7vrF2C+TlFiHyegAw3QLv6SK0myuEEXUOgfx0+Qio1YVDuSa6p/OHpoQVlUt3F8QJdbdZN9M1h/fYEAnEz16V0="); + + EXPECT_TRUE(MessageSigner::verifyMessage(address, msg, signature)); + } + + // uncompressed + const auto pubKeyUncomp = gPrivateKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended); + const auto keyHash = pubKeyUncomp.hash(Data{TW::p2pkhPrefix(TWCoinTypeBitcoin)}, Hash::HasherSha256ripemd); + const auto addressUncomp = Address(keyHash).string(); + EXPECT_EQ(addressUncomp, "1E4T9JZ3mq6cdgiRJEWzHqDXb9t322fE6d"); + { + const auto msg = "test signature"; + const auto signature = MessageSigner::signMessage(gPrivateKey, addressUncomp, msg, false); + EXPECT_EQ(signature, "HLH5K7JQLaRGaKGXXH5mYM6FIIy9IWyY4JUPI+PHYY4WaupxUbg+zy0bhBCrDuehy9x4WidwjkRR1GSLnWvOXBo="); + + EXPECT_TRUE(MessageSigner::verifyMessage(addressUncomp, msg, signature)); + } +} + +TEST(BitcoinMessageSigner, SignNegative) { + const auto address = Address(gPrivateKey.getPublicKey(TWPublicKeyTypeSECP256k1), TW::p2pkhPrefix(TWCoinTypeBitcoin)).string(); + EXPECT_EQ(address, "19cAJn4Ms8jodBBGtroBNNpCZiHAWGAq7X"); + const auto msg = "test signature"; + // Use invalid address + EXPECT_EXCEPTION(MessageSigner::signMessage(gPrivateKey, "__THIS_IS_NOT_A_VALID_ADDRESS__", msg), "Address is not valid (legacy) address"); + // Use invalid address, not legacy + EXPECT_EXCEPTION(MessageSigner::signMessage(gPrivateKey, "bc1qpjult34k9spjfym8hss2jrwjgf0xjf40ze0pp8", msg), "Address is not valid (legacy) address"); + // Use valid, but not matching key + EXPECT_EXCEPTION(MessageSigner::signMessage(gPrivateKey, "1B8Qea79tsxmn4dTiKKRVvsJpHwL2fMQnr", msg), "Address does not match key"); +} + +TEST(BitcoinMessageSigner, VerifyNegative) { + const auto sig = parse_hex("1fedcbe486d255c7a3a784b65702d70b12c43100160ef29b13c950caad2871dbf23356a812e764ccdfd2fea2c8def9cd38563a575dc15d6485acfaf73a319ae439"); + // Baseline positive + EXPECT_TRUE(MessageSigner::verifyMessage( + "1B8Qea79tsxmn4dTiKKRVvsJpHwL2fMQnr", + "test signature", + sig + )); + + // Provide non-matching address + EXPECT_FALSE(MessageSigner::verifyMessage( + "1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN", + "test signature", + sig + )); + // Signature too short + EXPECT_EXCEPTION(MessageSigner::verifyMessage( + "1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN", + "test signature", + parse_hex("1fedcbe486d255c7a3a784b65702d70b12c43100160ef29b13c950caad2871dbf23356a812e764ccdfd2fea2c8def9cd38563a575dc15d6485acfaf73a319ae4") + ), "signature too short"); + // Invalid address + EXPECT_EXCEPTION(MessageSigner::verifyMessage( + "__THIS_IS_NOT_A_VALID_ADDRESS__", + "test signature", + parse_hex("1fedcbe486d255c7a3a784b65702d70b12c43100160ef29b13c950caad2871dbf23356a812e764ccdfd2fea2c8def9cd38563a575dc15d6485acfaf73a319ae4") + ), "Input address invalid"); + EXPECT_EXCEPTION(MessageSigner::verifyMessage( + "bc1qpjult34k9spjfym8hss2jrwjgf0xjf40ze0pp8", + "test signature", + parse_hex("1fedcbe486d255c7a3a784b65702d70b12c43100160ef29b13c950caad2871dbf23356a812e764ccdfd2fea2c8def9cd38563a575dc15d6485acfaf73a319ae4") + ), "Input address invalid"); +} + +TEST(BitcoinMessageSigner, MessageToHash) { + EXPECT_EQ(hex(MessageSigner::messageToHash("Hello, world!")), "02d6c0643e40b0db549cbbd7eb47dcab71a59d7017199ebde6b272f28fbbf95f"); + EXPECT_EQ(hex(MessageSigner::messageToHash("test signature")), "8e81cc5bca9862d8b7f22be1f7cb762b49121cf4e1611c27906a041f9a9eb21f"); +} + +TEST(TWBitcoinMessageSigner, VerifyMessage) { + EXPECT_TRUE(TWBitcoinMessageSignerVerifyMessage( + STRING("1B8Qea79tsxmn4dTiKKRVvsJpHwL2fMQnr").get(), + STRING("test signature").get(), + STRING("H+3L5IbSVcejp4S2VwLXCxLEMQAWDvKbE8lQyq0ocdvyM1aoEudkzN/S/qLI3vnNOFY6V13BXWSFrPr3OjGa5Dk=").get() + )); +} + +TEST(TWBitcoinMessageSigner, SignAndVerify) { + const auto privKeyData = "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5"; + const auto privateKey = WRAP(TWPrivateKey, TWPrivateKeyCreateWithData(DATA(privKeyData).get())); + const auto address = STRING("19cAJn4Ms8jodBBGtroBNNpCZiHAWGAq7X"); + const auto message = STRING("test signature"); + + const auto signature = WRAPS(TWBitcoinMessageSignerSignMessage(privateKey.get(), address.get(), message.get())); + EXPECT_EQ(std::string(TWStringUTF8Bytes(signature.get())), "ILH5K7JQLaRGaKGXXH5mYM6FIIy9IWyY4JUPI+PHYY4WaupxUbg+zy0bhBCrDuehy9x4WidwjkRR1GSLnWvOXBo="); + + EXPECT_TRUE(TWBitcoinMessageSignerVerifyMessage(address.get(), message.get(), signature.get())); +} + +} // namespace TW::Bitcoin diff --git a/tests/PublicKeyTests.cpp b/tests/PublicKeyTests.cpp index 1154e3d8d6f..a9e2f09d115 100644 --- a/tests/PublicKeyTests.cpp +++ b/tests/PublicKeyTests.cpp @@ -250,6 +250,58 @@ TEST(PublicKeyTests, VerifySchnorrWrongType) { EXPECT_FALSE(publicKey.verifyZilliqa(signature, digest)); } +TEST(PublicKeyTests, RecoverRaw) { + { + const auto message = parse_hex("de4e9524586d6fce45667f9ff12f661e79870c4105fa0fb58af976619bb11432"); + const auto signature = parse_hex("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"); + { + const auto publicKey = PublicKey::recoverRaw(signature, 1ul, message); + EXPECT_EQ(publicKey.type, TWPublicKeyTypeSECP256k1Extended); + EXPECT_EQ(hex(publicKey.bytes), "0456d8089137b1fd0d890f8c7d4a04d0fd4520a30b19518ee87bd168ea12ed8090329274c4c6c0d9df04515776f2741eeffc30235d596065d718c3973e19711ad0"); + } + { // same data but different recId -> different result + const auto publicKey = PublicKey::recoverRaw(signature, 0ul, message); + EXPECT_EQ(publicKey.type, TWPublicKeyTypeSECP256k1Extended); + EXPECT_EQ(hex(publicKey.bytes), "043fc5bf5fec35b6ffe6fd246226d312742a8c296bfa57dd22da509a2e348529b7ddb9faf8afe1ecda3c05e7b2bda47ee1f5a87e952742b22afca560b29d972fcf"); + } + } + { + const auto message = parse_hex("6468eb103d51c9a683b51818fdb73390151c9973831d2cfb4e9587ad54273155"); + const auto signature = parse_hex("92c336138f7d0231fe9422bb30ee9ef10bf222761fe9e04442e3a11e88880c646487026011dae03dc281bc21c7d7ede5c2226d197befb813a4ecad686b559e58"); + const auto recovered = PublicKey::recoverRaw(signature, 0ul, message); + EXPECT_EQ(hex(recovered.bytes), "0463ade8ebc212b85e7e4278dc3dcb4f9cc18aab912ef5d302b5d1940e772e9e1a9213522efddad487bbd5dd7907e8e776f918e9a5e4cb51893724e9fe76792a4f"); + } +} + +TEST(PublicKeyTests, SignAndRecoverRaw) { + const auto privateKey = PrivateKey(parse_hex("4f96ed80e9a7555a6f74b3d658afdd9c756b0a40d4ca30c42c2039eb449bb904")); + const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended); + EXPECT_EQ(hex(publicKey.bytes), "0463ade8ebc212b85e7e4278dc3dcb4f9cc18aab912ef5d302b5d1940e772e9e1a9213522efddad487bbd5dd7907e8e776f918e9a5e4cb51893724e9fe76792a4f"); + const auto message = parse_hex("6468eb103d51c9a683b51818fdb73390151c9973831d2cfb4e9587ad54273155"); + + // sign + const auto signature = privateKey.sign(message, TWCurveSECP256k1); + EXPECT_EQ(hex(signature), "92c336138f7d0231fe9422bb30ee9ef10bf222761fe9e04442e3a11e88880c646487026011dae03dc281bc21c7d7ede5c2226d197befb813a4ecad686b559e5800"); + + // revocer + const auto pubkeyRecovered = PublicKey::recoverRaw(signature, signature[64], message); + EXPECT_EQ(hex(pubkeyRecovered.bytes), hex(publicKey.bytes)); + EXPECT_EQ(hex(pubkeyRecovered.bytes), "0463ade8ebc212b85e7e4278dc3dcb4f9cc18aab912ef5d302b5d1940e772e9e1a9213522efddad487bbd5dd7907e8e776f918e9a5e4cb51893724e9fe76792a4f"); +} + +TEST(PublicKeyTests, RecoverRawNegative) { + const auto message = parse_hex("de4e9524586d6fce45667f9ff12f661e79870c4105fa0fb58af976619bb11432"); + const auto signature = parse_hex("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"); + // recid >= 4 + EXPECT_EXCEPTION(PublicKey::recoverRaw(signature, 4ul, message), "Invalid recId"); + // signature too short + EXPECT_EXCEPTION(PublicKey::recoverRaw(parse_hex("00000000000000000000000000000000000000000000000000000000000000020123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"), 1ul, message), + "signature too short"); + // Digest too short + EXPECT_EXCEPTION(PublicKey::recoverRaw(signature, 1ul, parse_hex("de4e9524586d6fce45667f9ff12f661e79870c4105fa0fb58af976619bb114")), + "digest too short"); +} + TEST(PublicKeyTests, Recover) { { const auto message = parse_hex("de4e9524586d6fce45667f9ff12f661e79870c4105fa0fb58af976619bb11432"); From ff9e87007b1448a25f886cc1ebe43ed884d586f3 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 10 Oct 2022 11:52:20 +0200 Subject: [PATCH 107/497] [Misc]: Update Package.swift to 3.0.6 targets #2630 --- Package.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Package.swift b/Package.swift index 7da39e00a9d..7f6216bde07 100644 --- a/Package.swift +++ b/Package.swift @@ -12,13 +12,13 @@ let package = Package( targets: [ .binaryTarget( name: "WalletCore", - url: "https://github.com/trustwallet/wallet-core/releases/download/2.9.5/WalletCore.xcframework.zip", - checksum: "bb3bccd29e4f03c58bfa1fd746a0f8d6fc4ffc9ec2183beb4facd7b01974a9a2" + url: "https://github.com/trustwallet/wallet-core/releases/download/3.0.6/WalletCore.xcframework.zip", + checksum: "a3df0c2b30fc59ede0a2600266fc19b8c0cf655dbef3fb832488c8ddedcb6b93" ), .binaryTarget( name: "SwiftProtobuf", - url: "https://github.com/trustwallet/wallet-core/releases/download/2.9.5/SwiftProtobuf.xcframework.zip", - checksum: "7903f5e9487db4764dc57be000c384a0619a96c275993711f3a5a858d3c865bd" + url: "https://github.com/trustwallet/wallet-core/releases/download/3.0.6/SwiftProtobuf.xcframework.zip", + checksum: "61fa8483d4bd43f1898db6997eff0279426f15f9e518e12db0d762ec5f927a9b" ) ] ) From 3d1aaf076fb6f783a5b84b2aa30c24c4e5d7d6d0 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Tue, 11 Oct 2022 17:11:07 +0200 Subject: [PATCH 108/497] [TestOnly] `tests` folder reorg (#2627) --- codegen/bin/newcoin | 8 ++-- codegen/lib/coin_test_gen.rb | 2 +- codegen/lib/templates/TWCoinTypeTests.cpp.erb | 2 +- .../templates/newcoin/TWAddressTests.cpp.erb | 2 +- .../templates/newcoin/TWSignerTests.cpp.erb | 2 +- swift/Tests/Blockchains/Data | 2 +- tests/CMakeLists.txt | 1 + tests/{ => chains}/Aeternity/AddressTests.cpp | 0 tests/{ => chains}/Aeternity/SignerTests.cpp | 0 .../Aeternity/TWAeternityAddressTests.cpp | 2 +- .../Aeternity/TWAnySignerTests.cpp | 2 +- .../Aeternity/TWCoinTypeTests.cpp | 2 +- .../Aeternity/TransactionTests.cpp | 2 +- tests/{ => chains}/Aion/AddressTests.cpp | 0 tests/{ => chains}/Aion/RLPTests.cpp | 0 tests/{ => chains}/Aion/SignerTests.cpp | 0 tests/{ => chains}/Aion/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Aion/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Aion/TransactionTests.cpp | 0 tests/{ => chains}/Algorand/AddressTests.cpp | 0 tests/{ => chains}/Algorand/SignerTests.cpp | 0 .../Algorand/TWAnySignerTests.cpp | 2 +- .../{ => chains}/Algorand/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Aptos/AddressTests.cpp | 0 tests/{ => chains}/Aptos/MoveTypesTests.cpp | 0 tests/{ => chains}/Aptos/SignerTests.cpp | 2 +- tests/{ => chains}/Aptos/TWAnySignerTests.cpp | 2 +- .../Aptos/TWAptosAddressTests.cpp | 2 +- tests/{ => chains}/Aptos/TWCoinTypeTests.cpp | 2 +- .../Aptos/TransactionPayloadTests.cpp | 0 .../{ => chains}/Arbitrum/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Aurora/TWCoinTypeTests.cpp | 2 +- .../Avalanche/TWCoinTypeTests.cpp | 2 +- .../BandChain/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Binance/SignerTests.cpp | 0 .../{ => chains}/Binance/TWAnySignerTests.cpp | 2 +- .../{ => chains}/Binance/TWCoinTypeTests.cpp | 2 +- .../BinanceSmartChain/SignerTests.cpp | 2 +- .../BinanceSmartChain/TWAnyAddressTests.cpp | 2 +- .../BinanceSmartChain/TWCoinTypeTests.cpp | 2 +- .../Bitcoin/BitcoinAddressTests.cpp | 0 .../Bitcoin/BitcoinScriptTests.cpp | 2 +- .../Bitcoin/FeeCalculatorTests.cpp | 0 .../Bitcoin/InputSelectorTests.cpp | 0 .../Bitcoin/MessageSignerTests.cpp | 1 - .../Bitcoin/SegwitAddressTests.cpp | 0 .../Bitcoin/TWBitcoinAddressTests.cpp | 2 +- .../Bitcoin/TWBitcoinScriptTests.cpp | 2 +- .../Bitcoin/TWBitcoinSigningTests.cpp | 0 .../Bitcoin/TWBitcoinTransactionTests.cpp | 0 .../{ => chains}/Bitcoin/TWCoinTypeTests.cpp | 2 +- .../Bitcoin/TWSegwitAddressTests.cpp | 2 +- .../Bitcoin/TransactionPlanTests.cpp | 0 .../Bitcoin/TxComparisonHelper.cpp | 0 .../{ => chains}/Bitcoin/TxComparisonHelper.h | 0 .../BitcoinCash/TWBitcoinCashTests.cpp | 2 +- .../BitcoinCash/TWCoinTypeTests.cpp | 2 +- .../BitcoinGold/TWAddressTests.cpp | 2 +- .../BitcoinGold/TWBitcoinGoldTests.cpp | 2 +- .../BitcoinGold/TWCoinTypeTests.cpp | 2 +- .../BitcoinGold/TWSegwitAddressTests.cpp | 2 +- .../BitcoinGold/TWSignerTests.cpp | 2 +- .../{ => chains}/Bluzelle/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Boba/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/Callisto/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Cardano/AddressTests.cpp | 0 tests/{ => chains}/Cardano/SigningTests.cpp | 2 +- tests/{ => chains}/Cardano/StakingTests.cpp | 2 +- .../Cardano/TWCardanoAddressTests.cpp | 2 +- .../{ => chains}/Cardano/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/Cardano/TransactionTests.cpp | 0 tests/{ => chains}/Celo/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Cosmos/AddressTests.cpp | 0 tests/{ => chains}/Cosmos/Protobuf/.gitignore | 0 .../Cosmos/Protobuf/Article.proto | 0 tests/{ => chains}/Cosmos/ProtobufTests.cpp | 2 +- tests/{ => chains}/Cosmos/SignerTests.cpp | 2 +- tests/{ => chains}/Cosmos/StakingTests.cpp | 2 +- .../{ => chains}/Cosmos/TWAnyAddressTests.cpp | 2 +- .../{ => chains}/Cosmos/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Cosmos/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/Cronos/TWAnyAddressTests.cpp | 2 +- tests/{ => chains}/Cronos/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/CryptoOrg/AddressTests.cpp | 0 tests/{ => chains}/CryptoOrg/SignerTests.cpp | 2 +- .../CryptoOrg/TWAnyAddressTests.cpp | 2 +- .../CryptoOrg/TWAnySignerTests.cpp | 2 +- .../CryptoOrg/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Dash/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Dash/TWDashTests.cpp | 2 +- tests/{ => chains}/Decred/AddressTests.cpp | 0 tests/{ => chains}/Decred/SignerTests.cpp | 0 .../{ => chains}/Decred/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Decred/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Decred/TWDecredTests.cpp | 2 +- .../{ => chains}/DigiByte/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/DigiByte/TWDigiByteTests.cpp | 2 +- .../{ => chains}/Dogecoin/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Dogecoin/TWDogeTests.cpp | 2 +- tests/{ => chains}/ECO/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/ECash/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/ECash/TWECashTests.cpp | 2 +- tests/{ => chains}/EOS/AddressTests.cpp | 0 tests/{ => chains}/EOS/AssetTests.cpp | 0 tests/{ => chains}/EOS/NameTests.cpp | 0 tests/{ => chains}/EOS/SignatureTests.cpp | 0 tests/{ => chains}/EOS/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/EOS/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/EOS/TransactionTests.cpp | 0 tests/{ => chains}/Elrond/AddressTests.cpp | 0 .../Elrond/SerializationTests.cpp | 0 tests/{ => chains}/Elrond/SignerTests.cpp | 0 .../{ => chains}/Elrond/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Elrond/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Elrond/TestAccounts.h | 0 .../Elrond/TransactionFactoryTests.cpp | 0 .../{ => chains}/Ethereum/AbiStructTests.cpp | 14 +++---- tests/{ => chains}/Ethereum/AbiTests.cpp | 2 +- tests/{ => chains}/Ethereum/AddressTests.cpp | 0 .../Ethereum/ContractCallTests.cpp | 22 +++++----- tests/{ => chains}/Ethereum/Data/1inch.json | 0 tests/{ => chains}/Ethereum/Data/custom.json | 0 .../Ethereum/Data/eip712_cryptofights.json | 0 .../Ethereum/Data/eip712_emptyArray.json | 0 .../Ethereum/Data/eip712_emptyString.json | 0 .../Ethereum/Data/eip712_rarible.json | 0 .../Ethereum/Data/eip712_snapshot_v4.json | 0 .../Ethereum/Data/eip712_walletconnect.json | 0 tests/{ => chains}/Ethereum/Data/ens.json | 0 tests/{ => chains}/Ethereum/Data/erc20.json | 0 tests/{ => chains}/Ethereum/Data/erc721.json | 0 .../Ethereum/Data/eth_feeHistory.json | 0 .../Ethereum/Data/eth_feeHistory2.json | 0 .../Ethereum/Data/eth_feeHistory3.json | 0 .../Ethereum/Data/eth_feeHistory4.json | 0 .../Ethereum/Data/getAmountsOut.json | 0 .../Ethereum/Data/kyber_proxy.json | 0 .../Ethereum/Data/seaport_712.json | 0 .../Ethereum/Data/tuple_nested.json | 0 .../Ethereum/Data/uniswap_router_v2.json | 0 .../Ethereum/Data/zilliqa_data_tx.json | 0 tests/{ => chains}/Ethereum/RLPTests.cpp | 0 tests/{ => chains}/Ethereum/SignerTests.cpp | 0 .../Ethereum/TWAnySignerTests.cpp | 2 +- .../{ => chains}/Ethereum/TWCoinTypeTests.cpp | 2 +- .../Ethereum/TWEthereumAbiTests.cpp | 2 +- .../TWEthereumAbiValueDecoderTests.cpp | 2 +- .../TWEthereumAbiValueEncodeTests.cpp | 2 +- .../Ethereum/ValueDecoderTests.cpp | 0 .../Ethereum/ValueEncoderTests.cpp | 0 .../EthereumClassic/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Everscale/AddressTests.cpp | 0 .../Everscale/CellBuilderTest.cpp | 0 tests/{ => chains}/Everscale/CellTests.cpp | 0 tests/{ => chains}/Everscale/SignerTests.cpp | 0 .../Everscale/TWAnyAddressTests.cpp | 2 +- .../Everscale/TWAnySignerTests.cpp | 2 +- .../Everscale/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Evmos/SignerTests.cpp | 2 +- .../{ => chains}/Evmos/TWAnyAddressTests.cpp | 2 +- tests/{ => chains}/Evmos/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/FIO/AddressTests.cpp | 0 tests/{ => chains}/FIO/EncryptionTests.cpp | 0 tests/{ => chains}/FIO/SignerTests.cpp | 0 tests/{ => chains}/FIO/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/FIO/TWFIOAccountTests.cpp | 2 +- tests/{ => chains}/FIO/TWFIOTests.cpp | 2 +- .../FIO/TransactionBuilderTests.cpp | 0 tests/{ => chains}/Fantom/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Filecoin/AddressTests.cpp | 0 tests/{ => chains}/Filecoin/SignerTests.cpp | 0 .../Filecoin/TWAnySignerTests.cpp | 2 +- .../{ => chains}/Filecoin/TWCoinTypeTests.cpp | 2 +- .../Filecoin/TransactionTests.cpp | 0 tests/{ => chains}/Firo/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/Firo/TWZCoinAddressTests.cpp | 2 +- .../{ => chains}/GoChain/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/Groestlcoin/AddressTests.cpp | 0 .../Groestlcoin/TWCoinTypeTests.cpp | 2 +- .../Groestlcoin/TWGroestlcoinSigningTests.cpp | 2 +- .../Groestlcoin/TWGroestlcoinTests.cpp | 2 +- tests/{ => chains}/Harmony/AddressTests.cpp | 0 tests/{ => chains}/Harmony/SignerTests.cpp | 0 tests/{ => chains}/Harmony/StakingTests.cpp | 0 .../Harmony/TWAnyAddressTests.cpp | 2 +- .../{ => chains}/Harmony/TWAnySignerTests.cpp | 2 +- .../{ => chains}/Harmony/TWCoinTypeTests.cpp | 2 +- .../Harmony/TWHarmonyStakingTests.cpp | 2 +- tests/{Icon => chains/ICON}/AddressTests.cpp | 0 .../ICON}/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/ICON/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/IoTeX/AddressTests.cpp | 0 tests/{ => chains}/IoTeX/SignerTests.cpp | 0 tests/{ => chains}/IoTeX/StakingTests.cpp | 2 +- tests/{ => chains}/IoTeX/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/IoTeX/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Kava/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/KavaEvm/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Kin/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Klaytn/TWCoinTypeTests.cpp | 2 +- .../KuCoinCommunityChain/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Kusama/AddressTests.cpp | 0 tests/{ => chains}/Kusama/SignerTests.cpp | 0 .../{ => chains}/Kusama/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Kusama/TWCoinTypeTests.cpp | 2 +- .../Litecoin/LitecoinAddressTests.cpp | 0 .../{ => chains}/Litecoin/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/Litecoin/TWLitecoinTests.cpp | 2 +- tests/{ => chains}/Meter/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Metis/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/Monacoin/TWCoinTypeTests.cpp | 2 +- .../Monacoin/TWMonacoinAddressTests.cpp | 2 +- .../Monacoin/TWMonacoinTransactionTests.cpp | 2 +- .../{ => chains}/Moonbeam/TWCoinTypeTests.cpp | 2 +- .../Moonriver/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/NEAR/AccountTests.cpp | 0 tests/{ => chains}/NEAR/AddressTests.cpp | 0 .../{ => chains}/NEAR/SerializationTests.cpp | 0 tests/{ => chains}/NEAR/SignerTests.cpp | 0 tests/{ => chains}/NEAR/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/NEAR/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/NEAR/TWNEARAccountTests.cpp | 2 +- tests/{ => chains}/NEO/AddressTests.cpp | 0 tests/{ => chains}/NEO/CoinReferenceTests.cpp | 0 tests/{ => chains}/NEO/SignerTests.cpp | 0 tests/{ => chains}/NEO/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/NEO/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/NEO/TWNEOAddressTests.cpp | 2 +- .../NEO/TransactionAttributeTests.cpp | 0 .../NEO/TransactionOutputTests.cpp | 0 tests/{ => chains}/NEO/TransactionTests.cpp | 0 tests/{ => chains}/NEO/WitnessTests.cpp | 0 tests/{ => chains}/NULS/AddressTests.cpp | 0 tests/{ => chains}/NULS/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/NULS/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Nano/AddressTests.cpp | 0 tests/{ => chains}/Nano/SignerTests.cpp | 0 tests/{ => chains}/Nano/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Nano/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/Nano/TWNanoAddressTests.cpp | 2 +- .../NativeEvmos/TWAnyAddressTests.cpp | 2 +- .../NativeEvmos/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Nebulas/AddressTests.cpp | 0 tests/{ => chains}/Nebulas/SignerTests.cpp | 0 .../{ => chains}/Nebulas/TWAnySignerTests.cpp | 2 +- .../{ => chains}/Nebulas/TWCoinTypeTests.cpp | 2 +- .../Nebulas/TWNebulasAddressTests.cpp | 2 +- .../{ => chains}/Nebulas/TransactionTests.cpp | 0 tests/{ => chains}/Nervos/AddressTests.cpp | 0 tests/{ => chains}/Nervos/SignerTests.cpp | 2 +- .../{ => chains}/Nervos/TWAnyAddressTests.cpp | 2 +- .../{ => chains}/Nervos/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Nervos/TWCoinTypeTests.cpp | 2 +- .../Nervos/TWNervosAddressTests.cpp | 2 +- tests/{ => chains}/Nimiq/AddressTests.cpp | 0 tests/{ => chains}/Nimiq/SignerTests.cpp | 0 tests/{ => chains}/Nimiq/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Nimiq/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Nimiq/TransactionTests.cpp | 0 .../{ => chains}/OKXChain/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Oasis/AddressTests.cpp | 0 tests/{ => chains}/Oasis/SignerTests.cpp | 0 tests/{ => chains}/Oasis/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Oasis/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Ontology/AccountTests.cpp | 0 tests/{ => chains}/Ontology/AddressTests.cpp | 0 tests/{ => chains}/Ontology/Oep4Tests.cpp | 0 tests/{ => chains}/Ontology/OngTests.cpp | 0 tests/{ => chains}/Ontology/OntTests.cpp | 0 .../Ontology/ParamsBuilderTests.cpp | 0 .../Ontology/TWAnySignerTests.cpp | 2 +- .../{ => chains}/Ontology/TWCoinTypeTests.cpp | 2 +- .../Ontology/TransactionTests.cpp | 0 .../{ => chains}/Optimism/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Osmosis/AddressTests.cpp | 0 tests/{ => chains}/Osmosis/SignerTests.cpp | 2 +- .../Osmosis/TWAnyAddressTests.cpp | 2 +- .../{ => chains}/Osmosis/TWAnySignerTests.cpp | 2 +- .../{ => chains}/Osmosis/TWCoinTypeTests.cpp | 2 +- .../POANetwork/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Polkadot/AddressTests.cpp | 0 .../Polkadot/SS58AddressTests.cpp | 2 +- .../{ => chains}/Polkadot/ScaleCodecTests.cpp | 0 tests/{ => chains}/Polkadot/SignerTests.cpp | 0 .../{ => chains}/Polkadot/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/Polygon/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Qtum/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/Qtum/TWQtumAddressTests.cpp | 2 +- .../Ravencoin/TWCoinTypeTests.cpp | 2 +- .../Ravencoin/TWRavencoinTransactionTests.cpp | 2 +- .../{ => chains}/Ronin/TWAnyAddressTests.cpp | 2 +- tests/{ => chains}/Ronin/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Ronin/TWCoinTypeTests.cpp | 2 +- .../SmartBitcoinCash/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Solana/AddressTests.cpp | 0 tests/{ => chains}/Solana/ProgramTests.cpp | 0 tests/{ => chains}/Solana/SignerTests.cpp | 0 .../{ => chains}/Solana/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Solana/TWCoinTypeTests.cpp | 2 +- .../Solana/TWSolanaAddressTests.cpp | 2 +- .../{ => chains}/Solana/TransactionTests.cpp | 0 tests/{ => chains}/Stellar/AddressTests.cpp | 0 .../{ => chains}/Stellar/TWAnySignerTests.cpp | 2 +- .../{ => chains}/Stellar/TWCoinTypeTests.cpp | 2 +- .../Stellar/TWStellarAddressTests.cpp | 2 +- .../{ => chains}/Stellar/TransactionTests.cpp | 2 +- tests/{ => chains}/THORChain/SignerTests.cpp | 2 +- tests/{ => chains}/THORChain/SwapTests.cpp | 2 +- .../THORChain/TWAnyAddressTests.cpp | 2 +- .../THORChain/TWAnySignerTests.cpp | 2 +- .../THORChain/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/THORChain/TWSwapTests.cpp | 2 +- tests/{ => chains}/Terra/SignerTests.cpp | 2 +- tests/{ => chains}/Terra/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/TerraV2/SignerTests.cpp | 2 +- .../{ => chains}/TerraV2/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Tezos/AddressTests.cpp | 0 tests/{ => chains}/Tezos/ForgingTests.cpp | 0 .../{ => chains}/Tezos/OperationListTests.cpp | 0 tests/{ => chains}/Tezos/PublicKeyTests.cpp | 0 tests/{ => chains}/Tezos/SignerTests.cpp | 0 tests/{ => chains}/Tezos/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Tezos/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Theta/SignerTests.cpp | 0 tests/{ => chains}/Theta/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Theta/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Theta/TransactionTests.cpp | 0 .../ThunderToken/TWCoinTypeTests.cpp | 2 +- .../TomoChain/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Tron/AddressTests.cpp | 0 .../{ => chains}/Tron/SerializationTests.cpp | 0 tests/{ => chains}/Tron/SignerTests.cpp | 0 tests/{ => chains}/Tron/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Tron/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/VeChain/SignerTests.cpp | 0 .../{ => chains}/VeChain/TWAnySignerTests.cpp | 2 +- .../{ => chains}/VeChain/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/Viacoin/TWCoinTypeTests.cpp | 2 +- .../Viacoin/TWViacoinAddressTests.cpp | 2 +- .../{ => chains}/Wanchain/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Waves/AddressTests.cpp | 0 tests/{ => chains}/Waves/LeaseTests.cpp | 0 tests/{ => chains}/Waves/SignerTests.cpp | 0 tests/{ => chains}/Waves/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/Waves/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/Waves/TransactionTests.cpp | 0 tests/{ => chains}/XRP/AddressTests.cpp | 0 tests/{ => chains}/XRP/TWAnySignerTests.cpp | 2 +- tests/{ => chains}/XRP/TWCoinTypeTests.cpp | 2 +- .../{ => chains}/XRP/TWRippleAddressTests.cpp | 2 +- tests/{ => chains}/XRP/TransactionTests.cpp | 0 tests/{ => chains}/Zcash/AddressTests.cpp | 0 tests/{ => chains}/Zcash/TWCoinTypeTests.cpp | 2 +- .../Zcash/TWZcashAddressTests.cpp | 2 +- .../Zcash/TWZcashTransactionTests.cpp | 2 +- .../{ => chains}/Zelcash/TWCoinTypeTests.cpp | 2 +- .../Zelcash/TWZelcashAddressTests.cpp | 2 +- .../Zelcash/TWZelcashTransactionTests.cpp | 2 +- tests/{ => chains}/Zilliqa/AddressTests.cpp | 0 tests/{ => chains}/Zilliqa/SignatureTests.cpp | 2 +- tests/{ => chains}/Zilliqa/SignerTests.cpp | 0 .../{ => chains}/Zilliqa/TWAnySignerTests.cpp | 2 +- .../{ => chains}/Zilliqa/TWCoinTypeTests.cpp | 2 +- .../Zilliqa/TWZilliqaAddressTests.cpp | 2 +- .../{ => chains}/ZkSyncV2/TWCoinTypeTests.cpp | 2 +- tests/{ => chains}/xDai/TWCoinTypeTests.cpp | 2 +- tests/{ => common}/AnyAddressTests.cpp | 0 tests/{ => common}/BCSTests.cpp | 0 tests/{ => common}/Base64Tests.cpp | 0 tests/{ => common}/BaseEncoding.cpp | 0 tests/{ => common}/Bech32AddressTests.cpp | 0 tests/{ => common}/Bech32Tests.cpp | 0 tests/{ => common}/BinaryCodingTests.cpp | 0 tests/{ => common}/CborTests.cpp | 0 .../CoinAddressDerivationTests.cpp | 0 .../CoinAddressValidationTests.cpp | 0 tests/{ => common}/DataTests.cpp | 0 tests/{ => common}/EncryptTests.cpp | 0 .../HDWallet/HDWalletInternalTests.cpp | 2 +- tests/{ => common}/HDWallet/HDWalletTests.cpp | 4 +- .../{ => common}/HDWallet/bip39_vectors.json | 0 tests/{ => common}/HashTests.cpp | 0 tests/{ => common}/HexCodingTests.cpp | 0 .../Keystore/Data/empty-accounts.json | 0 .../Data/ethereum-wallet-address-no-0x.json | 0 tests/{ => common}/Keystore/Data/key.json | 0 .../Keystore/Data/key_bitcoin.json | 0 .../Keystore/Data/legacy-mnemonic.json | 0 .../Keystore/Data/legacy-private-key.json | 0 .../{ => common}/Keystore/Data/livepeer.json | 0 .../Keystore/Data/missing-address.json | 0 .../Keystore/Data/myetherwallet.uu | 0 tests/{ => common}/Keystore/Data/pbkdf2.json | 0 tests/{ => common}/Keystore/Data/wallet.json | 0 tests/{ => common}/Keystore/Data/watch.json | 0 tests/{ => common}/Keystore/Data/web3j.json | 0 .../Keystore/DerivationPathTests.cpp | 0 .../{ => common}/Keystore/StoredKeyTests.cpp | 40 ++++++++++--------- tests/{ => common}/MnemonicTests.cpp | 0 tests/{ => common}/NumericLiteralTests.cpp | 0 tests/{ => common}/PrivateKeyTests.cpp | 0 tests/{ => common}/PublicKeyTests.cpp | 2 +- .../TestUtilities.cpp} | 2 +- .../TestUtilities.h} | 0 .../{ => common}/TransactionCompilerTests.cpp | 2 +- tests/{ => common}/Uint256Tests.cpp | 0 tests/{ => common}/WalletConsoleTests.cpp | 0 tests/{ => common}/algorithm/erase_tests.cpp | 0 .../algorithm/sort_copy_tests.cpp | 0 .../{ => common}/algorithm/to_array_tests.cpp | 0 tests/{ => common}/memory/memzero_tests.cpp | 0 .../operators/equality_comparable_tests.cpp | 0 tests/interface/TWAESTests.cpp | 2 +- tests/interface/TWAccountTests.cpp | 2 +- tests/interface/TWAnyAddressTests.cpp | 2 +- tests/interface/TWBase32Tests.cpp | 2 +- tests/interface/TWBase58Tests.cpp | 2 +- tests/interface/TWBase64Tests.cpp | 2 +- tests/interface/TWCoinTypeTests.cpp | 2 +- tests/interface/TWDataTests.cpp | 2 +- tests/interface/TWDataVectorTests.cpp | 2 +- tests/interface/TWDerivationPathTests.cpp | 2 +- tests/interface/TWHDWalletTests.cpp | 2 +- tests/interface/TWHRPTests.cpp | 2 +- tests/interface/TWHashTests.cpp | 2 +- tests/interface/TWMnemonicTests.cpp | 2 +- tests/interface/TWPBKDF2Tests.cpp | 2 +- tests/interface/TWPrivateKeyTests.cpp | 2 +- tests/interface/TWPublicKeyTests.cpp | 2 +- tests/interface/TWStoredKeyTests.cpp | 4 +- tests/interface/TWStringTests.cpp | 2 +- .../interface/TWTransactionCompilerTests.cpp | 2 +- tools/generate-files | 2 +- 433 files changed, 289 insertions(+), 285 deletions(-) rename tests/{ => chains}/Aeternity/AddressTests.cpp (100%) rename tests/{ => chains}/Aeternity/SignerTests.cpp (100%) rename tests/{ => chains}/Aeternity/TWAeternityAddressTests.cpp (96%) rename tests/{ => chains}/Aeternity/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/Aeternity/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Aeternity/TransactionTests.cpp (98%) rename tests/{ => chains}/Aion/AddressTests.cpp (100%) rename tests/{ => chains}/Aion/RLPTests.cpp (100%) rename tests/{ => chains}/Aion/SignerTests.cpp (100%) rename tests/{ => chains}/Aion/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/Aion/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Aion/TransactionTests.cpp (100%) rename tests/{ => chains}/Algorand/AddressTests.cpp (100%) rename tests/{ => chains}/Algorand/SignerTests.cpp (100%) rename tests/{ => chains}/Algorand/TWAnySignerTests.cpp (98%) rename tests/{ => chains}/Algorand/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Aptos/AddressTests.cpp (100%) rename tests/{ => chains}/Aptos/MoveTypesTests.cpp (100%) rename tests/{ => chains}/Aptos/SignerTests.cpp (99%) rename tests/{ => chains}/Aptos/TWAnySignerTests.cpp (98%) rename tests/{ => chains}/Aptos/TWAptosAddressTests.cpp (96%) rename tests/{ => chains}/Aptos/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Aptos/TransactionPayloadTests.cpp (100%) rename tests/{ => chains}/Arbitrum/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Aurora/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Avalanche/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/BandChain/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Binance/SignerTests.cpp (100%) rename tests/{ => chains}/Binance/TWAnySignerTests.cpp (99%) rename tests/{ => chains}/Binance/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/BinanceSmartChain/SignerTests.cpp (98%) rename tests/{ => chains}/BinanceSmartChain/TWAnyAddressTests.cpp (96%) rename tests/{ => chains}/BinanceSmartChain/TWCoinTypeTests.cpp (98%) rename tests/{ => chains}/Bitcoin/BitcoinAddressTests.cpp (100%) rename tests/{ => chains}/Bitcoin/BitcoinScriptTests.cpp (99%) rename tests/{ => chains}/Bitcoin/FeeCalculatorTests.cpp (100%) rename tests/{ => chains}/Bitcoin/InputSelectorTests.cpp (100%) rename tests/{ => chains}/Bitcoin/MessageSignerTests.cpp (99%) rename tests/{ => chains}/Bitcoin/SegwitAddressTests.cpp (100%) rename tests/{ => chains}/Bitcoin/TWBitcoinAddressTests.cpp (98%) rename tests/{ => chains}/Bitcoin/TWBitcoinScriptTests.cpp (99%) rename tests/{ => chains}/Bitcoin/TWBitcoinSigningTests.cpp (100%) rename tests/{ => chains}/Bitcoin/TWBitcoinTransactionTests.cpp (100%) rename tests/{ => chains}/Bitcoin/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Bitcoin/TWSegwitAddressTests.cpp (98%) rename tests/{ => chains}/Bitcoin/TransactionPlanTests.cpp (100%) rename tests/{ => chains}/Bitcoin/TxComparisonHelper.cpp (100%) rename tests/{ => chains}/Bitcoin/TxComparisonHelper.h (100%) rename tests/{ => chains}/BitcoinCash/TWBitcoinCashTests.cpp (99%) rename tests/{ => chains}/BitcoinCash/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/BitcoinGold/TWAddressTests.cpp (96%) rename tests/{ => chains}/BitcoinGold/TWBitcoinGoldTests.cpp (99%) rename tests/{ => chains}/BitcoinGold/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/BitcoinGold/TWSegwitAddressTests.cpp (98%) rename tests/{ => chains}/BitcoinGold/TWSignerTests.cpp (98%) rename tests/{ => chains}/Bluzelle/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Boba/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Callisto/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Cardano/AddressTests.cpp (100%) rename tests/{ => chains}/Cardano/SigningTests.cpp (99%) rename tests/{ => chains}/Cardano/StakingTests.cpp (99%) rename tests/{ => chains}/Cardano/TWCardanoAddressTests.cpp (99%) rename tests/{ => chains}/Cardano/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Cardano/TransactionTests.cpp (100%) rename tests/{ => chains}/Celo/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Cosmos/AddressTests.cpp (100%) rename tests/{ => chains}/Cosmos/Protobuf/.gitignore (100%) rename tests/{ => chains}/Cosmos/Protobuf/Article.proto (100%) rename tests/{ => chains}/Cosmos/ProtobufTests.cpp (98%) rename tests/{ => chains}/Cosmos/SignerTests.cpp (99%) rename tests/{ => chains}/Cosmos/StakingTests.cpp (99%) rename tests/{ => chains}/Cosmos/TWAnyAddressTests.cpp (95%) rename tests/{ => chains}/Cosmos/TWAnySignerTests.cpp (98%) rename tests/{ => chains}/Cosmos/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Cronos/TWAnyAddressTests.cpp (94%) rename tests/{ => chains}/Cronos/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/CryptoOrg/AddressTests.cpp (100%) rename tests/{ => chains}/CryptoOrg/SignerTests.cpp (99%) rename tests/{ => chains}/CryptoOrg/TWAnyAddressTests.cpp (96%) rename tests/{ => chains}/CryptoOrg/TWAnySignerTests.cpp (99%) rename tests/{ => chains}/CryptoOrg/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Dash/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Dash/TWDashTests.cpp (95%) rename tests/{ => chains}/Decred/AddressTests.cpp (100%) rename tests/{ => chains}/Decred/SignerTests.cpp (100%) rename tests/{ => chains}/Decred/TWAnySignerTests.cpp (99%) rename tests/{ => chains}/Decred/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Decred/TWDecredTests.cpp (98%) rename tests/{ => chains}/DigiByte/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/DigiByte/TWDigiByteTests.cpp (99%) rename tests/{ => chains}/Dogecoin/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Dogecoin/TWDogeTests.cpp (95%) rename tests/{ => chains}/ECO/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/ECash/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/ECash/TWECashTests.cpp (99%) rename tests/{ => chains}/EOS/AddressTests.cpp (100%) rename tests/{ => chains}/EOS/AssetTests.cpp (100%) rename tests/{ => chains}/EOS/NameTests.cpp (100%) rename tests/{ => chains}/EOS/SignatureTests.cpp (100%) rename tests/{ => chains}/EOS/TWAnySignerTests.cpp (98%) rename tests/{ => chains}/EOS/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/EOS/TransactionTests.cpp (100%) rename tests/{ => chains}/Elrond/AddressTests.cpp (100%) rename tests/{ => chains}/Elrond/SerializationTests.cpp (100%) rename tests/{ => chains}/Elrond/SignerTests.cpp (100%) rename tests/{ => chains}/Elrond/TWAnySignerTests.cpp (98%) rename tests/{ => chains}/Elrond/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Elrond/TestAccounts.h (100%) rename tests/{ => chains}/Elrond/TransactionFactoryTests.cpp (100%) rename tests/{ => chains}/Ethereum/AbiStructTests.cpp (99%) rename tests/{ => chains}/Ethereum/AbiTests.cpp (99%) rename tests/{ => chains}/Ethereum/AddressTests.cpp (100%) rename tests/{ => chains}/Ethereum/ContractCallTests.cpp (95%) rename tests/{ => chains}/Ethereum/Data/1inch.json (100%) rename tests/{ => chains}/Ethereum/Data/custom.json (100%) rename tests/{ => chains}/Ethereum/Data/eip712_cryptofights.json (100%) rename tests/{ => chains}/Ethereum/Data/eip712_emptyArray.json (100%) rename tests/{ => chains}/Ethereum/Data/eip712_emptyString.json (100%) rename tests/{ => chains}/Ethereum/Data/eip712_rarible.json (100%) rename tests/{ => chains}/Ethereum/Data/eip712_snapshot_v4.json (100%) rename tests/{ => chains}/Ethereum/Data/eip712_walletconnect.json (100%) rename tests/{ => chains}/Ethereum/Data/ens.json (100%) rename tests/{ => chains}/Ethereum/Data/erc20.json (100%) rename tests/{ => chains}/Ethereum/Data/erc721.json (100%) rename tests/{ => chains}/Ethereum/Data/eth_feeHistory.json (100%) rename tests/{ => chains}/Ethereum/Data/eth_feeHistory2.json (100%) rename tests/{ => chains}/Ethereum/Data/eth_feeHistory3.json (100%) rename tests/{ => chains}/Ethereum/Data/eth_feeHistory4.json (100%) rename tests/{ => chains}/Ethereum/Data/getAmountsOut.json (100%) rename tests/{ => chains}/Ethereum/Data/kyber_proxy.json (100%) rename tests/{ => chains}/Ethereum/Data/seaport_712.json (100%) rename tests/{ => chains}/Ethereum/Data/tuple_nested.json (100%) rename tests/{ => chains}/Ethereum/Data/uniswap_router_v2.json (100%) rename tests/{ => chains}/Ethereum/Data/zilliqa_data_tx.json (100%) rename tests/{ => chains}/Ethereum/RLPTests.cpp (100%) rename tests/{ => chains}/Ethereum/SignerTests.cpp (100%) rename tests/{ => chains}/Ethereum/TWAnySignerTests.cpp (99%) rename tests/{ => chains}/Ethereum/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Ethereum/TWEthereumAbiTests.cpp (99%) rename tests/{ => chains}/Ethereum/TWEthereumAbiValueDecoderTests.cpp (99%) rename tests/{ => chains}/Ethereum/TWEthereumAbiValueEncodeTests.cpp (98%) rename tests/{ => chains}/Ethereum/ValueDecoderTests.cpp (100%) rename tests/{ => chains}/Ethereum/ValueEncoderTests.cpp (100%) rename tests/{ => chains}/EthereumClassic/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Everscale/AddressTests.cpp (100%) rename tests/{ => chains}/Everscale/CellBuilderTest.cpp (100%) rename tests/{ => chains}/Everscale/CellTests.cpp (100%) rename tests/{ => chains}/Everscale/SignerTests.cpp (100%) rename tests/{ => chains}/Everscale/TWAnyAddressTests.cpp (96%) rename tests/{ => chains}/Everscale/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/Everscale/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Evmos/SignerTests.cpp (99%) rename tests/{ => chains}/Evmos/TWAnyAddressTests.cpp (97%) rename tests/{ => chains}/Evmos/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/FIO/AddressTests.cpp (100%) rename tests/{ => chains}/FIO/EncryptionTests.cpp (100%) rename tests/{ => chains}/FIO/SignerTests.cpp (100%) rename tests/{ => chains}/FIO/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/FIO/TWFIOAccountTests.cpp (97%) rename tests/{ => chains}/FIO/TWFIOTests.cpp (99%) rename tests/{ => chains}/FIO/TransactionBuilderTests.cpp (100%) rename tests/{ => chains}/Fantom/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Filecoin/AddressTests.cpp (100%) rename tests/{ => chains}/Filecoin/SignerTests.cpp (100%) rename tests/{ => chains}/Filecoin/TWAnySignerTests.cpp (98%) rename tests/{ => chains}/Filecoin/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Filecoin/TransactionTests.cpp (100%) rename tests/{ => chains}/Firo/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Firo/TWZCoinAddressTests.cpp (98%) rename tests/{ => chains}/GoChain/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Groestlcoin/AddressTests.cpp (100%) rename tests/{ => chains}/Groestlcoin/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Groestlcoin/TWGroestlcoinSigningTests.cpp (99%) rename tests/{ => chains}/Groestlcoin/TWGroestlcoinTests.cpp (99%) rename tests/{ => chains}/Harmony/AddressTests.cpp (100%) rename tests/{ => chains}/Harmony/SignerTests.cpp (100%) rename tests/{ => chains}/Harmony/StakingTests.cpp (100%) rename tests/{ => chains}/Harmony/TWAnyAddressTests.cpp (95%) rename tests/{ => chains}/Harmony/TWAnySignerTests.cpp (98%) rename tests/{ => chains}/Harmony/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Harmony/TWHarmonyStakingTests.cpp (99%) rename tests/{Icon => chains/ICON}/AddressTests.cpp (100%) rename tests/{Icon => chains/ICON}/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/ICON/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/IoTeX/AddressTests.cpp (100%) rename tests/{ => chains}/IoTeX/SignerTests.cpp (100%) rename tests/{ => chains}/IoTeX/StakingTests.cpp (99%) rename tests/{ => chains}/IoTeX/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/IoTeX/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Kava/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/KavaEvm/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Kin/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Klaytn/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/KuCoinCommunityChain/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Kusama/AddressTests.cpp (100%) rename tests/{ => chains}/Kusama/SignerTests.cpp (100%) rename tests/{ => chains}/Kusama/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/Kusama/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Litecoin/LitecoinAddressTests.cpp (100%) rename tests/{ => chains}/Litecoin/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Litecoin/TWLitecoinTests.cpp (99%) rename tests/{ => chains}/Meter/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Metis/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Monacoin/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Monacoin/TWMonacoinAddressTests.cpp (99%) rename tests/{ => chains}/Monacoin/TWMonacoinTransactionTests.cpp (99%) rename tests/{ => chains}/Moonbeam/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Moonriver/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/NEAR/AccountTests.cpp (100%) rename tests/{ => chains}/NEAR/AddressTests.cpp (100%) rename tests/{ => chains}/NEAR/SerializationTests.cpp (100%) rename tests/{ => chains}/NEAR/SignerTests.cpp (100%) rename tests/{ => chains}/NEAR/TWAnySignerTests.cpp (98%) rename tests/{ => chains}/NEAR/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/NEAR/TWNEARAccountTests.cpp (96%) rename tests/{ => chains}/NEO/AddressTests.cpp (100%) rename tests/{ => chains}/NEO/CoinReferenceTests.cpp (100%) rename tests/{ => chains}/NEO/SignerTests.cpp (100%) rename tests/{ => chains}/NEO/TWAnySignerTests.cpp (99%) rename tests/{ => chains}/NEO/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/NEO/TWNEOAddressTests.cpp (96%) rename tests/{ => chains}/NEO/TransactionAttributeTests.cpp (100%) rename tests/{ => chains}/NEO/TransactionOutputTests.cpp (100%) rename tests/{ => chains}/NEO/TransactionTests.cpp (100%) rename tests/{ => chains}/NEO/WitnessTests.cpp (100%) rename tests/{ => chains}/NULS/AddressTests.cpp (100%) rename tests/{ => chains}/NULS/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/NULS/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Nano/AddressTests.cpp (100%) rename tests/{ => chains}/Nano/SignerTests.cpp (100%) rename tests/{ => chains}/Nano/TWAnySignerTests.cpp (98%) rename tests/{ => chains}/Nano/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Nano/TWNanoAddressTests.cpp (97%) rename tests/{ => chains}/NativeEvmos/TWAnyAddressTests.cpp (97%) rename tests/{ => chains}/NativeEvmos/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Nebulas/AddressTests.cpp (100%) rename tests/{ => chains}/Nebulas/SignerTests.cpp (100%) rename tests/{ => chains}/Nebulas/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/Nebulas/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Nebulas/TWNebulasAddressTests.cpp (98%) rename tests/{ => chains}/Nebulas/TransactionTests.cpp (100%) rename tests/{ => chains}/Nervos/AddressTests.cpp (100%) rename tests/{ => chains}/Nervos/SignerTests.cpp (99%) rename tests/{ => chains}/Nervos/TWAnyAddressTests.cpp (98%) rename tests/{ => chains}/Nervos/TWAnySignerTests.cpp (99%) rename tests/{ => chains}/Nervos/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Nervos/TWNervosAddressTests.cpp (96%) rename tests/{ => chains}/Nimiq/AddressTests.cpp (100%) rename tests/{ => chains}/Nimiq/SignerTests.cpp (100%) rename tests/{ => chains}/Nimiq/TWAnySignerTests.cpp (96%) rename tests/{ => chains}/Nimiq/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Nimiq/TransactionTests.cpp (100%) rename tests/{ => chains}/OKXChain/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Oasis/AddressTests.cpp (100%) rename tests/{ => chains}/Oasis/SignerTests.cpp (100%) rename tests/{ => chains}/Oasis/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/Oasis/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Ontology/AccountTests.cpp (100%) rename tests/{ => chains}/Ontology/AddressTests.cpp (100%) rename tests/{ => chains}/Ontology/Oep4Tests.cpp (100%) rename tests/{ => chains}/Ontology/OngTests.cpp (100%) rename tests/{ => chains}/Ontology/OntTests.cpp (100%) rename tests/{ => chains}/Ontology/ParamsBuilderTests.cpp (100%) rename tests/{ => chains}/Ontology/TWAnySignerTests.cpp (99%) rename tests/{ => chains}/Ontology/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Ontology/TransactionTests.cpp (100%) rename tests/{ => chains}/Optimism/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Osmosis/AddressTests.cpp (100%) rename tests/{ => chains}/Osmosis/SignerTests.cpp (98%) rename tests/{ => chains}/Osmosis/TWAnyAddressTests.cpp (96%) rename tests/{ => chains}/Osmosis/TWAnySignerTests.cpp (98%) rename tests/{ => chains}/Osmosis/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/POANetwork/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Polkadot/AddressTests.cpp (100%) rename tests/{ => chains}/Polkadot/SS58AddressTests.cpp (99%) rename tests/{ => chains}/Polkadot/ScaleCodecTests.cpp (100%) rename tests/{ => chains}/Polkadot/SignerTests.cpp (100%) rename tests/{ => chains}/Polkadot/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Polygon/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Qtum/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Qtum/TWQtumAddressTests.cpp (99%) rename tests/{ => chains}/Ravencoin/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Ravencoin/TWRavencoinTransactionTests.cpp (99%) rename tests/{ => chains}/Ronin/TWAnyAddressTests.cpp (98%) rename tests/{ => chains}/Ronin/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/Ronin/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/SmartBitcoinCash/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Solana/AddressTests.cpp (100%) rename tests/{ => chains}/Solana/ProgramTests.cpp (100%) rename tests/{ => chains}/Solana/SignerTests.cpp (100%) rename tests/{ => chains}/Solana/TWAnySignerTests.cpp (99%) rename tests/{ => chains}/Solana/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Solana/TWSolanaAddressTests.cpp (97%) rename tests/{ => chains}/Solana/TransactionTests.cpp (100%) rename tests/{ => chains}/Stellar/AddressTests.cpp (100%) rename tests/{ => chains}/Stellar/TWAnySignerTests.cpp (99%) rename tests/{ => chains}/Stellar/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Stellar/TWStellarAddressTests.cpp (96%) rename tests/{ => chains}/Stellar/TransactionTests.cpp (99%) rename tests/{ => chains}/THORChain/SignerTests.cpp (99%) rename tests/{ => chains}/THORChain/SwapTests.cpp (99%) rename tests/{ => chains}/THORChain/TWAnyAddressTests.cpp (96%) rename tests/{ => chains}/THORChain/TWAnySignerTests.cpp (98%) rename tests/{ => chains}/THORChain/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/THORChain/TWSwapTests.cpp (99%) rename tests/{ => chains}/Terra/SignerTests.cpp (99%) rename tests/{ => chains}/Terra/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/TerraV2/SignerTests.cpp (99%) rename tests/{ => chains}/TerraV2/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Tezos/AddressTests.cpp (100%) rename tests/{ => chains}/Tezos/ForgingTests.cpp (100%) rename tests/{ => chains}/Tezos/OperationListTests.cpp (100%) rename tests/{ => chains}/Tezos/PublicKeyTests.cpp (100%) rename tests/{ => chains}/Tezos/SignerTests.cpp (100%) rename tests/{ => chains}/Tezos/TWAnySignerTests.cpp (99%) rename tests/{ => chains}/Tezos/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Theta/SignerTests.cpp (100%) rename tests/{ => chains}/Theta/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/Theta/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Theta/TransactionTests.cpp (100%) rename tests/{ => chains}/ThunderToken/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/TomoChain/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Tron/AddressTests.cpp (100%) rename tests/{ => chains}/Tron/SerializationTests.cpp (100%) rename tests/{ => chains}/Tron/SignerTests.cpp (100%) rename tests/{ => chains}/Tron/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/Tron/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/VeChain/SignerTests.cpp (100%) rename tests/{ => chains}/VeChain/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/VeChain/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Viacoin/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Viacoin/TWViacoinAddressTests.cpp (99%) rename tests/{ => chains}/Wanchain/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Waves/AddressTests.cpp (100%) rename tests/{ => chains}/Waves/LeaseTests.cpp (100%) rename tests/{ => chains}/Waves/SignerTests.cpp (100%) rename tests/{ => chains}/Waves/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/Waves/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Waves/TransactionTests.cpp (100%) rename tests/{ => chains}/XRP/AddressTests.cpp (100%) rename tests/{ => chains}/XRP/TWAnySignerTests.cpp (97%) rename tests/{ => chains}/XRP/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/XRP/TWRippleAddressTests.cpp (97%) rename tests/{ => chains}/XRP/TransactionTests.cpp (100%) rename tests/{ => chains}/Zcash/AddressTests.cpp (100%) rename tests/{ => chains}/Zcash/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Zcash/TWZcashAddressTests.cpp (99%) rename tests/{ => chains}/Zcash/TWZcashTransactionTests.cpp (99%) rename tests/{ => chains}/Zelcash/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Zelcash/TWZelcashAddressTests.cpp (99%) rename tests/{ => chains}/Zelcash/TWZelcashTransactionTests.cpp (99%) rename tests/{ => chains}/Zilliqa/AddressTests.cpp (100%) rename tests/{ => chains}/Zilliqa/SignatureTests.cpp (97%) rename tests/{ => chains}/Zilliqa/SignerTests.cpp (100%) rename tests/{ => chains}/Zilliqa/TWAnySignerTests.cpp (98%) rename tests/{ => chains}/Zilliqa/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/Zilliqa/TWZilliqaAddressTests.cpp (97%) rename tests/{ => chains}/ZkSyncV2/TWCoinTypeTests.cpp (97%) rename tests/{ => chains}/xDai/TWCoinTypeTests.cpp (97%) rename tests/{ => common}/AnyAddressTests.cpp (100%) rename tests/{ => common}/BCSTests.cpp (100%) rename tests/{ => common}/Base64Tests.cpp (100%) rename tests/{ => common}/BaseEncoding.cpp (100%) rename tests/{ => common}/Bech32AddressTests.cpp (100%) rename tests/{ => common}/Bech32Tests.cpp (100%) rename tests/{ => common}/BinaryCodingTests.cpp (100%) rename tests/{ => common}/CborTests.cpp (100%) rename tests/{ => common}/CoinAddressDerivationTests.cpp (100%) rename tests/{ => common}/CoinAddressValidationTests.cpp (100%) rename tests/{ => common}/DataTests.cpp (100%) rename tests/{ => common}/EncryptTests.cpp (100%) rename tests/{ => common}/HDWallet/HDWalletInternalTests.cpp (99%) rename tests/{ => common}/HDWallet/HDWalletTests.cpp (99%) rename tests/{ => common}/HDWallet/bip39_vectors.json (100%) rename tests/{ => common}/HashTests.cpp (100%) rename tests/{ => common}/HexCodingTests.cpp (100%) rename tests/{ => common}/Keystore/Data/empty-accounts.json (100%) rename tests/{ => common}/Keystore/Data/ethereum-wallet-address-no-0x.json (100%) rename tests/{ => common}/Keystore/Data/key.json (100%) rename tests/{ => common}/Keystore/Data/key_bitcoin.json (100%) rename tests/{ => common}/Keystore/Data/legacy-mnemonic.json (100%) rename tests/{ => common}/Keystore/Data/legacy-private-key.json (100%) rename tests/{ => common}/Keystore/Data/livepeer.json (100%) rename tests/{ => common}/Keystore/Data/missing-address.json (100%) rename tests/{ => common}/Keystore/Data/myetherwallet.uu (100%) rename tests/{ => common}/Keystore/Data/pbkdf2.json (100%) rename tests/{ => common}/Keystore/Data/wallet.json (100%) rename tests/{ => common}/Keystore/Data/watch.json (100%) rename tests/{ => common}/Keystore/Data/web3j.json (100%) rename tests/{ => common}/Keystore/DerivationPathTests.cpp (100%) rename tests/{ => common}/Keystore/StoredKeyTests.cpp (95%) rename tests/{ => common}/MnemonicTests.cpp (100%) rename tests/{ => common}/NumericLiteralTests.cpp (100%) rename tests/{ => common}/PrivateKeyTests.cpp (100%) rename tests/{ => common}/PublicKeyTests.cpp (99%) rename tests/{interface/TWTestUtilities.cpp => common/TestUtilities.cpp} (96%) rename tests/{interface/TWTestUtilities.h => common/TestUtilities.h} (100%) rename tests/{ => common}/TransactionCompilerTests.cpp (99%) rename tests/{ => common}/Uint256Tests.cpp (100%) rename tests/{ => common}/WalletConsoleTests.cpp (100%) rename tests/{ => common}/algorithm/erase_tests.cpp (100%) rename tests/{ => common}/algorithm/sort_copy_tests.cpp (100%) rename tests/{ => common}/algorithm/to_array_tests.cpp (100%) rename tests/{ => common}/memory/memzero_tests.cpp (100%) rename tests/{ => common}/operators/equality_comparable_tests.cpp (100%) diff --git a/codegen/bin/newcoin b/codegen/bin/newcoin index af985bd292b..8fdacb210fe 100755 --- a/codegen/bin/newcoin +++ b/codegen/bin/newcoin @@ -134,10 +134,10 @@ generate_file("newcoin/Proto.erb", "src/proto", "#{name}.proto", coin) generate_file("newcoin/Signer.h.erb", "src/#{name}", "Signer.h", coin) generate_file("newcoin/Signer.cpp.erb", "src/#{name}", "Signer.cpp", coin) -generate_file("newcoin/AddressTests.cpp.erb", "tests/#{name}", "AddressTests.cpp", coin) -generate_file("newcoin/SignerTests.cpp.erb", "tests/#{name}", "SignerTests.cpp", coin) -generate_file("newcoin/TWAddressTests.cpp.erb", "tests/#{name}", "TWAnyAddressTests.cpp", coin) -generate_file("newcoin/TWSignerTests.cpp.erb", "tests/#{name}", "TWAnySignerTests.cpp", coin) +generate_file("newcoin/AddressTests.cpp.erb", "tests/chains/#{name}", "AddressTests.cpp", coin) +generate_file("newcoin/SignerTests.cpp.erb", "tests/chains/#{name}", "SignerTests.cpp", coin) +generate_file("newcoin/TWAddressTests.cpp.erb", "tests/chains/#{name}", "TWAnyAddressTests.cpp", coin) +generate_file("newcoin/TWSignerTests.cpp.erb", "tests/chains/#{name}", "TWAnySignerTests.cpp", coin) generate_file("newcoin/AddressTests.kt.erb", "android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/#{format_name_lowercase(coin)}", "Test#{name}Address.kt", coin) generate_file("newcoin/SignerTests.kt.erb", "android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/#{format_name_lowercase(coin)}", "Test#{name}Signer.kt", coin) generate_file("newcoin/Tests.swift.erb", "swift/Tests/Blockchains", "#{name}Tests.swift", coin) diff --git a/codegen/lib/coin_test_gen.rb b/codegen/lib/coin_test_gen.rb index e4d7d845fce..0b831bfb277 100755 --- a/codegen/lib/coin_test_gen.rb +++ b/codegen/lib/coin_test_gen.rb @@ -63,7 +63,7 @@ def generate_coin_test_file(coin, templateFile, overwriteExisting = true) template = ERB.new(File.read(path), nil, '-') result = template.result(binding) - folder = 'tests/' + folder = 'tests/chains/' if coin.key?('testFolderName') folder += format_name(coin['testFolderName']) else diff --git a/codegen/lib/templates/TWCoinTypeTests.cpp.erb b/codegen/lib/templates/TWCoinTypeTests.cpp.erb index 4c8cd77e4fc..ab2a8fbf9c3 100644 --- a/codegen/lib/templates/TWCoinTypeTests.cpp.erb +++ b/codegen/lib/templates/TWCoinTypeTests.cpp.erb @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/codegen/lib/templates/newcoin/TWAddressTests.cpp.erb b/codegen/lib/templates/newcoin/TWAddressTests.cpp.erb index 0a4ea03764d..b290debae7a 100644 --- a/codegen/lib/templates/newcoin/TWAddressTests.cpp.erb +++ b/codegen/lib/templates/newcoin/TWAddressTests.cpp.erb @@ -7,7 +7,7 @@ #include #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/codegen/lib/templates/newcoin/TWSignerTests.cpp.erb b/codegen/lib/templates/newcoin/TWSignerTests.cpp.erb index 4e72ef5fa5f..59b6aa225c6 100644 --- a/codegen/lib/templates/newcoin/TWSignerTests.cpp.erb +++ b/codegen/lib/templates/newcoin/TWSignerTests.cpp.erb @@ -7,7 +7,7 @@ #include #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/swift/Tests/Blockchains/Data b/swift/Tests/Blockchains/Data index f50c5d874d3..154e08de1f2 120000 --- a/swift/Tests/Blockchains/Data +++ b/swift/Tests/Blockchains/Data @@ -1 +1 @@ -../../../tests/Ethereum/Data \ No newline at end of file +../../../tests/chains/Ethereum/Data \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 746cff782a1..b48482ab71b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,6 +25,7 @@ file(GLOB_RECURSE test_sources *.cpp **/*.cpp **/*.cc) add_executable(tests ${test_sources}) target_link_libraries(tests gtest_main TrezorCrypto TrustWalletCore walletconsolelib protobuf Boost::boost) target_include_directories(tests PRIVATE ${CMAKE_SOURCE_DIR}/src) +target_include_directories(tests PRIVATE ${CMAKE_SOURCE_DIR}/tests/common) target_compile_options(tests PRIVATE "-Wall") if (NOT ANDROID AND TW_UNITY_BUILD) set_target_properties(tests PROPERTIES UNITY_BUILD ON) diff --git a/tests/Aeternity/AddressTests.cpp b/tests/chains/Aeternity/AddressTests.cpp similarity index 100% rename from tests/Aeternity/AddressTests.cpp rename to tests/chains/Aeternity/AddressTests.cpp diff --git a/tests/Aeternity/SignerTests.cpp b/tests/chains/Aeternity/SignerTests.cpp similarity index 100% rename from tests/Aeternity/SignerTests.cpp rename to tests/chains/Aeternity/SignerTests.cpp diff --git a/tests/Aeternity/TWAeternityAddressTests.cpp b/tests/chains/Aeternity/TWAeternityAddressTests.cpp similarity index 96% rename from tests/Aeternity/TWAeternityAddressTests.cpp rename to tests/chains/Aeternity/TWAeternityAddressTests.cpp index 51376f5cf7a..b801091634c 100644 --- a/tests/Aeternity/TWAeternityAddressTests.cpp +++ b/tests/chains/Aeternity/TWAeternityAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Aeternity/TWAnySignerTests.cpp b/tests/chains/Aeternity/TWAnySignerTests.cpp similarity index 97% rename from tests/Aeternity/TWAnySignerTests.cpp rename to tests/chains/Aeternity/TWAnySignerTests.cpp index f966db42fbe..9a1f716447f 100644 --- a/tests/Aeternity/TWAnySignerTests.cpp +++ b/tests/chains/Aeternity/TWAnySignerTests.cpp @@ -9,7 +9,7 @@ #include "proto/Aeternity.pb.h" #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include namespace TW::Aeternity::tests { diff --git a/tests/Aeternity/TWCoinTypeTests.cpp b/tests/chains/Aeternity/TWCoinTypeTests.cpp similarity index 97% rename from tests/Aeternity/TWCoinTypeTests.cpp rename to tests/chains/Aeternity/TWCoinTypeTests.cpp index 7db96db7589..7e9f16603ca 100644 --- a/tests/Aeternity/TWCoinTypeTests.cpp +++ b/tests/chains/Aeternity/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Aeternity/TransactionTests.cpp b/tests/chains/Aeternity/TransactionTests.cpp similarity index 98% rename from tests/Aeternity/TransactionTests.cpp rename to tests/chains/Aeternity/TransactionTests.cpp index ea0ac8aedd3..fa50abb449f 100644 --- a/tests/Aeternity/TransactionTests.cpp +++ b/tests/chains/Aeternity/TransactionTests.cpp @@ -6,7 +6,7 @@ #include "HexCoding.h" #include "PrivateKey.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Aion/AddressTests.cpp b/tests/chains/Aion/AddressTests.cpp similarity index 100% rename from tests/Aion/AddressTests.cpp rename to tests/chains/Aion/AddressTests.cpp diff --git a/tests/Aion/RLPTests.cpp b/tests/chains/Aion/RLPTests.cpp similarity index 100% rename from tests/Aion/RLPTests.cpp rename to tests/chains/Aion/RLPTests.cpp diff --git a/tests/Aion/SignerTests.cpp b/tests/chains/Aion/SignerTests.cpp similarity index 100% rename from tests/Aion/SignerTests.cpp rename to tests/chains/Aion/SignerTests.cpp diff --git a/tests/Aion/TWAnySignerTests.cpp b/tests/chains/Aion/TWAnySignerTests.cpp similarity index 97% rename from tests/Aion/TWAnySignerTests.cpp rename to tests/chains/Aion/TWAnySignerTests.cpp index 2f7ab4630c0..5b7f3417014 100644 --- a/tests/Aion/TWAnySignerTests.cpp +++ b/tests/chains/Aion/TWAnySignerTests.cpp @@ -9,7 +9,7 @@ #include "proto/Aion.pb.h" #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include namespace TW::Aion::tests { diff --git a/tests/Aion/TWCoinTypeTests.cpp b/tests/chains/Aion/TWCoinTypeTests.cpp similarity index 97% rename from tests/Aion/TWCoinTypeTests.cpp rename to tests/chains/Aion/TWCoinTypeTests.cpp index e87d983d8d8..9d217c0654f 100644 --- a/tests/Aion/TWCoinTypeTests.cpp +++ b/tests/chains/Aion/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Aion/TransactionTests.cpp b/tests/chains/Aion/TransactionTests.cpp similarity index 100% rename from tests/Aion/TransactionTests.cpp rename to tests/chains/Aion/TransactionTests.cpp diff --git a/tests/Algorand/AddressTests.cpp b/tests/chains/Algorand/AddressTests.cpp similarity index 100% rename from tests/Algorand/AddressTests.cpp rename to tests/chains/Algorand/AddressTests.cpp diff --git a/tests/Algorand/SignerTests.cpp b/tests/chains/Algorand/SignerTests.cpp similarity index 100% rename from tests/Algorand/SignerTests.cpp rename to tests/chains/Algorand/SignerTests.cpp diff --git a/tests/Algorand/TWAnySignerTests.cpp b/tests/chains/Algorand/TWAnySignerTests.cpp similarity index 98% rename from tests/Algorand/TWAnySignerTests.cpp rename to tests/chains/Algorand/TWAnySignerTests.cpp index 5b3e00aa411..3890bafcfeb 100644 --- a/tests/Algorand/TWAnySignerTests.cpp +++ b/tests/chains/Algorand/TWAnySignerTests.cpp @@ -9,7 +9,7 @@ #include "proto/Algorand.pb.h" #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/Algorand/TWCoinTypeTests.cpp b/tests/chains/Algorand/TWCoinTypeTests.cpp similarity index 97% rename from tests/Algorand/TWCoinTypeTests.cpp rename to tests/chains/Algorand/TWCoinTypeTests.cpp index f95721fa727..26d33c3670f 100644 --- a/tests/Algorand/TWCoinTypeTests.cpp +++ b/tests/chains/Algorand/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Aptos/AddressTests.cpp b/tests/chains/Aptos/AddressTests.cpp similarity index 100% rename from tests/Aptos/AddressTests.cpp rename to tests/chains/Aptos/AddressTests.cpp diff --git a/tests/Aptos/MoveTypesTests.cpp b/tests/chains/Aptos/MoveTypesTests.cpp similarity index 100% rename from tests/Aptos/MoveTypesTests.cpp rename to tests/chains/Aptos/MoveTypesTests.cpp diff --git a/tests/Aptos/SignerTests.cpp b/tests/chains/Aptos/SignerTests.cpp similarity index 99% rename from tests/Aptos/SignerTests.cpp rename to tests/chains/Aptos/SignerTests.cpp index 1ebb97cfcc3..3e0145d677b 100644 --- a/tests/Aptos/SignerTests.cpp +++ b/tests/chains/Aptos/SignerTests.cpp @@ -9,7 +9,7 @@ #include "HexCoding.h" #include "PrivateKey.h" #include "PublicKey.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Aptos/TWAnySignerTests.cpp b/tests/chains/Aptos/TWAnySignerTests.cpp similarity index 98% rename from tests/Aptos/TWAnySignerTests.cpp rename to tests/chains/Aptos/TWAnySignerTests.cpp index 1caf524cc5c..e42890edf7b 100644 --- a/tests/Aptos/TWAnySignerTests.cpp +++ b/tests/chains/Aptos/TWAnySignerTests.cpp @@ -11,7 +11,7 @@ #include "PublicKey.h" #include #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/Aptos/TWAptosAddressTests.cpp b/tests/chains/Aptos/TWAptosAddressTests.cpp similarity index 96% rename from tests/Aptos/TWAptosAddressTests.cpp rename to tests/chains/Aptos/TWAptosAddressTests.cpp index cc827933612..e03407f5c56 100644 --- a/tests/Aptos/TWAptosAddressTests.cpp +++ b/tests/chains/Aptos/TWAptosAddressTests.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Aptos/TWCoinTypeTests.cpp b/tests/chains/Aptos/TWCoinTypeTests.cpp similarity index 97% rename from tests/Aptos/TWCoinTypeTests.cpp rename to tests/chains/Aptos/TWCoinTypeTests.cpp index e9f26f59987..af10a478945 100644 --- a/tests/Aptos/TWCoinTypeTests.cpp +++ b/tests/chains/Aptos/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Aptos/TransactionPayloadTests.cpp b/tests/chains/Aptos/TransactionPayloadTests.cpp similarity index 100% rename from tests/Aptos/TransactionPayloadTests.cpp rename to tests/chains/Aptos/TransactionPayloadTests.cpp diff --git a/tests/Arbitrum/TWCoinTypeTests.cpp b/tests/chains/Arbitrum/TWCoinTypeTests.cpp similarity index 97% rename from tests/Arbitrum/TWCoinTypeTests.cpp rename to tests/chains/Arbitrum/TWCoinTypeTests.cpp index 35c6faa4ab6..bab96f946ff 100644 --- a/tests/Arbitrum/TWCoinTypeTests.cpp +++ b/tests/chains/Arbitrum/TWCoinTypeTests.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Aurora/TWCoinTypeTests.cpp b/tests/chains/Aurora/TWCoinTypeTests.cpp similarity index 97% rename from tests/Aurora/TWCoinTypeTests.cpp rename to tests/chains/Aurora/TWCoinTypeTests.cpp index 5dff7ccd8fb..b612ce508ce 100644 --- a/tests/Aurora/TWCoinTypeTests.cpp +++ b/tests/chains/Aurora/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Avalanche/TWCoinTypeTests.cpp b/tests/chains/Avalanche/TWCoinTypeTests.cpp similarity index 97% rename from tests/Avalanche/TWCoinTypeTests.cpp rename to tests/chains/Avalanche/TWCoinTypeTests.cpp index f9b1aa72576..8bf54001455 100644 --- a/tests/Avalanche/TWCoinTypeTests.cpp +++ b/tests/chains/Avalanche/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/BandChain/TWCoinTypeTests.cpp b/tests/chains/BandChain/TWCoinTypeTests.cpp similarity index 97% rename from tests/BandChain/TWCoinTypeTests.cpp rename to tests/chains/BandChain/TWCoinTypeTests.cpp index 4fdd7e8f90b..f6ad4c690c0 100644 --- a/tests/BandChain/TWCoinTypeTests.cpp +++ b/tests/chains/BandChain/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Binance/SignerTests.cpp b/tests/chains/Binance/SignerTests.cpp similarity index 100% rename from tests/Binance/SignerTests.cpp rename to tests/chains/Binance/SignerTests.cpp diff --git a/tests/Binance/TWAnySignerTests.cpp b/tests/chains/Binance/TWAnySignerTests.cpp similarity index 99% rename from tests/Binance/TWAnySignerTests.cpp rename to tests/chains/Binance/TWAnySignerTests.cpp index aa06a82e55e..84193da844a 100644 --- a/tests/Binance/TWAnySignerTests.cpp +++ b/tests/chains/Binance/TWAnySignerTests.cpp @@ -10,7 +10,7 @@ #include #include "Coin.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Binance/TWCoinTypeTests.cpp b/tests/chains/Binance/TWCoinTypeTests.cpp similarity index 97% rename from tests/Binance/TWCoinTypeTests.cpp rename to tests/chains/Binance/TWCoinTypeTests.cpp index 52ce9bc3bf9..2059c040c6b 100644 --- a/tests/Binance/TWCoinTypeTests.cpp +++ b/tests/chains/Binance/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/BinanceSmartChain/SignerTests.cpp b/tests/chains/BinanceSmartChain/SignerTests.cpp similarity index 98% rename from tests/BinanceSmartChain/SignerTests.cpp rename to tests/chains/BinanceSmartChain/SignerTests.cpp index 3ec01b4f1e6..6303410de22 100644 --- a/tests/BinanceSmartChain/SignerTests.cpp +++ b/tests/chains/BinanceSmartChain/SignerTests.cpp @@ -12,7 +12,7 @@ #include "proto/Ethereum.pb.h" #include "HexCoding.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/BinanceSmartChain/TWAnyAddressTests.cpp b/tests/chains/BinanceSmartChain/TWAnyAddressTests.cpp similarity index 96% rename from tests/BinanceSmartChain/TWAnyAddressTests.cpp rename to tests/chains/BinanceSmartChain/TWAnyAddressTests.cpp index e50537d7b8c..f7769d5c198 100644 --- a/tests/BinanceSmartChain/TWAnyAddressTests.cpp +++ b/tests/chains/BinanceSmartChain/TWAnyAddressTests.cpp @@ -7,7 +7,7 @@ #include #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/BinanceSmartChain/TWCoinTypeTests.cpp b/tests/chains/BinanceSmartChain/TWCoinTypeTests.cpp similarity index 98% rename from tests/BinanceSmartChain/TWCoinTypeTests.cpp rename to tests/chains/BinanceSmartChain/TWCoinTypeTests.cpp index 9f768216878..f48a6b1e56e 100644 --- a/tests/BinanceSmartChain/TWCoinTypeTests.cpp +++ b/tests/chains/BinanceSmartChain/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Bitcoin/BitcoinAddressTests.cpp b/tests/chains/Bitcoin/BitcoinAddressTests.cpp similarity index 100% rename from tests/Bitcoin/BitcoinAddressTests.cpp rename to tests/chains/Bitcoin/BitcoinAddressTests.cpp diff --git a/tests/Bitcoin/BitcoinScriptTests.cpp b/tests/chains/Bitcoin/BitcoinScriptTests.cpp similarity index 99% rename from tests/Bitcoin/BitcoinScriptTests.cpp rename to tests/chains/Bitcoin/BitcoinScriptTests.cpp index 15d3cf7fc5e..66c50b9701e 100644 --- a/tests/Bitcoin/BitcoinScriptTests.cpp +++ b/tests/chains/Bitcoin/BitcoinScriptTests.cpp @@ -6,7 +6,7 @@ #include "Bitcoin/Script.h" #include "Bitcoin/SignatureBuilder.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "HexCoding.h" #include diff --git a/tests/Bitcoin/FeeCalculatorTests.cpp b/tests/chains/Bitcoin/FeeCalculatorTests.cpp similarity index 100% rename from tests/Bitcoin/FeeCalculatorTests.cpp rename to tests/chains/Bitcoin/FeeCalculatorTests.cpp diff --git a/tests/Bitcoin/InputSelectorTests.cpp b/tests/chains/Bitcoin/InputSelectorTests.cpp similarity index 100% rename from tests/Bitcoin/InputSelectorTests.cpp rename to tests/chains/Bitcoin/InputSelectorTests.cpp diff --git a/tests/Bitcoin/MessageSignerTests.cpp b/tests/chains/Bitcoin/MessageSignerTests.cpp similarity index 99% rename from tests/Bitcoin/MessageSignerTests.cpp rename to tests/chains/Bitcoin/MessageSignerTests.cpp index e8df4e56631..5ec7d6d361a 100644 --- a/tests/Bitcoin/MessageSignerTests.cpp +++ b/tests/chains/Bitcoin/MessageSignerTests.cpp @@ -19,7 +19,6 @@ #include #include -#include // TODO remove namespace TW::Bitcoin::MessageSignerTests { diff --git a/tests/Bitcoin/SegwitAddressTests.cpp b/tests/chains/Bitcoin/SegwitAddressTests.cpp similarity index 100% rename from tests/Bitcoin/SegwitAddressTests.cpp rename to tests/chains/Bitcoin/SegwitAddressTests.cpp diff --git a/tests/Bitcoin/TWBitcoinAddressTests.cpp b/tests/chains/Bitcoin/TWBitcoinAddressTests.cpp similarity index 98% rename from tests/Bitcoin/TWBitcoinAddressTests.cpp rename to tests/chains/Bitcoin/TWBitcoinAddressTests.cpp index c2e81b6d33a..13c96dc5a5c 100644 --- a/tests/Bitcoin/TWBitcoinAddressTests.cpp +++ b/tests/chains/Bitcoin/TWBitcoinAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Bitcoin/TWBitcoinScriptTests.cpp b/tests/chains/Bitcoin/TWBitcoinScriptTests.cpp similarity index 99% rename from tests/Bitcoin/TWBitcoinScriptTests.cpp rename to tests/chains/Bitcoin/TWBitcoinScriptTests.cpp index 064b83f50d9..2f9a3e1ad29 100644 --- a/tests/Bitcoin/TWBitcoinScriptTests.cpp +++ b/tests/chains/Bitcoin/TWBitcoinScriptTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Bitcoin/TWBitcoinSigningTests.cpp b/tests/chains/Bitcoin/TWBitcoinSigningTests.cpp similarity index 100% rename from tests/Bitcoin/TWBitcoinSigningTests.cpp rename to tests/chains/Bitcoin/TWBitcoinSigningTests.cpp diff --git a/tests/Bitcoin/TWBitcoinTransactionTests.cpp b/tests/chains/Bitcoin/TWBitcoinTransactionTests.cpp similarity index 100% rename from tests/Bitcoin/TWBitcoinTransactionTests.cpp rename to tests/chains/Bitcoin/TWBitcoinTransactionTests.cpp diff --git a/tests/Bitcoin/TWCoinTypeTests.cpp b/tests/chains/Bitcoin/TWCoinTypeTests.cpp similarity index 97% rename from tests/Bitcoin/TWCoinTypeTests.cpp rename to tests/chains/Bitcoin/TWCoinTypeTests.cpp index 0cba7d8cb7e..3ce30dd594b 100644 --- a/tests/Bitcoin/TWCoinTypeTests.cpp +++ b/tests/chains/Bitcoin/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Bitcoin/TWSegwitAddressTests.cpp b/tests/chains/Bitcoin/TWSegwitAddressTests.cpp similarity index 98% rename from tests/Bitcoin/TWSegwitAddressTests.cpp rename to tests/chains/Bitcoin/TWSegwitAddressTests.cpp index ccc41fc5737..65c632ca6b9 100644 --- a/tests/Bitcoin/TWSegwitAddressTests.cpp +++ b/tests/chains/Bitcoin/TWSegwitAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Bitcoin/TransactionPlanTests.cpp b/tests/chains/Bitcoin/TransactionPlanTests.cpp similarity index 100% rename from tests/Bitcoin/TransactionPlanTests.cpp rename to tests/chains/Bitcoin/TransactionPlanTests.cpp diff --git a/tests/Bitcoin/TxComparisonHelper.cpp b/tests/chains/Bitcoin/TxComparisonHelper.cpp similarity index 100% rename from tests/Bitcoin/TxComparisonHelper.cpp rename to tests/chains/Bitcoin/TxComparisonHelper.cpp diff --git a/tests/Bitcoin/TxComparisonHelper.h b/tests/chains/Bitcoin/TxComparisonHelper.h similarity index 100% rename from tests/Bitcoin/TxComparisonHelper.h rename to tests/chains/Bitcoin/TxComparisonHelper.h diff --git a/tests/BitcoinCash/TWBitcoinCashTests.cpp b/tests/chains/BitcoinCash/TWBitcoinCashTests.cpp similarity index 99% rename from tests/BitcoinCash/TWBitcoinCashTests.cpp rename to tests/chains/BitcoinCash/TWBitcoinCashTests.cpp index e4f960149f6..19f6fc564d4 100644 --- a/tests/BitcoinCash/TWBitcoinCashTests.cpp +++ b/tests/chains/BitcoinCash/TWBitcoinCashTests.cpp @@ -8,7 +8,7 @@ #include "Bitcoin/SigHashType.h" #include "HexCoding.h" #include "proto/Bitcoin.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/BitcoinCash/TWCoinTypeTests.cpp b/tests/chains/BitcoinCash/TWCoinTypeTests.cpp similarity index 97% rename from tests/BitcoinCash/TWCoinTypeTests.cpp rename to tests/chains/BitcoinCash/TWCoinTypeTests.cpp index 9b56e10a7af..666aa70328c 100644 --- a/tests/BitcoinCash/TWCoinTypeTests.cpp +++ b/tests/chains/BitcoinCash/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/BitcoinGold/TWAddressTests.cpp b/tests/chains/BitcoinGold/TWAddressTests.cpp similarity index 96% rename from tests/BitcoinGold/TWAddressTests.cpp rename to tests/chains/BitcoinGold/TWAddressTests.cpp index 77c192461bb..977c77900e1 100644 --- a/tests/BitcoinGold/TWAddressTests.cpp +++ b/tests/chains/BitcoinGold/TWAddressTests.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "Bitcoin/Address.h" #include "PrivateKey.h" #include "PublicKey.h" diff --git a/tests/BitcoinGold/TWBitcoinGoldTests.cpp b/tests/chains/BitcoinGold/TWBitcoinGoldTests.cpp similarity index 99% rename from tests/BitcoinGold/TWBitcoinGoldTests.cpp rename to tests/chains/BitcoinGold/TWBitcoinGoldTests.cpp index 6c4247b4f90..760cd79b9a6 100644 --- a/tests/BitcoinGold/TWBitcoinGoldTests.cpp +++ b/tests/chains/BitcoinGold/TWBitcoinGoldTests.cpp @@ -20,7 +20,7 @@ #include "Bitcoin/TransactionSigner.h" #include "HexCoding.h" #include "proto/Bitcoin.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" using namespace TW; diff --git a/tests/BitcoinGold/TWCoinTypeTests.cpp b/tests/chains/BitcoinGold/TWCoinTypeTests.cpp similarity index 97% rename from tests/BitcoinGold/TWCoinTypeTests.cpp rename to tests/chains/BitcoinGold/TWCoinTypeTests.cpp index 55b11cdfa52..5ab3db7a03b 100644 --- a/tests/BitcoinGold/TWCoinTypeTests.cpp +++ b/tests/chains/BitcoinGold/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/BitcoinGold/TWSegwitAddressTests.cpp b/tests/chains/BitcoinGold/TWSegwitAddressTests.cpp similarity index 98% rename from tests/BitcoinGold/TWSegwitAddressTests.cpp rename to tests/chains/BitcoinGold/TWSegwitAddressTests.cpp index b526c21a480..0f8c1413fe1 100644 --- a/tests/BitcoinGold/TWSegwitAddressTests.cpp +++ b/tests/chains/BitcoinGold/TWSegwitAddressTests.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "Bitcoin/SegwitAddress.h" #include "Coin.h" #include "PrivateKey.h" diff --git a/tests/BitcoinGold/TWSignerTests.cpp b/tests/chains/BitcoinGold/TWSignerTests.cpp similarity index 98% rename from tests/BitcoinGold/TWSignerTests.cpp rename to tests/chains/BitcoinGold/TWSignerTests.cpp index f75bc5219a5..673e6437912 100644 --- a/tests/BitcoinGold/TWSignerTests.cpp +++ b/tests/chains/BitcoinGold/TWSignerTests.cpp @@ -18,7 +18,7 @@ #include "HexCoding.h" #include "proto/Bitcoin.pb.h" #include "../Bitcoin/TxComparisonHelper.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" namespace TW::Bitcoin { diff --git a/tests/Bluzelle/TWCoinTypeTests.cpp b/tests/chains/Bluzelle/TWCoinTypeTests.cpp similarity index 97% rename from tests/Bluzelle/TWCoinTypeTests.cpp rename to tests/chains/Bluzelle/TWCoinTypeTests.cpp index 33acfa33f7b..09dcb1aed7b 100644 --- a/tests/Bluzelle/TWCoinTypeTests.cpp +++ b/tests/chains/Bluzelle/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Boba/TWCoinTypeTests.cpp b/tests/chains/Boba/TWCoinTypeTests.cpp similarity index 97% rename from tests/Boba/TWCoinTypeTests.cpp rename to tests/chains/Boba/TWCoinTypeTests.cpp index d538cea0cf3..9d9d27f52cf 100644 --- a/tests/Boba/TWCoinTypeTests.cpp +++ b/tests/chains/Boba/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Callisto/TWCoinTypeTests.cpp b/tests/chains/Callisto/TWCoinTypeTests.cpp similarity index 97% rename from tests/Callisto/TWCoinTypeTests.cpp rename to tests/chains/Callisto/TWCoinTypeTests.cpp index 2c83326e867..e742718974f 100644 --- a/tests/Callisto/TWCoinTypeTests.cpp +++ b/tests/chains/Callisto/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Cardano/AddressTests.cpp b/tests/chains/Cardano/AddressTests.cpp similarity index 100% rename from tests/Cardano/AddressTests.cpp rename to tests/chains/Cardano/AddressTests.cpp diff --git a/tests/Cardano/SigningTests.cpp b/tests/chains/Cardano/SigningTests.cpp similarity index 99% rename from tests/Cardano/SigningTests.cpp rename to tests/chains/Cardano/SigningTests.cpp index d0fb95a5a95..79b1fe0072c 100644 --- a/tests/Cardano/SigningTests.cpp +++ b/tests/chains/Cardano/SigningTests.cpp @@ -13,7 +13,7 @@ #include "HexCoding.h" #include "PrivateKey.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Cardano/StakingTests.cpp b/tests/chains/Cardano/StakingTests.cpp similarity index 99% rename from tests/Cardano/StakingTests.cpp rename to tests/chains/Cardano/StakingTests.cpp index a1cc13e71f1..cf7636b23c5 100644 --- a/tests/Cardano/StakingTests.cpp +++ b/tests/chains/Cardano/StakingTests.cpp @@ -13,7 +13,7 @@ #include "HexCoding.h" #include "PrivateKey.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Cardano/TWCardanoAddressTests.cpp b/tests/chains/Cardano/TWCardanoAddressTests.cpp similarity index 99% rename from tests/Cardano/TWCardanoAddressTests.cpp rename to tests/chains/Cardano/TWCardanoAddressTests.cpp index e77f3e81520..709cba08745 100644 --- a/tests/Cardano/TWCardanoAddressTests.cpp +++ b/tests/chains/Cardano/TWCardanoAddressTests.cpp @@ -12,7 +12,7 @@ #include #include #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "PrivateKey.h" #include diff --git a/tests/Cardano/TWCoinTypeTests.cpp b/tests/chains/Cardano/TWCoinTypeTests.cpp similarity index 97% rename from tests/Cardano/TWCoinTypeTests.cpp rename to tests/chains/Cardano/TWCoinTypeTests.cpp index 987f2fc7856..33f8c9e197d 100644 --- a/tests/Cardano/TWCoinTypeTests.cpp +++ b/tests/chains/Cardano/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Cardano/TransactionTests.cpp b/tests/chains/Cardano/TransactionTests.cpp similarity index 100% rename from tests/Cardano/TransactionTests.cpp rename to tests/chains/Cardano/TransactionTests.cpp diff --git a/tests/Celo/TWCoinTypeTests.cpp b/tests/chains/Celo/TWCoinTypeTests.cpp similarity index 97% rename from tests/Celo/TWCoinTypeTests.cpp rename to tests/chains/Celo/TWCoinTypeTests.cpp index 7a66fc66eda..35fd5a76d73 100644 --- a/tests/Celo/TWCoinTypeTests.cpp +++ b/tests/chains/Celo/TWCoinTypeTests.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Cosmos/AddressTests.cpp b/tests/chains/Cosmos/AddressTests.cpp similarity index 100% rename from tests/Cosmos/AddressTests.cpp rename to tests/chains/Cosmos/AddressTests.cpp diff --git a/tests/Cosmos/Protobuf/.gitignore b/tests/chains/Cosmos/Protobuf/.gitignore similarity index 100% rename from tests/Cosmos/Protobuf/.gitignore rename to tests/chains/Cosmos/Protobuf/.gitignore diff --git a/tests/Cosmos/Protobuf/Article.proto b/tests/chains/Cosmos/Protobuf/Article.proto similarity index 100% rename from tests/Cosmos/Protobuf/Article.proto rename to tests/chains/Cosmos/Protobuf/Article.proto diff --git a/tests/Cosmos/ProtobufTests.cpp b/tests/chains/Cosmos/ProtobufTests.cpp similarity index 98% rename from tests/Cosmos/ProtobufTests.cpp rename to tests/chains/Cosmos/ProtobufTests.cpp index 73557fd4303..89b36346ac5 100644 --- a/tests/Cosmos/ProtobufTests.cpp +++ b/tests/chains/Cosmos/ProtobufTests.cpp @@ -13,7 +13,7 @@ #include "HexCoding.h" #include "Protobuf/Article.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Cosmos/SignerTests.cpp b/tests/chains/Cosmos/SignerTests.cpp similarity index 99% rename from tests/Cosmos/SignerTests.cpp rename to tests/chains/Cosmos/SignerTests.cpp index 36355e3ed4f..a791e7bd10f 100644 --- a/tests/Cosmos/SignerTests.cpp +++ b/tests/chains/Cosmos/SignerTests.cpp @@ -10,7 +10,7 @@ #include "proto/Cosmos.pb.h" #include "Cosmos/Address.h" #include "Cosmos/Signer.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "Cosmos/Protobuf/bank_tx.pb.h" #include diff --git a/tests/Cosmos/StakingTests.cpp b/tests/chains/Cosmos/StakingTests.cpp similarity index 99% rename from tests/Cosmos/StakingTests.cpp rename to tests/chains/Cosmos/StakingTests.cpp index f3fb89a34f5..0abee814e66 100644 --- a/tests/Cosmos/StakingTests.cpp +++ b/tests/chains/Cosmos/StakingTests.cpp @@ -10,7 +10,7 @@ #include "Cosmos/Signer.h" #include "HexCoding.h" #include "proto/Cosmos.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include namespace TW::Cosmos::tests { diff --git a/tests/Cosmos/TWAnyAddressTests.cpp b/tests/chains/Cosmos/TWAnyAddressTests.cpp similarity index 95% rename from tests/Cosmos/TWAnyAddressTests.cpp rename to tests/chains/Cosmos/TWAnyAddressTests.cpp index 5605e54aef0..27559eff580 100644 --- a/tests/Cosmos/TWAnyAddressTests.cpp +++ b/tests/chains/Cosmos/TWAnyAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Cosmos/TWAnySignerTests.cpp b/tests/chains/Cosmos/TWAnySignerTests.cpp similarity index 98% rename from tests/Cosmos/TWAnySignerTests.cpp rename to tests/chains/Cosmos/TWAnySignerTests.cpp index ae6fd1e8bf7..014bd26d4f4 100644 --- a/tests/Cosmos/TWAnySignerTests.cpp +++ b/tests/chains/Cosmos/TWAnySignerTests.cpp @@ -7,7 +7,7 @@ #include "Cosmos/Address.h" #include "HexCoding.h" #include "proto/Cosmos.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Cosmos/TWCoinTypeTests.cpp b/tests/chains/Cosmos/TWCoinTypeTests.cpp similarity index 97% rename from tests/Cosmos/TWCoinTypeTests.cpp rename to tests/chains/Cosmos/TWCoinTypeTests.cpp index 10d3a2d3cc4..228564d05d3 100644 --- a/tests/Cosmos/TWCoinTypeTests.cpp +++ b/tests/chains/Cosmos/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Cronos/TWAnyAddressTests.cpp b/tests/chains/Cronos/TWAnyAddressTests.cpp similarity index 94% rename from tests/Cronos/TWAnyAddressTests.cpp rename to tests/chains/Cronos/TWAnyAddressTests.cpp index bee3a617641..115c061283f 100644 --- a/tests/Cronos/TWAnyAddressTests.cpp +++ b/tests/chains/Cronos/TWAnyAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Cronos/TWCoinTypeTests.cpp b/tests/chains/Cronos/TWCoinTypeTests.cpp similarity index 97% rename from tests/Cronos/TWCoinTypeTests.cpp rename to tests/chains/Cronos/TWCoinTypeTests.cpp index 728c15a121d..b3f60a93b58 100644 --- a/tests/Cronos/TWCoinTypeTests.cpp +++ b/tests/chains/Cronos/TWCoinTypeTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/CryptoOrg/AddressTests.cpp b/tests/chains/CryptoOrg/AddressTests.cpp similarity index 100% rename from tests/CryptoOrg/AddressTests.cpp rename to tests/chains/CryptoOrg/AddressTests.cpp diff --git a/tests/CryptoOrg/SignerTests.cpp b/tests/chains/CryptoOrg/SignerTests.cpp similarity index 99% rename from tests/CryptoOrg/SignerTests.cpp rename to tests/chains/CryptoOrg/SignerTests.cpp index 9cb39723edb..bfc9dc634b5 100644 --- a/tests/CryptoOrg/SignerTests.cpp +++ b/tests/chains/CryptoOrg/SignerTests.cpp @@ -9,7 +9,7 @@ #include "Cosmos/Address.h" #include "HexCoding.h" #include "PublicKey.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/CryptoOrg/TWAnyAddressTests.cpp b/tests/chains/CryptoOrg/TWAnyAddressTests.cpp similarity index 96% rename from tests/CryptoOrg/TWAnyAddressTests.cpp rename to tests/chains/CryptoOrg/TWAnyAddressTests.cpp index e9771fed810..4af5812a464 100644 --- a/tests/CryptoOrg/TWAnyAddressTests.cpp +++ b/tests/chains/CryptoOrg/TWAnyAddressTests.cpp @@ -7,7 +7,7 @@ #include #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/CryptoOrg/TWAnySignerTests.cpp b/tests/chains/CryptoOrg/TWAnySignerTests.cpp similarity index 99% rename from tests/CryptoOrg/TWAnySignerTests.cpp rename to tests/chains/CryptoOrg/TWAnySignerTests.cpp index 5f87a527d21..62519f35671 100644 --- a/tests/CryptoOrg/TWAnySignerTests.cpp +++ b/tests/chains/CryptoOrg/TWAnySignerTests.cpp @@ -10,7 +10,7 @@ #include "Base64.h" #include "Data.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/CryptoOrg/TWCoinTypeTests.cpp b/tests/chains/CryptoOrg/TWCoinTypeTests.cpp similarity index 97% rename from tests/CryptoOrg/TWCoinTypeTests.cpp rename to tests/chains/CryptoOrg/TWCoinTypeTests.cpp index a6e06751ec4..0e19d390f0b 100644 --- a/tests/CryptoOrg/TWCoinTypeTests.cpp +++ b/tests/chains/CryptoOrg/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Dash/TWCoinTypeTests.cpp b/tests/chains/Dash/TWCoinTypeTests.cpp similarity index 97% rename from tests/Dash/TWCoinTypeTests.cpp rename to tests/chains/Dash/TWCoinTypeTests.cpp index 20fa3257b39..9995965fda6 100644 --- a/tests/Dash/TWCoinTypeTests.cpp +++ b/tests/chains/Dash/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Dash/TWDashTests.cpp b/tests/chains/Dash/TWDashTests.cpp similarity index 95% rename from tests/Dash/TWDashTests.cpp rename to tests/chains/Dash/TWDashTests.cpp index c1ad9c58117..a0d86239464 100644 --- a/tests/Dash/TWDashTests.cpp +++ b/tests/chains/Dash/TWDashTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/Decred/AddressTests.cpp b/tests/chains/Decred/AddressTests.cpp similarity index 100% rename from tests/Decred/AddressTests.cpp rename to tests/chains/Decred/AddressTests.cpp diff --git a/tests/Decred/SignerTests.cpp b/tests/chains/Decred/SignerTests.cpp similarity index 100% rename from tests/Decred/SignerTests.cpp rename to tests/chains/Decred/SignerTests.cpp diff --git a/tests/Decred/TWAnySignerTests.cpp b/tests/chains/Decred/TWAnySignerTests.cpp similarity index 99% rename from tests/Decred/TWAnySignerTests.cpp rename to tests/chains/Decred/TWAnySignerTests.cpp index 033d87a4a2c..2960a5fcb1c 100644 --- a/tests/Decred/TWAnySignerTests.cpp +++ b/tests/chains/Decred/TWAnySignerTests.cpp @@ -5,7 +5,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "HexCoding.h" #include "proto/Bitcoin.pb.h" diff --git a/tests/Decred/TWCoinTypeTests.cpp b/tests/chains/Decred/TWCoinTypeTests.cpp similarity index 97% rename from tests/Decred/TWCoinTypeTests.cpp rename to tests/chains/Decred/TWCoinTypeTests.cpp index 8e8200bae80..f355997d41b 100644 --- a/tests/Decred/TWCoinTypeTests.cpp +++ b/tests/chains/Decred/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Decred/TWDecredTests.cpp b/tests/chains/Decred/TWDecredTests.cpp similarity index 98% rename from tests/Decred/TWDecredTests.cpp rename to tests/chains/Decred/TWDecredTests.cpp index 1b05944929b..661420c887c 100644 --- a/tests/Decred/TWDecredTests.cpp +++ b/tests/chains/Decred/TWDecredTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/DigiByte/TWCoinTypeTests.cpp b/tests/chains/DigiByte/TWCoinTypeTests.cpp similarity index 97% rename from tests/DigiByte/TWCoinTypeTests.cpp rename to tests/chains/DigiByte/TWCoinTypeTests.cpp index 0140cef4893..46d2adfa5de 100644 --- a/tests/DigiByte/TWCoinTypeTests.cpp +++ b/tests/chains/DigiByte/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/DigiByte/TWDigiByteTests.cpp b/tests/chains/DigiByte/TWDigiByteTests.cpp similarity index 99% rename from tests/DigiByte/TWDigiByteTests.cpp rename to tests/chains/DigiByte/TWDigiByteTests.cpp index 32ff866d846..c824018607c 100644 --- a/tests/DigiByte/TWDigiByteTests.cpp +++ b/tests/chains/DigiByte/TWDigiByteTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "Bitcoin/OutPoint.h" #include "Bitcoin/TransactionBuilder.h" diff --git a/tests/Dogecoin/TWCoinTypeTests.cpp b/tests/chains/Dogecoin/TWCoinTypeTests.cpp similarity index 97% rename from tests/Dogecoin/TWCoinTypeTests.cpp rename to tests/chains/Dogecoin/TWCoinTypeTests.cpp index decba7e836e..3196965f758 100644 --- a/tests/Dogecoin/TWCoinTypeTests.cpp +++ b/tests/chains/Dogecoin/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Dogecoin/TWDogeTests.cpp b/tests/chains/Dogecoin/TWDogeTests.cpp similarity index 95% rename from tests/Dogecoin/TWDogeTests.cpp rename to tests/chains/Dogecoin/TWDogeTests.cpp index 76f83bdb96a..627fc78a72e 100644 --- a/tests/Dogecoin/TWDogeTests.cpp +++ b/tests/chains/Dogecoin/TWDogeTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/ECO/TWCoinTypeTests.cpp b/tests/chains/ECO/TWCoinTypeTests.cpp similarity index 97% rename from tests/ECO/TWCoinTypeTests.cpp rename to tests/chains/ECO/TWCoinTypeTests.cpp index 3f2f2ae6b96..a72cb7b7877 100644 --- a/tests/ECO/TWCoinTypeTests.cpp +++ b/tests/chains/ECO/TWCoinTypeTests.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/ECash/TWCoinTypeTests.cpp b/tests/chains/ECash/TWCoinTypeTests.cpp similarity index 97% rename from tests/ECash/TWCoinTypeTests.cpp rename to tests/chains/ECash/TWCoinTypeTests.cpp index 59d2ea5954d..d8f9305bc12 100644 --- a/tests/ECash/TWCoinTypeTests.cpp +++ b/tests/chains/ECash/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/ECash/TWECashTests.cpp b/tests/chains/ECash/TWECashTests.cpp similarity index 99% rename from tests/ECash/TWECashTests.cpp rename to tests/chains/ECash/TWECashTests.cpp index 974f9bcff81..f258e4a4816 100644 --- a/tests/ECash/TWECashTests.cpp +++ b/tests/chains/ECash/TWECashTests.cpp @@ -8,7 +8,7 @@ #include "Bitcoin/SigHashType.h" #include "HexCoding.h" #include "proto/Bitcoin.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/EOS/AddressTests.cpp b/tests/chains/EOS/AddressTests.cpp similarity index 100% rename from tests/EOS/AddressTests.cpp rename to tests/chains/EOS/AddressTests.cpp diff --git a/tests/EOS/AssetTests.cpp b/tests/chains/EOS/AssetTests.cpp similarity index 100% rename from tests/EOS/AssetTests.cpp rename to tests/chains/EOS/AssetTests.cpp diff --git a/tests/EOS/NameTests.cpp b/tests/chains/EOS/NameTests.cpp similarity index 100% rename from tests/EOS/NameTests.cpp rename to tests/chains/EOS/NameTests.cpp diff --git a/tests/EOS/SignatureTests.cpp b/tests/chains/EOS/SignatureTests.cpp similarity index 100% rename from tests/EOS/SignatureTests.cpp rename to tests/chains/EOS/SignatureTests.cpp diff --git a/tests/EOS/TWAnySignerTests.cpp b/tests/chains/EOS/TWAnySignerTests.cpp similarity index 98% rename from tests/EOS/TWAnySignerTests.cpp rename to tests/chains/EOS/TWAnySignerTests.cpp index ea9e2b2b237..e075c7ad8d8 100644 --- a/tests/EOS/TWAnySignerTests.cpp +++ b/tests/chains/EOS/TWAnySignerTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include "HexCoding.h" #include "proto/EOS.pb.h" diff --git a/tests/EOS/TWCoinTypeTests.cpp b/tests/chains/EOS/TWCoinTypeTests.cpp similarity index 97% rename from tests/EOS/TWCoinTypeTests.cpp rename to tests/chains/EOS/TWCoinTypeTests.cpp index 65412f55772..18edd68aa46 100644 --- a/tests/EOS/TWCoinTypeTests.cpp +++ b/tests/chains/EOS/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/EOS/TransactionTests.cpp b/tests/chains/EOS/TransactionTests.cpp similarity index 100% rename from tests/EOS/TransactionTests.cpp rename to tests/chains/EOS/TransactionTests.cpp diff --git a/tests/Elrond/AddressTests.cpp b/tests/chains/Elrond/AddressTests.cpp similarity index 100% rename from tests/Elrond/AddressTests.cpp rename to tests/chains/Elrond/AddressTests.cpp diff --git a/tests/Elrond/SerializationTests.cpp b/tests/chains/Elrond/SerializationTests.cpp similarity index 100% rename from tests/Elrond/SerializationTests.cpp rename to tests/chains/Elrond/SerializationTests.cpp diff --git a/tests/Elrond/SignerTests.cpp b/tests/chains/Elrond/SignerTests.cpp similarity index 100% rename from tests/Elrond/SignerTests.cpp rename to tests/chains/Elrond/SignerTests.cpp diff --git a/tests/Elrond/TWAnySignerTests.cpp b/tests/chains/Elrond/TWAnySignerTests.cpp similarity index 98% rename from tests/Elrond/TWAnySignerTests.cpp rename to tests/chains/Elrond/TWAnySignerTests.cpp index 277864dbe9e..09785661191 100644 --- a/tests/Elrond/TWAnySignerTests.cpp +++ b/tests/chains/Elrond/TWAnySignerTests.cpp @@ -10,7 +10,7 @@ #include "Elrond/Signer.h" #include "HexCoding.h" #include "TestAccounts.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/Elrond/TWCoinTypeTests.cpp b/tests/chains/Elrond/TWCoinTypeTests.cpp similarity index 97% rename from tests/Elrond/TWCoinTypeTests.cpp rename to tests/chains/Elrond/TWCoinTypeTests.cpp index 900d36abd6d..1f7a977bdc0 100644 --- a/tests/Elrond/TWCoinTypeTests.cpp +++ b/tests/chains/Elrond/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Elrond/TestAccounts.h b/tests/chains/Elrond/TestAccounts.h similarity index 100% rename from tests/Elrond/TestAccounts.h rename to tests/chains/Elrond/TestAccounts.h diff --git a/tests/Elrond/TransactionFactoryTests.cpp b/tests/chains/Elrond/TransactionFactoryTests.cpp similarity index 100% rename from tests/Elrond/TransactionFactoryTests.cpp rename to tests/chains/Elrond/TransactionFactoryTests.cpp diff --git a/tests/Ethereum/AbiStructTests.cpp b/tests/chains/Ethereum/AbiStructTests.cpp similarity index 99% rename from tests/Ethereum/AbiStructTests.cpp rename to tests/chains/Ethereum/AbiStructTests.cpp index 7db3e83333b..259fb4ef3f6 100644 --- a/tests/Ethereum/AbiStructTests.cpp +++ b/tests/chains/Ethereum/AbiStructTests.cpp @@ -7,7 +7,7 @@ #include "Ethereum/ABI.h" #include "Ethereum/Address.h" #include "Ethereum/Signer.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include @@ -487,7 +487,7 @@ TEST(EthereumAbiStruct, hashStructJson) { } TEST(EthereumAbiStruct, hashStruct_emptyString) { - auto path = TESTS_ROOT + "/Ethereum/Data/eip712_emptyString.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/eip712_emptyString.json"; auto typeData = load_file(path); auto hash = ParamStruct::hashStructJson(typeData); EXPECT_EQ(hex(hash), "bc9d33285c5e42b00571f5deaf9636d2e498a6fa50e0d1be81095bded070117a"); @@ -500,7 +500,7 @@ TEST(EthereumAbiStruct, hashStruct_emptyString) { } TEST(EthereumAbiStruct, hashStruct_emptyArray) { - auto path = TESTS_ROOT + "/Ethereum/Data/eip712_emptyArray.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/eip712_emptyArray.json"; auto typeData = load_file(path); auto hash = ParamStruct::hashStructJson(typeData); EXPECT_EQ(hex(hash), "9f1a1bc718e966d683c544aef6fd0b73c85a1d6244af9b64bb8f4a6fa6716086"); @@ -514,7 +514,7 @@ TEST(EthereumAbiStruct, hashStruct_emptyArray) { TEST(EthereumAbiStruct, hashStruct_walletConnect) { // https://github.com/WalletConnect/walletconnect-example-dapp/blob/master/src/helpers/eip712.ts - auto path = TESTS_ROOT + "/Ethereum/Data/eip712_walletconnect.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/eip712_walletconnect.json"; auto typeData = load_file(path); auto hash = ParamStruct::hashStructJson(typeData); EXPECT_EQ(hex(hash), "abc79f527273b9e7bca1b3f1ac6ad1a8431fa6dc34ece900deabcd6969856b5e"); @@ -527,7 +527,7 @@ TEST(EthereumAbiStruct, hashStruct_walletConnect) { } TEST(EthereumAbiStruct, hashStruct_cryptofights) { - auto path = TESTS_ROOT + "/Ethereum/Data/eip712_cryptofights.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/eip712_cryptofights.json"; auto typeData = load_file(path); auto hash = ParamStruct::hashStructJson(typeData); EXPECT_EQ(hex(hash), "db12328a6d193965801548e1174936c3aa7adbe1b54b3535a3c905bd4966467c"); @@ -540,7 +540,7 @@ TEST(EthereumAbiStruct, hashStruct_cryptofights) { } TEST(EthereumAbiStruct, hashStruct_rarible) { - auto path = TESTS_ROOT + "/Ethereum/Data/eip712_rarible.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/eip712_rarible.json"; auto typeData = load_file(path); auto hash = ParamStruct::hashStructJson(typeData); EXPECT_EQ(hex(hash), "df0200de55c05eb55af2597012767ea3af653d68000be49580f8e05acd91d366"); @@ -553,7 +553,7 @@ TEST(EthereumAbiStruct, hashStruct_rarible) { } TEST(EthereumAbiStruct, hashStruct_snapshot) { - auto path = TESTS_ROOT + "/Ethereum/Data/eip712_snapshot_v4.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/eip712_snapshot_v4.json"; auto typeData = load_file(path); auto hash = ParamStruct::hashStructJson(typeData); EXPECT_EQ(hex(hash), "f558d08ad4a7651dbc9ec028cfcb4a8e6878a249073ef4fa694f85ee95f61c0f"); diff --git a/tests/Ethereum/AbiTests.cpp b/tests/chains/Ethereum/AbiTests.cpp similarity index 99% rename from tests/Ethereum/AbiTests.cpp rename to tests/chains/Ethereum/AbiTests.cpp index 598fc454f86..3575dcb0f95 100644 --- a/tests/Ethereum/AbiTests.cpp +++ b/tests/chains/Ethereum/AbiTests.cpp @@ -6,7 +6,7 @@ #include "Ethereum/ABI.h" #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/Ethereum/AddressTests.cpp b/tests/chains/Ethereum/AddressTests.cpp similarity index 100% rename from tests/Ethereum/AddressTests.cpp rename to tests/chains/Ethereum/AddressTests.cpp diff --git a/tests/Ethereum/ContractCallTests.cpp b/tests/chains/Ethereum/ContractCallTests.cpp similarity index 95% rename from tests/Ethereum/ContractCallTests.cpp rename to tests/chains/Ethereum/ContractCallTests.cpp index f338581c242..bf21bcd21cb 100644 --- a/tests/Ethereum/ContractCallTests.cpp +++ b/tests/chains/Ethereum/ContractCallTests.cpp @@ -22,7 +22,7 @@ static nlohmann::json load_json(std::string path) { } TEST(ContractCall, Approval) { - auto path = TESTS_ROOT + "/Ethereum/Data/erc20.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/erc20.json"; auto abi = load_json(path); auto call = parse_hex("095ea7b30000000000000000000000005aaeb6053f3e94c9b9a09f33669435e7ef1beaed" "0000000000000000000000000000000000000000000000000000000000000001"); @@ -35,7 +35,7 @@ TEST(ContractCall, Approval) { } TEST(ContractCall, UniswapSwapTokens) { - auto path = TESTS_ROOT + "/Ethereum/Data/uniswap_router_v2.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/uniswap_router_v2.json"; auto abi = load_json(path); // https://etherscan.io/tx/0x57a2414f3cd9ca373b7e663ae67ecf933e40cb77a6e4ed28e4e28b5aa0d8ec63 auto call = parse_hex( @@ -55,7 +55,7 @@ TEST(ContractCall, UniswapSwapTokens) { } TEST(ContractCall, KyberTrade) { - auto path = TESTS_ROOT + "/Ethereum/Data/kyber_proxy.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/kyber_proxy.json"; auto abi = load_json(path); // https://etherscan.io/tx/0x51ffab782b9a27d754389505d5a50db525c04c68142ce20512d579f10f9e13e4 @@ -77,7 +77,7 @@ TEST(ContractCall, KyberTrade) { } TEST(ContractCall, ApprovalForAll) { - auto path = TESTS_ROOT + "/Ethereum/Data/erc721.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/erc721.json"; auto abi = load_json(path); // https://etherscan.io/tx/0xc2744000a107aee4761cf8a638657f91c3003a54e2f1818c37d781be7e48187a @@ -92,7 +92,7 @@ TEST(ContractCall, ApprovalForAll) { } TEST(ContractCall, CustomCall) { - auto path = TESTS_ROOT + "/Ethereum/Data/custom.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/custom.json"; auto abi = load_json(path); auto call = parse_hex("ec37a4a000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000067472757374790000000000000000000000000000000000000000000000000000"); @@ -106,7 +106,7 @@ TEST(ContractCall, CustomCall) { TEST(ContractCall, SetResolver) { auto call = parse_hex("0x1896f70ae71cd96d4ba1c4b512b0c5bee30d2b6becf61e574c32a17a67156fa9ed3c4c" "6f0000000000000000000000004976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41"); - auto path = TESTS_ROOT + "/Ethereum/Data/ens.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/ens.json"; auto abi = load_json(path); auto decoded = decodeCall(call, abi); auto expected = @@ -120,7 +120,7 @@ TEST(ContractCall, RenewENS) { "0xacf1a84100000000000000000000000000000000000000000000000000000000000000400000000000000000" "000000000000000000000000000000000000000001e18558000000000000000000000000000000000000000000" "000000000000000000000a68657769676f76656e7300000000000000000000000000000000000000000000"); - auto path = TESTS_ROOT + "/Ethereum/Data/ens.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/ens.json"; auto abi = load_json(path); auto decoded = decodeCall(call, abi); auto expected = @@ -153,7 +153,7 @@ TEST(ContractCall, Multicall) { "000000000000000000000000000000000014d30f834b53d8f7e851e87b90ffa65757a35b850500000000000000" "000000000000000000000000000000000000000000000000000000000000000000"); ASSERT_EQ(4 + 928ul, call.size()); - auto path = TESTS_ROOT + "/Ethereum/Data/ens.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/ens.json"; auto abi = load_json(path); auto decoded = decodeCall(call, abi); auto expected = @@ -174,7 +174,7 @@ TEST(ContractCall, GetAmountsOut) { "0000000000000000000000000000000000000000000000000000000000000040" "0000000000000000000000000000000000000000000000000000000000000001" "000000000000000000000000f784682c82526e245f50975190ef0fff4e4fc077"); - auto path = TESTS_ROOT + "/Ethereum/Data/getAmountsOut.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/getAmountsOut.json"; auto abi = load_json(path); auto decoded = decodeCall(call, abi); @@ -185,7 +185,7 @@ TEST(ContractCall, GetAmountsOut) { } TEST(ContractCall, 1inch) { - auto path = TESTS_ROOT + "/Ethereum/Data/1inch.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/1inch.json"; auto abi = load_json(path); // https://etherscan.io/tx/0xc2d113151124579c21332d4cc6ab2b7f61e81d62392ed8596174513cb47e35ba @@ -199,7 +199,7 @@ TEST(ContractCall, 1inch) { } TEST(ContractCall, TupleNested) { - auto path = TESTS_ROOT + "/Ethereum/Data/tuple_nested.json"; + auto path = TESTS_ROOT + "/chains/Ethereum/Data/tuple_nested.json"; auto abi = load_json(path); auto call = parse_hex( diff --git a/tests/Ethereum/Data/1inch.json b/tests/chains/Ethereum/Data/1inch.json similarity index 100% rename from tests/Ethereum/Data/1inch.json rename to tests/chains/Ethereum/Data/1inch.json diff --git a/tests/Ethereum/Data/custom.json b/tests/chains/Ethereum/Data/custom.json similarity index 100% rename from tests/Ethereum/Data/custom.json rename to tests/chains/Ethereum/Data/custom.json diff --git a/tests/Ethereum/Data/eip712_cryptofights.json b/tests/chains/Ethereum/Data/eip712_cryptofights.json similarity index 100% rename from tests/Ethereum/Data/eip712_cryptofights.json rename to tests/chains/Ethereum/Data/eip712_cryptofights.json diff --git a/tests/Ethereum/Data/eip712_emptyArray.json b/tests/chains/Ethereum/Data/eip712_emptyArray.json similarity index 100% rename from tests/Ethereum/Data/eip712_emptyArray.json rename to tests/chains/Ethereum/Data/eip712_emptyArray.json diff --git a/tests/Ethereum/Data/eip712_emptyString.json b/tests/chains/Ethereum/Data/eip712_emptyString.json similarity index 100% rename from tests/Ethereum/Data/eip712_emptyString.json rename to tests/chains/Ethereum/Data/eip712_emptyString.json diff --git a/tests/Ethereum/Data/eip712_rarible.json b/tests/chains/Ethereum/Data/eip712_rarible.json similarity index 100% rename from tests/Ethereum/Data/eip712_rarible.json rename to tests/chains/Ethereum/Data/eip712_rarible.json diff --git a/tests/Ethereum/Data/eip712_snapshot_v4.json b/tests/chains/Ethereum/Data/eip712_snapshot_v4.json similarity index 100% rename from tests/Ethereum/Data/eip712_snapshot_v4.json rename to tests/chains/Ethereum/Data/eip712_snapshot_v4.json diff --git a/tests/Ethereum/Data/eip712_walletconnect.json b/tests/chains/Ethereum/Data/eip712_walletconnect.json similarity index 100% rename from tests/Ethereum/Data/eip712_walletconnect.json rename to tests/chains/Ethereum/Data/eip712_walletconnect.json diff --git a/tests/Ethereum/Data/ens.json b/tests/chains/Ethereum/Data/ens.json similarity index 100% rename from tests/Ethereum/Data/ens.json rename to tests/chains/Ethereum/Data/ens.json diff --git a/tests/Ethereum/Data/erc20.json b/tests/chains/Ethereum/Data/erc20.json similarity index 100% rename from tests/Ethereum/Data/erc20.json rename to tests/chains/Ethereum/Data/erc20.json diff --git a/tests/Ethereum/Data/erc721.json b/tests/chains/Ethereum/Data/erc721.json similarity index 100% rename from tests/Ethereum/Data/erc721.json rename to tests/chains/Ethereum/Data/erc721.json diff --git a/tests/Ethereum/Data/eth_feeHistory.json b/tests/chains/Ethereum/Data/eth_feeHistory.json similarity index 100% rename from tests/Ethereum/Data/eth_feeHistory.json rename to tests/chains/Ethereum/Data/eth_feeHistory.json diff --git a/tests/Ethereum/Data/eth_feeHistory2.json b/tests/chains/Ethereum/Data/eth_feeHistory2.json similarity index 100% rename from tests/Ethereum/Data/eth_feeHistory2.json rename to tests/chains/Ethereum/Data/eth_feeHistory2.json diff --git a/tests/Ethereum/Data/eth_feeHistory3.json b/tests/chains/Ethereum/Data/eth_feeHistory3.json similarity index 100% rename from tests/Ethereum/Data/eth_feeHistory3.json rename to tests/chains/Ethereum/Data/eth_feeHistory3.json diff --git a/tests/Ethereum/Data/eth_feeHistory4.json b/tests/chains/Ethereum/Data/eth_feeHistory4.json similarity index 100% rename from tests/Ethereum/Data/eth_feeHistory4.json rename to tests/chains/Ethereum/Data/eth_feeHistory4.json diff --git a/tests/Ethereum/Data/getAmountsOut.json b/tests/chains/Ethereum/Data/getAmountsOut.json similarity index 100% rename from tests/Ethereum/Data/getAmountsOut.json rename to tests/chains/Ethereum/Data/getAmountsOut.json diff --git a/tests/Ethereum/Data/kyber_proxy.json b/tests/chains/Ethereum/Data/kyber_proxy.json similarity index 100% rename from tests/Ethereum/Data/kyber_proxy.json rename to tests/chains/Ethereum/Data/kyber_proxy.json diff --git a/tests/Ethereum/Data/seaport_712.json b/tests/chains/Ethereum/Data/seaport_712.json similarity index 100% rename from tests/Ethereum/Data/seaport_712.json rename to tests/chains/Ethereum/Data/seaport_712.json diff --git a/tests/Ethereum/Data/tuple_nested.json b/tests/chains/Ethereum/Data/tuple_nested.json similarity index 100% rename from tests/Ethereum/Data/tuple_nested.json rename to tests/chains/Ethereum/Data/tuple_nested.json diff --git a/tests/Ethereum/Data/uniswap_router_v2.json b/tests/chains/Ethereum/Data/uniswap_router_v2.json similarity index 100% rename from tests/Ethereum/Data/uniswap_router_v2.json rename to tests/chains/Ethereum/Data/uniswap_router_v2.json diff --git a/tests/Ethereum/Data/zilliqa_data_tx.json b/tests/chains/Ethereum/Data/zilliqa_data_tx.json similarity index 100% rename from tests/Ethereum/Data/zilliqa_data_tx.json rename to tests/chains/Ethereum/Data/zilliqa_data_tx.json diff --git a/tests/Ethereum/RLPTests.cpp b/tests/chains/Ethereum/RLPTests.cpp similarity index 100% rename from tests/Ethereum/RLPTests.cpp rename to tests/chains/Ethereum/RLPTests.cpp diff --git a/tests/Ethereum/SignerTests.cpp b/tests/chains/Ethereum/SignerTests.cpp similarity index 100% rename from tests/Ethereum/SignerTests.cpp rename to tests/chains/Ethereum/SignerTests.cpp diff --git a/tests/Ethereum/TWAnySignerTests.cpp b/tests/chains/Ethereum/TWAnySignerTests.cpp similarity index 99% rename from tests/Ethereum/TWAnySignerTests.cpp rename to tests/chains/Ethereum/TWAnySignerTests.cpp index 727966fa8d8..c50cef17583 100644 --- a/tests/Ethereum/TWAnySignerTests.cpp +++ b/tests/chains/Ethereum/TWAnySignerTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include "HexCoding.h" #include "uint256.h" diff --git a/tests/Ethereum/TWCoinTypeTests.cpp b/tests/chains/Ethereum/TWCoinTypeTests.cpp similarity index 97% rename from tests/Ethereum/TWCoinTypeTests.cpp rename to tests/chains/Ethereum/TWCoinTypeTests.cpp index 128fa78357e..39878ade96c 100644 --- a/tests/Ethereum/TWCoinTypeTests.cpp +++ b/tests/chains/Ethereum/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Ethereum/TWEthereumAbiTests.cpp b/tests/chains/Ethereum/TWEthereumAbiTests.cpp similarity index 99% rename from tests/Ethereum/TWEthereumAbiTests.cpp rename to tests/chains/Ethereum/TWEthereumAbiTests.cpp index be8a59d4731..9cb63bd7569 100644 --- a/tests/Ethereum/TWEthereumAbiTests.cpp +++ b/tests/chains/Ethereum/TWEthereumAbiTests.cpp @@ -13,7 +13,7 @@ #include "HexCoding.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Ethereum/TWEthereumAbiValueDecoderTests.cpp b/tests/chains/Ethereum/TWEthereumAbiValueDecoderTests.cpp similarity index 99% rename from tests/Ethereum/TWEthereumAbiValueDecoderTests.cpp rename to tests/chains/Ethereum/TWEthereumAbiValueDecoderTests.cpp index 2f84327195b..da8dcc4b728 100644 --- a/tests/Ethereum/TWEthereumAbiValueDecoderTests.cpp +++ b/tests/chains/Ethereum/TWEthereumAbiValueDecoderTests.cpp @@ -8,7 +8,7 @@ #include "Data.h" #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/Ethereum/TWEthereumAbiValueEncodeTests.cpp b/tests/chains/Ethereum/TWEthereumAbiValueEncodeTests.cpp similarity index 98% rename from tests/Ethereum/TWEthereumAbiValueEncodeTests.cpp rename to tests/chains/Ethereum/TWEthereumAbiValueEncodeTests.cpp index b4b120adbd3..7235666c804 100644 --- a/tests/Ethereum/TWEthereumAbiValueEncodeTests.cpp +++ b/tests/chains/Ethereum/TWEthereumAbiValueEncodeTests.cpp @@ -9,7 +9,7 @@ #include "Data.h" #include "HexCoding.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/Ethereum/ValueDecoderTests.cpp b/tests/chains/Ethereum/ValueDecoderTests.cpp similarity index 100% rename from tests/Ethereum/ValueDecoderTests.cpp rename to tests/chains/Ethereum/ValueDecoderTests.cpp diff --git a/tests/Ethereum/ValueEncoderTests.cpp b/tests/chains/Ethereum/ValueEncoderTests.cpp similarity index 100% rename from tests/Ethereum/ValueEncoderTests.cpp rename to tests/chains/Ethereum/ValueEncoderTests.cpp diff --git a/tests/EthereumClassic/TWCoinTypeTests.cpp b/tests/chains/EthereumClassic/TWCoinTypeTests.cpp similarity index 97% rename from tests/EthereumClassic/TWCoinTypeTests.cpp rename to tests/chains/EthereumClassic/TWCoinTypeTests.cpp index 4e0183374fe..6ac2854fa36 100644 --- a/tests/EthereumClassic/TWCoinTypeTests.cpp +++ b/tests/chains/EthereumClassic/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Everscale/AddressTests.cpp b/tests/chains/Everscale/AddressTests.cpp similarity index 100% rename from tests/Everscale/AddressTests.cpp rename to tests/chains/Everscale/AddressTests.cpp diff --git a/tests/Everscale/CellBuilderTest.cpp b/tests/chains/Everscale/CellBuilderTest.cpp similarity index 100% rename from tests/Everscale/CellBuilderTest.cpp rename to tests/chains/Everscale/CellBuilderTest.cpp diff --git a/tests/Everscale/CellTests.cpp b/tests/chains/Everscale/CellTests.cpp similarity index 100% rename from tests/Everscale/CellTests.cpp rename to tests/chains/Everscale/CellTests.cpp diff --git a/tests/Everscale/SignerTests.cpp b/tests/chains/Everscale/SignerTests.cpp similarity index 100% rename from tests/Everscale/SignerTests.cpp rename to tests/chains/Everscale/SignerTests.cpp diff --git a/tests/Everscale/TWAnyAddressTests.cpp b/tests/chains/Everscale/TWAnyAddressTests.cpp similarity index 96% rename from tests/Everscale/TWAnyAddressTests.cpp rename to tests/chains/Everscale/TWAnyAddressTests.cpp index 74d1212ec58..6cf7627b0f6 100644 --- a/tests/Everscale/TWAnyAddressTests.cpp +++ b/tests/chains/Everscale/TWAnyAddressTests.cpp @@ -7,7 +7,7 @@ #include #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include namespace TW::Everscale { diff --git a/tests/Everscale/TWAnySignerTests.cpp b/tests/chains/Everscale/TWAnySignerTests.cpp similarity index 97% rename from tests/Everscale/TWAnySignerTests.cpp rename to tests/chains/Everscale/TWAnySignerTests.cpp index 0dbae0871ee..d404ce00210 100644 --- a/tests/Everscale/TWAnySignerTests.cpp +++ b/tests/chains/Everscale/TWAnySignerTests.cpp @@ -9,7 +9,7 @@ #include "proto/Everscale.pb.h" #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include namespace TW::Everscale { diff --git a/tests/Everscale/TWCoinTypeTests.cpp b/tests/chains/Everscale/TWCoinTypeTests.cpp similarity index 97% rename from tests/Everscale/TWCoinTypeTests.cpp rename to tests/chains/Everscale/TWCoinTypeTests.cpp index b737fe7dc63..95a9297cef2 100644 --- a/tests/Everscale/TWCoinTypeTests.cpp +++ b/tests/chains/Everscale/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Evmos/SignerTests.cpp b/tests/chains/Evmos/SignerTests.cpp similarity index 99% rename from tests/Evmos/SignerTests.cpp rename to tests/chains/Evmos/SignerTests.cpp index 53f599038eb..0dc9d3e816c 100644 --- a/tests/Evmos/SignerTests.cpp +++ b/tests/chains/Evmos/SignerTests.cpp @@ -9,7 +9,7 @@ #include "proto/Cosmos.pb.h" #include "Cosmos/Address.h" #include "Cosmos/Signer.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/Evmos/TWAnyAddressTests.cpp b/tests/chains/Evmos/TWAnyAddressTests.cpp similarity index 97% rename from tests/Evmos/TWAnyAddressTests.cpp rename to tests/chains/Evmos/TWAnyAddressTests.cpp index 5f52cdbf5c4..de3468d4cce 100644 --- a/tests/Evmos/TWAnyAddressTests.cpp +++ b/tests/chains/Evmos/TWAnyAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Evmos/TWCoinTypeTests.cpp b/tests/chains/Evmos/TWCoinTypeTests.cpp similarity index 97% rename from tests/Evmos/TWCoinTypeTests.cpp rename to tests/chains/Evmos/TWCoinTypeTests.cpp index 9e5fdcf643e..346d9c98117 100644 --- a/tests/Evmos/TWCoinTypeTests.cpp +++ b/tests/chains/Evmos/TWCoinTypeTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/FIO/AddressTests.cpp b/tests/chains/FIO/AddressTests.cpp similarity index 100% rename from tests/FIO/AddressTests.cpp rename to tests/chains/FIO/AddressTests.cpp diff --git a/tests/FIO/EncryptionTests.cpp b/tests/chains/FIO/EncryptionTests.cpp similarity index 100% rename from tests/FIO/EncryptionTests.cpp rename to tests/chains/FIO/EncryptionTests.cpp diff --git a/tests/FIO/SignerTests.cpp b/tests/chains/FIO/SignerTests.cpp similarity index 100% rename from tests/FIO/SignerTests.cpp rename to tests/chains/FIO/SignerTests.cpp diff --git a/tests/FIO/TWCoinTypeTests.cpp b/tests/chains/FIO/TWCoinTypeTests.cpp similarity index 97% rename from tests/FIO/TWCoinTypeTests.cpp rename to tests/chains/FIO/TWCoinTypeTests.cpp index fcbb7a47bb6..2dec77e3723 100644 --- a/tests/FIO/TWCoinTypeTests.cpp +++ b/tests/chains/FIO/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/FIO/TWFIOAccountTests.cpp b/tests/chains/FIO/TWFIOAccountTests.cpp similarity index 97% rename from tests/FIO/TWFIOAccountTests.cpp rename to tests/chains/FIO/TWFIOAccountTests.cpp index 3c4764d4801..e9b0f948a09 100644 --- a/tests/FIO/TWFIOAccountTests.cpp +++ b/tests/chains/FIO/TWFIOAccountTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/FIO/TWFIOTests.cpp b/tests/chains/FIO/TWFIOTests.cpp similarity index 99% rename from tests/FIO/TWFIOTests.cpp rename to tests/chains/FIO/TWFIOTests.cpp index 4460eff762a..9777e10f5c5 100644 --- a/tests/FIO/TWFIOTests.cpp +++ b/tests/chains/FIO/TWFIOTests.cpp @@ -10,7 +10,7 @@ #include "proto/FIO.pb.h" #include "FIO/Address.h" #include "Data.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "HexCoding.h" #include "PrivateKey.h" diff --git a/tests/FIO/TransactionBuilderTests.cpp b/tests/chains/FIO/TransactionBuilderTests.cpp similarity index 100% rename from tests/FIO/TransactionBuilderTests.cpp rename to tests/chains/FIO/TransactionBuilderTests.cpp diff --git a/tests/Fantom/TWCoinTypeTests.cpp b/tests/chains/Fantom/TWCoinTypeTests.cpp similarity index 97% rename from tests/Fantom/TWCoinTypeTests.cpp rename to tests/chains/Fantom/TWCoinTypeTests.cpp index acd79755342..15dcde31182 100644 --- a/tests/Fantom/TWCoinTypeTests.cpp +++ b/tests/chains/Fantom/TWCoinTypeTests.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Filecoin/AddressTests.cpp b/tests/chains/Filecoin/AddressTests.cpp similarity index 100% rename from tests/Filecoin/AddressTests.cpp rename to tests/chains/Filecoin/AddressTests.cpp diff --git a/tests/Filecoin/SignerTests.cpp b/tests/chains/Filecoin/SignerTests.cpp similarity index 100% rename from tests/Filecoin/SignerTests.cpp rename to tests/chains/Filecoin/SignerTests.cpp diff --git a/tests/Filecoin/TWAnySignerTests.cpp b/tests/chains/Filecoin/TWAnySignerTests.cpp similarity index 98% rename from tests/Filecoin/TWAnySignerTests.cpp rename to tests/chains/Filecoin/TWAnySignerTests.cpp index 0f7c0ae4d5c..a4af47a4332 100644 --- a/tests/Filecoin/TWAnySignerTests.cpp +++ b/tests/chains/Filecoin/TWAnySignerTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include "Data.h" diff --git a/tests/Filecoin/TWCoinTypeTests.cpp b/tests/chains/Filecoin/TWCoinTypeTests.cpp similarity index 97% rename from tests/Filecoin/TWCoinTypeTests.cpp rename to tests/chains/Filecoin/TWCoinTypeTests.cpp index 9e5ff95f72e..16d5499b5b1 100644 --- a/tests/Filecoin/TWCoinTypeTests.cpp +++ b/tests/chains/Filecoin/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Filecoin/TransactionTests.cpp b/tests/chains/Filecoin/TransactionTests.cpp similarity index 100% rename from tests/Filecoin/TransactionTests.cpp rename to tests/chains/Filecoin/TransactionTests.cpp diff --git a/tests/Firo/TWCoinTypeTests.cpp b/tests/chains/Firo/TWCoinTypeTests.cpp similarity index 97% rename from tests/Firo/TWCoinTypeTests.cpp rename to tests/chains/Firo/TWCoinTypeTests.cpp index b8e7a60f49b..2f22a9c23ac 100644 --- a/tests/Firo/TWCoinTypeTests.cpp +++ b/tests/chains/Firo/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Firo/TWZCoinAddressTests.cpp b/tests/chains/Firo/TWZCoinAddressTests.cpp similarity index 98% rename from tests/Firo/TWZCoinAddressTests.cpp rename to tests/chains/Firo/TWZCoinAddressTests.cpp index 21c495364e5..33ccf2516e8 100644 --- a/tests/Firo/TWZCoinAddressTests.cpp +++ b/tests/chains/Firo/TWZCoinAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/GoChain/TWCoinTypeTests.cpp b/tests/chains/GoChain/TWCoinTypeTests.cpp similarity index 97% rename from tests/GoChain/TWCoinTypeTests.cpp rename to tests/chains/GoChain/TWCoinTypeTests.cpp index 7e8b1b75a94..70e8170b723 100644 --- a/tests/GoChain/TWCoinTypeTests.cpp +++ b/tests/chains/GoChain/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Groestlcoin/AddressTests.cpp b/tests/chains/Groestlcoin/AddressTests.cpp similarity index 100% rename from tests/Groestlcoin/AddressTests.cpp rename to tests/chains/Groestlcoin/AddressTests.cpp diff --git a/tests/Groestlcoin/TWCoinTypeTests.cpp b/tests/chains/Groestlcoin/TWCoinTypeTests.cpp similarity index 97% rename from tests/Groestlcoin/TWCoinTypeTests.cpp rename to tests/chains/Groestlcoin/TWCoinTypeTests.cpp index 6187d5d4e85..2cb15c927b2 100644 --- a/tests/Groestlcoin/TWCoinTypeTests.cpp +++ b/tests/chains/Groestlcoin/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Groestlcoin/TWGroestlcoinSigningTests.cpp b/tests/chains/Groestlcoin/TWGroestlcoinSigningTests.cpp similarity index 99% rename from tests/Groestlcoin/TWGroestlcoinSigningTests.cpp rename to tests/chains/Groestlcoin/TWGroestlcoinSigningTests.cpp index b2c7127d6e5..994c8977942 100644 --- a/tests/Groestlcoin/TWGroestlcoinSigningTests.cpp +++ b/tests/chains/Groestlcoin/TWGroestlcoinSigningTests.cpp @@ -9,7 +9,7 @@ #include "HexCoding.h" #include "PrivateKey.h" #include "proto/Bitcoin.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "../Bitcoin/TxComparisonHelper.h" #include #include diff --git a/tests/Groestlcoin/TWGroestlcoinTests.cpp b/tests/chains/Groestlcoin/TWGroestlcoinTests.cpp similarity index 99% rename from tests/Groestlcoin/TWGroestlcoinTests.cpp rename to tests/chains/Groestlcoin/TWGroestlcoinTests.cpp index a00b684b019..e685bc59646 100644 --- a/tests/Groestlcoin/TWGroestlcoinTests.cpp +++ b/tests/chains/Groestlcoin/TWGroestlcoinTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Harmony/AddressTests.cpp b/tests/chains/Harmony/AddressTests.cpp similarity index 100% rename from tests/Harmony/AddressTests.cpp rename to tests/chains/Harmony/AddressTests.cpp diff --git a/tests/Harmony/SignerTests.cpp b/tests/chains/Harmony/SignerTests.cpp similarity index 100% rename from tests/Harmony/SignerTests.cpp rename to tests/chains/Harmony/SignerTests.cpp diff --git a/tests/Harmony/StakingTests.cpp b/tests/chains/Harmony/StakingTests.cpp similarity index 100% rename from tests/Harmony/StakingTests.cpp rename to tests/chains/Harmony/StakingTests.cpp diff --git a/tests/Harmony/TWAnyAddressTests.cpp b/tests/chains/Harmony/TWAnyAddressTests.cpp similarity index 95% rename from tests/Harmony/TWAnyAddressTests.cpp rename to tests/chains/Harmony/TWAnyAddressTests.cpp index 759eef52c84..a289284b229 100644 --- a/tests/Harmony/TWAnyAddressTests.cpp +++ b/tests/chains/Harmony/TWAnyAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Harmony/TWAnySignerTests.cpp b/tests/chains/Harmony/TWAnySignerTests.cpp similarity index 98% rename from tests/Harmony/TWAnySignerTests.cpp rename to tests/chains/Harmony/TWAnySignerTests.cpp index 5278c3ff18e..3edae0c8247 100644 --- a/tests/Harmony/TWAnySignerTests.cpp +++ b/tests/chains/Harmony/TWAnySignerTests.cpp @@ -8,7 +8,7 @@ #include "HexCoding.h" #include "proto/Harmony.pb.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Harmony/TWCoinTypeTests.cpp b/tests/chains/Harmony/TWCoinTypeTests.cpp similarity index 97% rename from tests/Harmony/TWCoinTypeTests.cpp rename to tests/chains/Harmony/TWCoinTypeTests.cpp index 5541e8ca94f..1147cfeb362 100644 --- a/tests/Harmony/TWCoinTypeTests.cpp +++ b/tests/chains/Harmony/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Harmony/TWHarmonyStakingTests.cpp b/tests/chains/Harmony/TWHarmonyStakingTests.cpp similarity index 99% rename from tests/Harmony/TWHarmonyStakingTests.cpp rename to tests/chains/Harmony/TWHarmonyStakingTests.cpp index 9492225f7a7..164d37edacb 100644 --- a/tests/Harmony/TWHarmonyStakingTests.cpp +++ b/tests/chains/Harmony/TWHarmonyStakingTests.cpp @@ -9,7 +9,7 @@ #include "Harmony/Staking.h" #include "HexCoding.h" #include "PrivateKey.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "proto/Harmony.pb.h" #include "uint256.h" #include diff --git a/tests/Icon/AddressTests.cpp b/tests/chains/ICON/AddressTests.cpp similarity index 100% rename from tests/Icon/AddressTests.cpp rename to tests/chains/ICON/AddressTests.cpp diff --git a/tests/Icon/TWAnySignerTests.cpp b/tests/chains/ICON/TWAnySignerTests.cpp similarity index 97% rename from tests/Icon/TWAnySignerTests.cpp rename to tests/chains/ICON/TWAnySignerTests.cpp index ca9f6b070d3..74a57537568 100644 --- a/tests/Icon/TWAnySignerTests.cpp +++ b/tests/chains/ICON/TWAnySignerTests.cpp @@ -9,7 +9,7 @@ #include "HexCoding.h" #include "proto/Icon.pb.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/ICON/TWCoinTypeTests.cpp b/tests/chains/ICON/TWCoinTypeTests.cpp similarity index 97% rename from tests/ICON/TWCoinTypeTests.cpp rename to tests/chains/ICON/TWCoinTypeTests.cpp index bffbd0459f0..5fc84a70033 100644 --- a/tests/ICON/TWCoinTypeTests.cpp +++ b/tests/chains/ICON/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/IoTeX/AddressTests.cpp b/tests/chains/IoTeX/AddressTests.cpp similarity index 100% rename from tests/IoTeX/AddressTests.cpp rename to tests/chains/IoTeX/AddressTests.cpp diff --git a/tests/IoTeX/SignerTests.cpp b/tests/chains/IoTeX/SignerTests.cpp similarity index 100% rename from tests/IoTeX/SignerTests.cpp rename to tests/chains/IoTeX/SignerTests.cpp diff --git a/tests/IoTeX/StakingTests.cpp b/tests/chains/IoTeX/StakingTests.cpp similarity index 99% rename from tests/IoTeX/StakingTests.cpp rename to tests/chains/IoTeX/StakingTests.cpp index 8a2008b1908..e5f37330dee 100644 --- a/tests/IoTeX/StakingTests.cpp +++ b/tests/chains/IoTeX/StakingTests.cpp @@ -8,7 +8,7 @@ #include "HexCoding.h" #include "IoTeX/Staking.h" #include "proto/IoTeX.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/IoTeX/TWAnySignerTests.cpp b/tests/chains/IoTeX/TWAnySignerTests.cpp similarity index 97% rename from tests/IoTeX/TWAnySignerTests.cpp rename to tests/chains/IoTeX/TWAnySignerTests.cpp index 9807a5dfb8a..4fbeafd20ac 100644 --- a/tests/IoTeX/TWAnySignerTests.cpp +++ b/tests/chains/IoTeX/TWAnySignerTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include "HexCoding.h" #include "proto/IoTeX.pb.h" diff --git a/tests/IoTeX/TWCoinTypeTests.cpp b/tests/chains/IoTeX/TWCoinTypeTests.cpp similarity index 97% rename from tests/IoTeX/TWCoinTypeTests.cpp rename to tests/chains/IoTeX/TWCoinTypeTests.cpp index ce42df73442..4cdc2d68ad4 100644 --- a/tests/IoTeX/TWCoinTypeTests.cpp +++ b/tests/chains/IoTeX/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Kava/TWCoinTypeTests.cpp b/tests/chains/Kava/TWCoinTypeTests.cpp similarity index 97% rename from tests/Kava/TWCoinTypeTests.cpp rename to tests/chains/Kava/TWCoinTypeTests.cpp index 0852f499368..fd4a19b7412 100644 --- a/tests/Kava/TWCoinTypeTests.cpp +++ b/tests/chains/Kava/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/KavaEvm/TWCoinTypeTests.cpp b/tests/chains/KavaEvm/TWCoinTypeTests.cpp similarity index 97% rename from tests/KavaEvm/TWCoinTypeTests.cpp rename to tests/chains/KavaEvm/TWCoinTypeTests.cpp index 70b1d91b97c..a658eba031a 100644 --- a/tests/KavaEvm/TWCoinTypeTests.cpp +++ b/tests/chains/KavaEvm/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Kin/TWCoinTypeTests.cpp b/tests/chains/Kin/TWCoinTypeTests.cpp similarity index 97% rename from tests/Kin/TWCoinTypeTests.cpp rename to tests/chains/Kin/TWCoinTypeTests.cpp index 9120ef0e2f9..8f37b7f3607 100644 --- a/tests/Kin/TWCoinTypeTests.cpp +++ b/tests/chains/Kin/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Klaytn/TWCoinTypeTests.cpp b/tests/chains/Klaytn/TWCoinTypeTests.cpp similarity index 97% rename from tests/Klaytn/TWCoinTypeTests.cpp rename to tests/chains/Klaytn/TWCoinTypeTests.cpp index 9f293370262..d7eb5c71136 100644 --- a/tests/Klaytn/TWCoinTypeTests.cpp +++ b/tests/chains/Klaytn/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/KuCoinCommunityChain/TWCoinTypeTests.cpp b/tests/chains/KuCoinCommunityChain/TWCoinTypeTests.cpp similarity index 97% rename from tests/KuCoinCommunityChain/TWCoinTypeTests.cpp rename to tests/chains/KuCoinCommunityChain/TWCoinTypeTests.cpp index c8069645912..354bc8b7ba1 100644 --- a/tests/KuCoinCommunityChain/TWCoinTypeTests.cpp +++ b/tests/chains/KuCoinCommunityChain/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Kusama/AddressTests.cpp b/tests/chains/Kusama/AddressTests.cpp similarity index 100% rename from tests/Kusama/AddressTests.cpp rename to tests/chains/Kusama/AddressTests.cpp diff --git a/tests/Kusama/SignerTests.cpp b/tests/chains/Kusama/SignerTests.cpp similarity index 100% rename from tests/Kusama/SignerTests.cpp rename to tests/chains/Kusama/SignerTests.cpp diff --git a/tests/Kusama/TWAnySignerTests.cpp b/tests/chains/Kusama/TWAnySignerTests.cpp similarity index 97% rename from tests/Kusama/TWAnySignerTests.cpp rename to tests/chains/Kusama/TWAnySignerTests.cpp index 68875989066..c23abdd9acb 100644 --- a/tests/Kusama/TWAnySignerTests.cpp +++ b/tests/chains/Kusama/TWAnySignerTests.cpp @@ -7,7 +7,7 @@ #include "HexCoding.h" #include "proto/Polkadot.pb.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Kusama/TWCoinTypeTests.cpp b/tests/chains/Kusama/TWCoinTypeTests.cpp similarity index 97% rename from tests/Kusama/TWCoinTypeTests.cpp rename to tests/chains/Kusama/TWCoinTypeTests.cpp index 3ea8f9284f5..09cd2bf8c0f 100644 --- a/tests/Kusama/TWCoinTypeTests.cpp +++ b/tests/chains/Kusama/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Litecoin/LitecoinAddressTests.cpp b/tests/chains/Litecoin/LitecoinAddressTests.cpp similarity index 100% rename from tests/Litecoin/LitecoinAddressTests.cpp rename to tests/chains/Litecoin/LitecoinAddressTests.cpp diff --git a/tests/Litecoin/TWCoinTypeTests.cpp b/tests/chains/Litecoin/TWCoinTypeTests.cpp similarity index 97% rename from tests/Litecoin/TWCoinTypeTests.cpp rename to tests/chains/Litecoin/TWCoinTypeTests.cpp index 3d96044505d..441d729e66d 100644 --- a/tests/Litecoin/TWCoinTypeTests.cpp +++ b/tests/chains/Litecoin/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Litecoin/TWLitecoinTests.cpp b/tests/chains/Litecoin/TWLitecoinTests.cpp similarity index 99% rename from tests/Litecoin/TWLitecoinTests.cpp rename to tests/chains/Litecoin/TWLitecoinTests.cpp index 35daa1d0a8c..0008fd375d1 100644 --- a/tests/Litecoin/TWLitecoinTests.cpp +++ b/tests/chains/Litecoin/TWLitecoinTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Meter/TWCoinTypeTests.cpp b/tests/chains/Meter/TWCoinTypeTests.cpp similarity index 97% rename from tests/Meter/TWCoinTypeTests.cpp rename to tests/chains/Meter/TWCoinTypeTests.cpp index 50902798e57..b9c4df9d838 100644 --- a/tests/Meter/TWCoinTypeTests.cpp +++ b/tests/chains/Meter/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Metis/TWCoinTypeTests.cpp b/tests/chains/Metis/TWCoinTypeTests.cpp similarity index 97% rename from tests/Metis/TWCoinTypeTests.cpp rename to tests/chains/Metis/TWCoinTypeTests.cpp index da3e515be54..60733b44741 100644 --- a/tests/Metis/TWCoinTypeTests.cpp +++ b/tests/chains/Metis/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Monacoin/TWCoinTypeTests.cpp b/tests/chains/Monacoin/TWCoinTypeTests.cpp similarity index 97% rename from tests/Monacoin/TWCoinTypeTests.cpp rename to tests/chains/Monacoin/TWCoinTypeTests.cpp index e539e3924e2..82fc75a0c68 100644 --- a/tests/Monacoin/TWCoinTypeTests.cpp +++ b/tests/chains/Monacoin/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Monacoin/TWMonacoinAddressTests.cpp b/tests/chains/Monacoin/TWMonacoinAddressTests.cpp similarity index 99% rename from tests/Monacoin/TWMonacoinAddressTests.cpp rename to tests/chains/Monacoin/TWMonacoinAddressTests.cpp index e8f6c7c985d..d46964f25f5 100644 --- a/tests/Monacoin/TWMonacoinAddressTests.cpp +++ b/tests/chains/Monacoin/TWMonacoinAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Monacoin/TWMonacoinTransactionTests.cpp b/tests/chains/Monacoin/TWMonacoinTransactionTests.cpp similarity index 99% rename from tests/Monacoin/TWMonacoinTransactionTests.cpp rename to tests/chains/Monacoin/TWMonacoinTransactionTests.cpp index 29a70f4045f..94f26493815 100644 --- a/tests/Monacoin/TWMonacoinTransactionTests.cpp +++ b/tests/chains/Monacoin/TWMonacoinTransactionTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "HexCoding.h" #include "PublicKey.h" #include "proto/Bitcoin.pb.h" diff --git a/tests/Moonbeam/TWCoinTypeTests.cpp b/tests/chains/Moonbeam/TWCoinTypeTests.cpp similarity index 97% rename from tests/Moonbeam/TWCoinTypeTests.cpp rename to tests/chains/Moonbeam/TWCoinTypeTests.cpp index 76083ca05e8..0c59369a597 100644 --- a/tests/Moonbeam/TWCoinTypeTests.cpp +++ b/tests/chains/Moonbeam/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Moonriver/TWCoinTypeTests.cpp b/tests/chains/Moonriver/TWCoinTypeTests.cpp similarity index 97% rename from tests/Moonriver/TWCoinTypeTests.cpp rename to tests/chains/Moonriver/TWCoinTypeTests.cpp index 8ef39efaf15..b19f8a84b7b 100644 --- a/tests/Moonriver/TWCoinTypeTests.cpp +++ b/tests/chains/Moonriver/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/NEAR/AccountTests.cpp b/tests/chains/NEAR/AccountTests.cpp similarity index 100% rename from tests/NEAR/AccountTests.cpp rename to tests/chains/NEAR/AccountTests.cpp diff --git a/tests/NEAR/AddressTests.cpp b/tests/chains/NEAR/AddressTests.cpp similarity index 100% rename from tests/NEAR/AddressTests.cpp rename to tests/chains/NEAR/AddressTests.cpp diff --git a/tests/NEAR/SerializationTests.cpp b/tests/chains/NEAR/SerializationTests.cpp similarity index 100% rename from tests/NEAR/SerializationTests.cpp rename to tests/chains/NEAR/SerializationTests.cpp diff --git a/tests/NEAR/SignerTests.cpp b/tests/chains/NEAR/SignerTests.cpp similarity index 100% rename from tests/NEAR/SignerTests.cpp rename to tests/chains/NEAR/SignerTests.cpp diff --git a/tests/NEAR/TWAnySignerTests.cpp b/tests/chains/NEAR/TWAnySignerTests.cpp similarity index 98% rename from tests/NEAR/TWAnySignerTests.cpp rename to tests/chains/NEAR/TWAnySignerTests.cpp index 2f6204022e7..afa81ba9a79 100644 --- a/tests/NEAR/TWAnySignerTests.cpp +++ b/tests/chains/NEAR/TWAnySignerTests.cpp @@ -6,7 +6,7 @@ #include "HexCoding.h" #include "proto/NEAR.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/NEAR/TWCoinTypeTests.cpp b/tests/chains/NEAR/TWCoinTypeTests.cpp similarity index 97% rename from tests/NEAR/TWCoinTypeTests.cpp rename to tests/chains/NEAR/TWCoinTypeTests.cpp index e5b5951a368..c5a04325d1f 100644 --- a/tests/NEAR/TWCoinTypeTests.cpp +++ b/tests/chains/NEAR/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/NEAR/TWNEARAccountTests.cpp b/tests/chains/NEAR/TWNEARAccountTests.cpp similarity index 96% rename from tests/NEAR/TWNEARAccountTests.cpp rename to tests/chains/NEAR/TWNEARAccountTests.cpp index c97ba7d5c0d..0be2cf6dbc7 100644 --- a/tests/NEAR/TWNEARAccountTests.cpp +++ b/tests/chains/NEAR/TWNEARAccountTests.cpp @@ -6,7 +6,7 @@ // // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/NEO/AddressTests.cpp b/tests/chains/NEO/AddressTests.cpp similarity index 100% rename from tests/NEO/AddressTests.cpp rename to tests/chains/NEO/AddressTests.cpp diff --git a/tests/NEO/CoinReferenceTests.cpp b/tests/chains/NEO/CoinReferenceTests.cpp similarity index 100% rename from tests/NEO/CoinReferenceTests.cpp rename to tests/chains/NEO/CoinReferenceTests.cpp diff --git a/tests/NEO/SignerTests.cpp b/tests/chains/NEO/SignerTests.cpp similarity index 100% rename from tests/NEO/SignerTests.cpp rename to tests/chains/NEO/SignerTests.cpp diff --git a/tests/NEO/TWAnySignerTests.cpp b/tests/chains/NEO/TWAnySignerTests.cpp similarity index 99% rename from tests/NEO/TWAnySignerTests.cpp rename to tests/chains/NEO/TWAnySignerTests.cpp index e61fec59506..9a92c1133c0 100644 --- a/tests/NEO/TWAnySignerTests.cpp +++ b/tests/chains/NEO/TWAnySignerTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include "HexCoding.h" #include "proto/NEO.pb.h" diff --git a/tests/NEO/TWCoinTypeTests.cpp b/tests/chains/NEO/TWCoinTypeTests.cpp similarity index 97% rename from tests/NEO/TWCoinTypeTests.cpp rename to tests/chains/NEO/TWCoinTypeTests.cpp index 8b986b73a4d..fa87f98119b 100644 --- a/tests/NEO/TWCoinTypeTests.cpp +++ b/tests/chains/NEO/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/NEO/TWNEOAddressTests.cpp b/tests/chains/NEO/TWNEOAddressTests.cpp similarity index 96% rename from tests/NEO/TWNEOAddressTests.cpp rename to tests/chains/NEO/TWNEOAddressTests.cpp index 029f3bdb95b..cc36db2af5f 100644 --- a/tests/NEO/TWNEOAddressTests.cpp +++ b/tests/chains/NEO/TWNEOAddressTests.cpp @@ -9,7 +9,7 @@ #include #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/NEO/TransactionAttributeTests.cpp b/tests/chains/NEO/TransactionAttributeTests.cpp similarity index 100% rename from tests/NEO/TransactionAttributeTests.cpp rename to tests/chains/NEO/TransactionAttributeTests.cpp diff --git a/tests/NEO/TransactionOutputTests.cpp b/tests/chains/NEO/TransactionOutputTests.cpp similarity index 100% rename from tests/NEO/TransactionOutputTests.cpp rename to tests/chains/NEO/TransactionOutputTests.cpp diff --git a/tests/NEO/TransactionTests.cpp b/tests/chains/NEO/TransactionTests.cpp similarity index 100% rename from tests/NEO/TransactionTests.cpp rename to tests/chains/NEO/TransactionTests.cpp diff --git a/tests/NEO/WitnessTests.cpp b/tests/chains/NEO/WitnessTests.cpp similarity index 100% rename from tests/NEO/WitnessTests.cpp rename to tests/chains/NEO/WitnessTests.cpp diff --git a/tests/NULS/AddressTests.cpp b/tests/chains/NULS/AddressTests.cpp similarity index 100% rename from tests/NULS/AddressTests.cpp rename to tests/chains/NULS/AddressTests.cpp diff --git a/tests/NULS/TWAnySignerTests.cpp b/tests/chains/NULS/TWAnySignerTests.cpp similarity index 97% rename from tests/NULS/TWAnySignerTests.cpp rename to tests/chains/NULS/TWAnySignerTests.cpp index c0f5c3b0eea..749de87342b 100644 --- a/tests/NULS/TWAnySignerTests.cpp +++ b/tests/chains/NULS/TWAnySignerTests.cpp @@ -9,7 +9,7 @@ #include #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include namespace TW::NULS::tests { diff --git a/tests/NULS/TWCoinTypeTests.cpp b/tests/chains/NULS/TWCoinTypeTests.cpp similarity index 97% rename from tests/NULS/TWCoinTypeTests.cpp rename to tests/chains/NULS/TWCoinTypeTests.cpp index 3d048c09faf..5618222dcb2 100644 --- a/tests/NULS/TWCoinTypeTests.cpp +++ b/tests/chains/NULS/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Nano/AddressTests.cpp b/tests/chains/Nano/AddressTests.cpp similarity index 100% rename from tests/Nano/AddressTests.cpp rename to tests/chains/Nano/AddressTests.cpp diff --git a/tests/Nano/SignerTests.cpp b/tests/chains/Nano/SignerTests.cpp similarity index 100% rename from tests/Nano/SignerTests.cpp rename to tests/chains/Nano/SignerTests.cpp diff --git a/tests/Nano/TWAnySignerTests.cpp b/tests/chains/Nano/TWAnySignerTests.cpp similarity index 98% rename from tests/Nano/TWAnySignerTests.cpp rename to tests/chains/Nano/TWAnySignerTests.cpp index a348de09dae..aa76abc83f5 100644 --- a/tests/Nano/TWAnySignerTests.cpp +++ b/tests/chains/Nano/TWAnySignerTests.cpp @@ -7,7 +7,7 @@ #include "HexCoding.h" #include "proto/Nano.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Nano/TWCoinTypeTests.cpp b/tests/chains/Nano/TWCoinTypeTests.cpp similarity index 97% rename from tests/Nano/TWCoinTypeTests.cpp rename to tests/chains/Nano/TWCoinTypeTests.cpp index 37be0b6aa62..c6458843538 100644 --- a/tests/Nano/TWCoinTypeTests.cpp +++ b/tests/chains/Nano/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Nano/TWNanoAddressTests.cpp b/tests/chains/Nano/TWNanoAddressTests.cpp similarity index 97% rename from tests/Nano/TWNanoAddressTests.cpp rename to tests/chains/Nano/TWNanoAddressTests.cpp index afcd1587cf4..44d653119aa 100644 --- a/tests/Nano/TWNanoAddressTests.cpp +++ b/tests/chains/Nano/TWNanoAddressTests.cpp @@ -5,7 +5,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "HexCoding.h" #include "PrivateKey.h" #include "PublicKey.h" diff --git a/tests/NativeEvmos/TWAnyAddressTests.cpp b/tests/chains/NativeEvmos/TWAnyAddressTests.cpp similarity index 97% rename from tests/NativeEvmos/TWAnyAddressTests.cpp rename to tests/chains/NativeEvmos/TWAnyAddressTests.cpp index 410da049ba9..ed2a02cd50f 100644 --- a/tests/NativeEvmos/TWAnyAddressTests.cpp +++ b/tests/chains/NativeEvmos/TWAnyAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/NativeEvmos/TWCoinTypeTests.cpp b/tests/chains/NativeEvmos/TWCoinTypeTests.cpp similarity index 97% rename from tests/NativeEvmos/TWCoinTypeTests.cpp rename to tests/chains/NativeEvmos/TWCoinTypeTests.cpp index fdcc17272f5..6df42eaa394 100644 --- a/tests/NativeEvmos/TWCoinTypeTests.cpp +++ b/tests/chains/NativeEvmos/TWCoinTypeTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Nebulas/AddressTests.cpp b/tests/chains/Nebulas/AddressTests.cpp similarity index 100% rename from tests/Nebulas/AddressTests.cpp rename to tests/chains/Nebulas/AddressTests.cpp diff --git a/tests/Nebulas/SignerTests.cpp b/tests/chains/Nebulas/SignerTests.cpp similarity index 100% rename from tests/Nebulas/SignerTests.cpp rename to tests/chains/Nebulas/SignerTests.cpp diff --git a/tests/Nebulas/TWAnySignerTests.cpp b/tests/chains/Nebulas/TWAnySignerTests.cpp similarity index 97% rename from tests/Nebulas/TWAnySignerTests.cpp rename to tests/chains/Nebulas/TWAnySignerTests.cpp index bafee5a3fcf..c850acf6935 100644 --- a/tests/Nebulas/TWAnySignerTests.cpp +++ b/tests/chains/Nebulas/TWAnySignerTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include "HexCoding.h" #include "uint256.h" diff --git a/tests/Nebulas/TWCoinTypeTests.cpp b/tests/chains/Nebulas/TWCoinTypeTests.cpp similarity index 97% rename from tests/Nebulas/TWCoinTypeTests.cpp rename to tests/chains/Nebulas/TWCoinTypeTests.cpp index c3eac69cffa..d0f30bcc619 100644 --- a/tests/Nebulas/TWCoinTypeTests.cpp +++ b/tests/chains/Nebulas/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Nebulas/TWNebulasAddressTests.cpp b/tests/chains/Nebulas/TWNebulasAddressTests.cpp similarity index 98% rename from tests/Nebulas/TWNebulasAddressTests.cpp rename to tests/chains/Nebulas/TWNebulasAddressTests.cpp index 32e7ae08fa4..50a2cdcea9b 100644 --- a/tests/Nebulas/TWNebulasAddressTests.cpp +++ b/tests/chains/Nebulas/TWNebulasAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Nebulas/TransactionTests.cpp b/tests/chains/Nebulas/TransactionTests.cpp similarity index 100% rename from tests/Nebulas/TransactionTests.cpp rename to tests/chains/Nebulas/TransactionTests.cpp diff --git a/tests/Nervos/AddressTests.cpp b/tests/chains/Nervos/AddressTests.cpp similarity index 100% rename from tests/Nervos/AddressTests.cpp rename to tests/chains/Nervos/AddressTests.cpp diff --git a/tests/Nervos/SignerTests.cpp b/tests/chains/Nervos/SignerTests.cpp similarity index 99% rename from tests/Nervos/SignerTests.cpp rename to tests/chains/Nervos/SignerTests.cpp index b7ea9e3645f..1b8bdfefeb6 100644 --- a/tests/Nervos/SignerTests.cpp +++ b/tests/chains/Nervos/SignerTests.cpp @@ -14,7 +14,7 @@ #include "PrivateKey.h" #include "PublicKey.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Nervos/TWAnyAddressTests.cpp b/tests/chains/Nervos/TWAnyAddressTests.cpp similarity index 98% rename from tests/Nervos/TWAnyAddressTests.cpp rename to tests/chains/Nervos/TWAnyAddressTests.cpp index c948853f3ec..c514723797c 100644 --- a/tests/Nervos/TWAnyAddressTests.cpp +++ b/tests/chains/Nervos/TWAnyAddressTests.cpp @@ -12,7 +12,7 @@ #include #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/Nervos/TWAnySignerTests.cpp b/tests/chains/Nervos/TWAnySignerTests.cpp similarity index 99% rename from tests/Nervos/TWAnySignerTests.cpp rename to tests/chains/Nervos/TWAnySignerTests.cpp index 79a4b91079c..c213e802d0a 100644 --- a/tests/Nervos/TWAnySignerTests.cpp +++ b/tests/chains/Nervos/TWAnySignerTests.cpp @@ -11,7 +11,7 @@ #include "PublicKey.h" #include "proto/Nervos.pb.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Nervos/TWCoinTypeTests.cpp b/tests/chains/Nervos/TWCoinTypeTests.cpp similarity index 97% rename from tests/Nervos/TWCoinTypeTests.cpp rename to tests/chains/Nervos/TWCoinTypeTests.cpp index bff876ae0c3..1150536151a 100644 --- a/tests/Nervos/TWCoinTypeTests.cpp +++ b/tests/chains/Nervos/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Nervos/TWNervosAddressTests.cpp b/tests/chains/Nervos/TWNervosAddressTests.cpp similarity index 96% rename from tests/Nervos/TWNervosAddressTests.cpp rename to tests/chains/Nervos/TWNervosAddressTests.cpp index 1fa5924000c..cf7a8560e0d 100644 --- a/tests/Nervos/TWNervosAddressTests.cpp +++ b/tests/chains/Nervos/TWNervosAddressTests.cpp @@ -8,7 +8,7 @@ #include "PrivateKey.h" #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include namespace TW::Nervos::tests { diff --git a/tests/Nimiq/AddressTests.cpp b/tests/chains/Nimiq/AddressTests.cpp similarity index 100% rename from tests/Nimiq/AddressTests.cpp rename to tests/chains/Nimiq/AddressTests.cpp diff --git a/tests/Nimiq/SignerTests.cpp b/tests/chains/Nimiq/SignerTests.cpp similarity index 100% rename from tests/Nimiq/SignerTests.cpp rename to tests/chains/Nimiq/SignerTests.cpp diff --git a/tests/Nimiq/TWAnySignerTests.cpp b/tests/chains/Nimiq/TWAnySignerTests.cpp similarity index 96% rename from tests/Nimiq/TWAnySignerTests.cpp rename to tests/chains/Nimiq/TWAnySignerTests.cpp index bc7bcaf9fec..b9a9ee32b24 100644 --- a/tests/Nimiq/TWAnySignerTests.cpp +++ b/tests/chains/Nimiq/TWAnySignerTests.cpp @@ -8,7 +8,7 @@ #include "proto/Nimiq.pb.h" #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include namespace TW::Nimiq::tests { diff --git a/tests/Nimiq/TWCoinTypeTests.cpp b/tests/chains/Nimiq/TWCoinTypeTests.cpp similarity index 97% rename from tests/Nimiq/TWCoinTypeTests.cpp rename to tests/chains/Nimiq/TWCoinTypeTests.cpp index 40f585625e3..f973c71604e 100644 --- a/tests/Nimiq/TWCoinTypeTests.cpp +++ b/tests/chains/Nimiq/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Nimiq/TransactionTests.cpp b/tests/chains/Nimiq/TransactionTests.cpp similarity index 100% rename from tests/Nimiq/TransactionTests.cpp rename to tests/chains/Nimiq/TransactionTests.cpp diff --git a/tests/OKXChain/TWCoinTypeTests.cpp b/tests/chains/OKXChain/TWCoinTypeTests.cpp similarity index 97% rename from tests/OKXChain/TWCoinTypeTests.cpp rename to tests/chains/OKXChain/TWCoinTypeTests.cpp index 4e68b569a69..af4eed1e128 100644 --- a/tests/OKXChain/TWCoinTypeTests.cpp +++ b/tests/chains/OKXChain/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Oasis/AddressTests.cpp b/tests/chains/Oasis/AddressTests.cpp similarity index 100% rename from tests/Oasis/AddressTests.cpp rename to tests/chains/Oasis/AddressTests.cpp diff --git a/tests/Oasis/SignerTests.cpp b/tests/chains/Oasis/SignerTests.cpp similarity index 100% rename from tests/Oasis/SignerTests.cpp rename to tests/chains/Oasis/SignerTests.cpp diff --git a/tests/Oasis/TWAnySignerTests.cpp b/tests/chains/Oasis/TWAnySignerTests.cpp similarity index 97% rename from tests/Oasis/TWAnySignerTests.cpp rename to tests/chains/Oasis/TWAnySignerTests.cpp index 5e1c2b504ee..d390b051db5 100644 --- a/tests/Oasis/TWAnySignerTests.cpp +++ b/tests/chains/Oasis/TWAnySignerTests.cpp @@ -8,7 +8,7 @@ #include "HexCoding.h" #include "proto/Oasis.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/Oasis/TWCoinTypeTests.cpp b/tests/chains/Oasis/TWCoinTypeTests.cpp similarity index 97% rename from tests/Oasis/TWCoinTypeTests.cpp rename to tests/chains/Oasis/TWCoinTypeTests.cpp index a75e79d0796..86ff3764832 100644 --- a/tests/Oasis/TWCoinTypeTests.cpp +++ b/tests/chains/Oasis/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Ontology/AccountTests.cpp b/tests/chains/Ontology/AccountTests.cpp similarity index 100% rename from tests/Ontology/AccountTests.cpp rename to tests/chains/Ontology/AccountTests.cpp diff --git a/tests/Ontology/AddressTests.cpp b/tests/chains/Ontology/AddressTests.cpp similarity index 100% rename from tests/Ontology/AddressTests.cpp rename to tests/chains/Ontology/AddressTests.cpp diff --git a/tests/Ontology/Oep4Tests.cpp b/tests/chains/Ontology/Oep4Tests.cpp similarity index 100% rename from tests/Ontology/Oep4Tests.cpp rename to tests/chains/Ontology/Oep4Tests.cpp diff --git a/tests/Ontology/OngTests.cpp b/tests/chains/Ontology/OngTests.cpp similarity index 100% rename from tests/Ontology/OngTests.cpp rename to tests/chains/Ontology/OngTests.cpp diff --git a/tests/Ontology/OntTests.cpp b/tests/chains/Ontology/OntTests.cpp similarity index 100% rename from tests/Ontology/OntTests.cpp rename to tests/chains/Ontology/OntTests.cpp diff --git a/tests/Ontology/ParamsBuilderTests.cpp b/tests/chains/Ontology/ParamsBuilderTests.cpp similarity index 100% rename from tests/Ontology/ParamsBuilderTests.cpp rename to tests/chains/Ontology/ParamsBuilderTests.cpp diff --git a/tests/Ontology/TWAnySignerTests.cpp b/tests/chains/Ontology/TWAnySignerTests.cpp similarity index 99% rename from tests/Ontology/TWAnySignerTests.cpp rename to tests/chains/Ontology/TWAnySignerTests.cpp index e25b1e46190..99f2c8b1559 100644 --- a/tests/Ontology/TWAnySignerTests.cpp +++ b/tests/chains/Ontology/TWAnySignerTests.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "Ontology/Oep4TxBuilder.h" #include "Ontology/OngTxBuilder.h" diff --git a/tests/Ontology/TWCoinTypeTests.cpp b/tests/chains/Ontology/TWCoinTypeTests.cpp similarity index 97% rename from tests/Ontology/TWCoinTypeTests.cpp rename to tests/chains/Ontology/TWCoinTypeTests.cpp index 733c1fe94cf..4bada2c0a47 100644 --- a/tests/Ontology/TWCoinTypeTests.cpp +++ b/tests/chains/Ontology/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Ontology/TransactionTests.cpp b/tests/chains/Ontology/TransactionTests.cpp similarity index 100% rename from tests/Ontology/TransactionTests.cpp rename to tests/chains/Ontology/TransactionTests.cpp diff --git a/tests/Optimism/TWCoinTypeTests.cpp b/tests/chains/Optimism/TWCoinTypeTests.cpp similarity index 97% rename from tests/Optimism/TWCoinTypeTests.cpp rename to tests/chains/Optimism/TWCoinTypeTests.cpp index 4073c8896b8..1cc6ff0e4c3 100644 --- a/tests/Optimism/TWCoinTypeTests.cpp +++ b/tests/chains/Optimism/TWCoinTypeTests.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Osmosis/AddressTests.cpp b/tests/chains/Osmosis/AddressTests.cpp similarity index 100% rename from tests/Osmosis/AddressTests.cpp rename to tests/chains/Osmosis/AddressTests.cpp diff --git a/tests/Osmosis/SignerTests.cpp b/tests/chains/Osmosis/SignerTests.cpp similarity index 98% rename from tests/Osmosis/SignerTests.cpp rename to tests/chains/Osmosis/SignerTests.cpp index a418f5fc6fb..91dd335f25e 100644 --- a/tests/Osmosis/SignerTests.cpp +++ b/tests/chains/Osmosis/SignerTests.cpp @@ -9,7 +9,7 @@ #include "HexCoding.h" #include "PublicKey.h" #include "proto/Cosmos.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/Osmosis/TWAnyAddressTests.cpp b/tests/chains/Osmosis/TWAnyAddressTests.cpp similarity index 96% rename from tests/Osmosis/TWAnyAddressTests.cpp rename to tests/chains/Osmosis/TWAnyAddressTests.cpp index 58e8d8abb24..40793a73acf 100644 --- a/tests/Osmosis/TWAnyAddressTests.cpp +++ b/tests/chains/Osmosis/TWAnyAddressTests.cpp @@ -7,7 +7,7 @@ #include #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/Osmosis/TWAnySignerTests.cpp b/tests/chains/Osmosis/TWAnySignerTests.cpp similarity index 98% rename from tests/Osmosis/TWAnySignerTests.cpp rename to tests/chains/Osmosis/TWAnySignerTests.cpp index 5985d55949c..95f230551a8 100644 --- a/tests/Osmosis/TWAnySignerTests.cpp +++ b/tests/chains/Osmosis/TWAnySignerTests.cpp @@ -9,7 +9,7 @@ #include "proto/Cosmos.pb.h" #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include namespace TW::Cosmos::tests { diff --git a/tests/Osmosis/TWCoinTypeTests.cpp b/tests/chains/Osmosis/TWCoinTypeTests.cpp similarity index 97% rename from tests/Osmosis/TWCoinTypeTests.cpp rename to tests/chains/Osmosis/TWCoinTypeTests.cpp index dc9b81fe90e..d42a4106616 100644 --- a/tests/Osmosis/TWCoinTypeTests.cpp +++ b/tests/chains/Osmosis/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/POANetwork/TWCoinTypeTests.cpp b/tests/chains/POANetwork/TWCoinTypeTests.cpp similarity index 97% rename from tests/POANetwork/TWCoinTypeTests.cpp rename to tests/chains/POANetwork/TWCoinTypeTests.cpp index 37ca284bc69..76581a52843 100644 --- a/tests/POANetwork/TWCoinTypeTests.cpp +++ b/tests/chains/POANetwork/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Polkadot/AddressTests.cpp b/tests/chains/Polkadot/AddressTests.cpp similarity index 100% rename from tests/Polkadot/AddressTests.cpp rename to tests/chains/Polkadot/AddressTests.cpp diff --git a/tests/Polkadot/SS58AddressTests.cpp b/tests/chains/Polkadot/SS58AddressTests.cpp similarity index 99% rename from tests/Polkadot/SS58AddressTests.cpp rename to tests/chains/Polkadot/SS58AddressTests.cpp index b8db84c66af..701938d697b 100644 --- a/tests/Polkadot/SS58AddressTests.cpp +++ b/tests/chains/Polkadot/SS58AddressTests.cpp @@ -7,7 +7,7 @@ #include "Polkadot/SS58Address.h" #include "HexCoding.h" #include "PublicKey.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Polkadot/ScaleCodecTests.cpp b/tests/chains/Polkadot/ScaleCodecTests.cpp similarity index 100% rename from tests/Polkadot/ScaleCodecTests.cpp rename to tests/chains/Polkadot/ScaleCodecTests.cpp diff --git a/tests/Polkadot/SignerTests.cpp b/tests/chains/Polkadot/SignerTests.cpp similarity index 100% rename from tests/Polkadot/SignerTests.cpp rename to tests/chains/Polkadot/SignerTests.cpp diff --git a/tests/Polkadot/TWCoinTypeTests.cpp b/tests/chains/Polkadot/TWCoinTypeTests.cpp similarity index 97% rename from tests/Polkadot/TWCoinTypeTests.cpp rename to tests/chains/Polkadot/TWCoinTypeTests.cpp index f5504a5c30f..b35b069a115 100644 --- a/tests/Polkadot/TWCoinTypeTests.cpp +++ b/tests/chains/Polkadot/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Polygon/TWCoinTypeTests.cpp b/tests/chains/Polygon/TWCoinTypeTests.cpp similarity index 97% rename from tests/Polygon/TWCoinTypeTests.cpp rename to tests/chains/Polygon/TWCoinTypeTests.cpp index a1810ade109..3ffc1203d40 100644 --- a/tests/Polygon/TWCoinTypeTests.cpp +++ b/tests/chains/Polygon/TWCoinTypeTests.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Qtum/TWCoinTypeTests.cpp b/tests/chains/Qtum/TWCoinTypeTests.cpp similarity index 97% rename from tests/Qtum/TWCoinTypeTests.cpp rename to tests/chains/Qtum/TWCoinTypeTests.cpp index bef8e814b59..97814e04ab3 100644 --- a/tests/Qtum/TWCoinTypeTests.cpp +++ b/tests/chains/Qtum/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Qtum/TWQtumAddressTests.cpp b/tests/chains/Qtum/TWQtumAddressTests.cpp similarity index 99% rename from tests/Qtum/TWQtumAddressTests.cpp rename to tests/chains/Qtum/TWQtumAddressTests.cpp index 8d658cf096c..7da7788ce7e 100644 --- a/tests/Qtum/TWQtumAddressTests.cpp +++ b/tests/chains/Qtum/TWQtumAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Ravencoin/TWCoinTypeTests.cpp b/tests/chains/Ravencoin/TWCoinTypeTests.cpp similarity index 97% rename from tests/Ravencoin/TWCoinTypeTests.cpp rename to tests/chains/Ravencoin/TWCoinTypeTests.cpp index f639dfe6bba..9f90f507883 100644 --- a/tests/Ravencoin/TWCoinTypeTests.cpp +++ b/tests/chains/Ravencoin/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Ravencoin/TWRavencoinTransactionTests.cpp b/tests/chains/Ravencoin/TWRavencoinTransactionTests.cpp similarity index 99% rename from tests/Ravencoin/TWRavencoinTransactionTests.cpp rename to tests/chains/Ravencoin/TWRavencoinTransactionTests.cpp index b90d76b91c8..d3927772a2c 100644 --- a/tests/Ravencoin/TWRavencoinTransactionTests.cpp +++ b/tests/chains/Ravencoin/TWRavencoinTransactionTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "Bitcoin/OutPoint.h" #include "Bitcoin/TransactionBuilder.h" diff --git a/tests/Ronin/TWAnyAddressTests.cpp b/tests/chains/Ronin/TWAnyAddressTests.cpp similarity index 98% rename from tests/Ronin/TWAnyAddressTests.cpp rename to tests/chains/Ronin/TWAnyAddressTests.cpp index d2e0bde63c7..8bdcd75d68f 100644 --- a/tests/Ronin/TWAnyAddressTests.cpp +++ b/tests/chains/Ronin/TWAnyAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Ronin/TWAnySignerTests.cpp b/tests/chains/Ronin/TWAnySignerTests.cpp similarity index 97% rename from tests/Ronin/TWAnySignerTests.cpp rename to tests/chains/Ronin/TWAnySignerTests.cpp index 3f852a1dab2..cabaf560b68 100644 --- a/tests/Ronin/TWAnySignerTests.cpp +++ b/tests/chains/Ronin/TWAnySignerTests.cpp @@ -7,7 +7,7 @@ #include "HexCoding.h" #include "proto/Ethereum.pb.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Ronin/TWCoinTypeTests.cpp b/tests/chains/Ronin/TWCoinTypeTests.cpp similarity index 97% rename from tests/Ronin/TWCoinTypeTests.cpp rename to tests/chains/Ronin/TWCoinTypeTests.cpp index 5d29a67771e..3549ef495a0 100644 --- a/tests/Ronin/TWCoinTypeTests.cpp +++ b/tests/chains/Ronin/TWCoinTypeTests.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/SmartBitcoinCash/TWCoinTypeTests.cpp b/tests/chains/SmartBitcoinCash/TWCoinTypeTests.cpp similarity index 97% rename from tests/SmartBitcoinCash/TWCoinTypeTests.cpp rename to tests/chains/SmartBitcoinCash/TWCoinTypeTests.cpp index 04b97444049..f08f7466371 100644 --- a/tests/SmartBitcoinCash/TWCoinTypeTests.cpp +++ b/tests/chains/SmartBitcoinCash/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Solana/AddressTests.cpp b/tests/chains/Solana/AddressTests.cpp similarity index 100% rename from tests/Solana/AddressTests.cpp rename to tests/chains/Solana/AddressTests.cpp diff --git a/tests/Solana/ProgramTests.cpp b/tests/chains/Solana/ProgramTests.cpp similarity index 100% rename from tests/Solana/ProgramTests.cpp rename to tests/chains/Solana/ProgramTests.cpp diff --git a/tests/Solana/SignerTests.cpp b/tests/chains/Solana/SignerTests.cpp similarity index 100% rename from tests/Solana/SignerTests.cpp rename to tests/chains/Solana/SignerTests.cpp diff --git a/tests/Solana/TWAnySignerTests.cpp b/tests/chains/Solana/TWAnySignerTests.cpp similarity index 99% rename from tests/Solana/TWAnySignerTests.cpp rename to tests/chains/Solana/TWAnySignerTests.cpp index 2a0dd1ca007..8246f8f48ce 100644 --- a/tests/Solana/TWAnySignerTests.cpp +++ b/tests/chains/Solana/TWAnySignerTests.cpp @@ -10,7 +10,7 @@ #include "Solana/Address.h" #include "Solana/Program.h" #include "PrivateKey.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Solana/TWCoinTypeTests.cpp b/tests/chains/Solana/TWCoinTypeTests.cpp similarity index 97% rename from tests/Solana/TWCoinTypeTests.cpp rename to tests/chains/Solana/TWCoinTypeTests.cpp index 5bd9998488a..c6225566d1e 100644 --- a/tests/Solana/TWCoinTypeTests.cpp +++ b/tests/chains/Solana/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Solana/TWSolanaAddressTests.cpp b/tests/chains/Solana/TWSolanaAddressTests.cpp similarity index 97% rename from tests/Solana/TWSolanaAddressTests.cpp rename to tests/chains/Solana/TWSolanaAddressTests.cpp index 2ad4f854fcd..1cdd42676f2 100644 --- a/tests/Solana/TWSolanaAddressTests.cpp +++ b/tests/chains/Solana/TWSolanaAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Solana/TransactionTests.cpp b/tests/chains/Solana/TransactionTests.cpp similarity index 100% rename from tests/Solana/TransactionTests.cpp rename to tests/chains/Solana/TransactionTests.cpp diff --git a/tests/Stellar/AddressTests.cpp b/tests/chains/Stellar/AddressTests.cpp similarity index 100% rename from tests/Stellar/AddressTests.cpp rename to tests/chains/Stellar/AddressTests.cpp diff --git a/tests/Stellar/TWAnySignerTests.cpp b/tests/chains/Stellar/TWAnySignerTests.cpp similarity index 99% rename from tests/Stellar/TWAnySignerTests.cpp rename to tests/chains/Stellar/TWAnySignerTests.cpp index 739f0926bca..7ad662a073a 100644 --- a/tests/Stellar/TWAnySignerTests.cpp +++ b/tests/chains/Stellar/TWAnySignerTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "HexCoding.h" #include "PrivateKey.h" diff --git a/tests/Stellar/TWCoinTypeTests.cpp b/tests/chains/Stellar/TWCoinTypeTests.cpp similarity index 97% rename from tests/Stellar/TWCoinTypeTests.cpp rename to tests/chains/Stellar/TWCoinTypeTests.cpp index 12164f9b2d6..2fc1c59fb4b 100644 --- a/tests/Stellar/TWCoinTypeTests.cpp +++ b/tests/chains/Stellar/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Stellar/TWStellarAddressTests.cpp b/tests/chains/Stellar/TWStellarAddressTests.cpp similarity index 96% rename from tests/Stellar/TWStellarAddressTests.cpp rename to tests/chains/Stellar/TWStellarAddressTests.cpp index 47d1f759c76..97f9fc32f12 100644 --- a/tests/Stellar/TWStellarAddressTests.cpp +++ b/tests/chains/Stellar/TWStellarAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Stellar/TransactionTests.cpp b/tests/chains/Stellar/TransactionTests.cpp similarity index 99% rename from tests/Stellar/TransactionTests.cpp rename to tests/chains/Stellar/TransactionTests.cpp index b80e60a0274..8a7890eac2e 100644 --- a/tests/Stellar/TransactionTests.cpp +++ b/tests/chains/Stellar/TransactionTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "Stellar/Signer.h" #include "HexCoding.h" diff --git a/tests/THORChain/SignerTests.cpp b/tests/chains/THORChain/SignerTests.cpp similarity index 99% rename from tests/THORChain/SignerTests.cpp rename to tests/chains/THORChain/SignerTests.cpp index c283cae8bf2..85b6bbf68fc 100644 --- a/tests/THORChain/SignerTests.cpp +++ b/tests/chains/THORChain/SignerTests.cpp @@ -8,7 +8,7 @@ #include "THORChain/Signer.h" #include "HexCoding.h" #include "Bech32Address.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp similarity index 99% rename from tests/THORChain/SwapTests.cpp rename to tests/chains/THORChain/SwapTests.cpp index adb3340a417..1f0738595e4 100644 --- a/tests/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -22,7 +22,7 @@ #include #include #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/THORChain/TWAnyAddressTests.cpp b/tests/chains/THORChain/TWAnyAddressTests.cpp similarity index 96% rename from tests/THORChain/TWAnyAddressTests.cpp rename to tests/chains/THORChain/TWAnyAddressTests.cpp index 28e1618885e..52d9bc560cb 100644 --- a/tests/THORChain/TWAnyAddressTests.cpp +++ b/tests/chains/THORChain/TWAnyAddressTests.cpp @@ -7,7 +7,7 @@ #include #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/THORChain/TWAnySignerTests.cpp b/tests/chains/THORChain/TWAnySignerTests.cpp similarity index 98% rename from tests/THORChain/TWAnySignerTests.cpp rename to tests/chains/THORChain/TWAnySignerTests.cpp index a4fb0eebde3..8e9e45380d7 100644 --- a/tests/THORChain/TWAnySignerTests.cpp +++ b/tests/chains/THORChain/TWAnySignerTests.cpp @@ -10,7 +10,7 @@ #include "proto/Cosmos.pb.h" #include "HexCoding.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/THORChain/TWCoinTypeTests.cpp b/tests/chains/THORChain/TWCoinTypeTests.cpp similarity index 97% rename from tests/THORChain/TWCoinTypeTests.cpp rename to tests/chains/THORChain/TWCoinTypeTests.cpp index fead42b2449..de7f561af47 100644 --- a/tests/THORChain/TWCoinTypeTests.cpp +++ b/tests/chains/THORChain/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/THORChain/TWSwapTests.cpp b/tests/chains/THORChain/TWSwapTests.cpp similarity index 99% rename from tests/THORChain/TWSwapTests.cpp rename to tests/chains/THORChain/TWSwapTests.cpp index d2af7e2a18e..ea266cb6584 100644 --- a/tests/THORChain/TWSwapTests.cpp +++ b/tests/chains/THORChain/TWSwapTests.cpp @@ -16,7 +16,7 @@ #include "HexCoding.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/Terra/SignerTests.cpp b/tests/chains/Terra/SignerTests.cpp similarity index 99% rename from tests/Terra/SignerTests.cpp rename to tests/chains/Terra/SignerTests.cpp index ee67a38dddc..34c01feb560 100644 --- a/tests/Terra/SignerTests.cpp +++ b/tests/chains/Terra/SignerTests.cpp @@ -11,7 +11,7 @@ #include "Cosmos/Signer.h" #include "Cosmos/ProtobufSerialization.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Terra/TWCoinTypeTests.cpp b/tests/chains/Terra/TWCoinTypeTests.cpp similarity index 97% rename from tests/Terra/TWCoinTypeTests.cpp rename to tests/chains/Terra/TWCoinTypeTests.cpp index e46e7c58f0c..464be13fa31 100644 --- a/tests/Terra/TWCoinTypeTests.cpp +++ b/tests/chains/Terra/TWCoinTypeTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/TerraV2/SignerTests.cpp b/tests/chains/TerraV2/SignerTests.cpp similarity index 99% rename from tests/TerraV2/SignerTests.cpp rename to tests/chains/TerraV2/SignerTests.cpp index 4978a5c4405..b1cc0c152b2 100644 --- a/tests/TerraV2/SignerTests.cpp +++ b/tests/chains/TerraV2/SignerTests.cpp @@ -11,7 +11,7 @@ #include "Cosmos/Signer.h" #include "Cosmos/ProtobufSerialization.h" #include "uint256.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/TerraV2/TWCoinTypeTests.cpp b/tests/chains/TerraV2/TWCoinTypeTests.cpp similarity index 97% rename from tests/TerraV2/TWCoinTypeTests.cpp rename to tests/chains/TerraV2/TWCoinTypeTests.cpp index 96c27cff876..ee436963959 100644 --- a/tests/TerraV2/TWCoinTypeTests.cpp +++ b/tests/chains/TerraV2/TWCoinTypeTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Tezos/AddressTests.cpp b/tests/chains/Tezos/AddressTests.cpp similarity index 100% rename from tests/Tezos/AddressTests.cpp rename to tests/chains/Tezos/AddressTests.cpp diff --git a/tests/Tezos/ForgingTests.cpp b/tests/chains/Tezos/ForgingTests.cpp similarity index 100% rename from tests/Tezos/ForgingTests.cpp rename to tests/chains/Tezos/ForgingTests.cpp diff --git a/tests/Tezos/OperationListTests.cpp b/tests/chains/Tezos/OperationListTests.cpp similarity index 100% rename from tests/Tezos/OperationListTests.cpp rename to tests/chains/Tezos/OperationListTests.cpp diff --git a/tests/Tezos/PublicKeyTests.cpp b/tests/chains/Tezos/PublicKeyTests.cpp similarity index 100% rename from tests/Tezos/PublicKeyTests.cpp rename to tests/chains/Tezos/PublicKeyTests.cpp diff --git a/tests/Tezos/SignerTests.cpp b/tests/chains/Tezos/SignerTests.cpp similarity index 100% rename from tests/Tezos/SignerTests.cpp rename to tests/chains/Tezos/SignerTests.cpp diff --git a/tests/Tezos/TWAnySignerTests.cpp b/tests/chains/Tezos/TWAnySignerTests.cpp similarity index 99% rename from tests/Tezos/TWAnySignerTests.cpp rename to tests/chains/Tezos/TWAnySignerTests.cpp index 4cac74a7885..89fac461677 100644 --- a/tests/Tezos/TWAnySignerTests.cpp +++ b/tests/chains/Tezos/TWAnySignerTests.cpp @@ -7,7 +7,7 @@ #include "HexCoding.h" #include "Tezos/BinaryCoding.h" #include "proto/Tezos.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Tezos/TWCoinTypeTests.cpp b/tests/chains/Tezos/TWCoinTypeTests.cpp similarity index 97% rename from tests/Tezos/TWCoinTypeTests.cpp rename to tests/chains/Tezos/TWCoinTypeTests.cpp index a8d44065d59..2c33d888f68 100644 --- a/tests/Tezos/TWCoinTypeTests.cpp +++ b/tests/chains/Tezos/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Theta/SignerTests.cpp b/tests/chains/Theta/SignerTests.cpp similarity index 100% rename from tests/Theta/SignerTests.cpp rename to tests/chains/Theta/SignerTests.cpp diff --git a/tests/Theta/TWAnySignerTests.cpp b/tests/chains/Theta/TWAnySignerTests.cpp similarity index 97% rename from tests/Theta/TWAnySignerTests.cpp rename to tests/chains/Theta/TWAnySignerTests.cpp index 6b9fbe87e6d..1c18296d549 100644 --- a/tests/Theta/TWAnySignerTests.cpp +++ b/tests/chains/Theta/TWAnySignerTests.cpp @@ -9,7 +9,7 @@ #include "uint256.h" #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/Theta/TWCoinTypeTests.cpp b/tests/chains/Theta/TWCoinTypeTests.cpp similarity index 97% rename from tests/Theta/TWCoinTypeTests.cpp rename to tests/chains/Theta/TWCoinTypeTests.cpp index 55ed4e35b38..94107b0898c 100644 --- a/tests/Theta/TWCoinTypeTests.cpp +++ b/tests/chains/Theta/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Theta/TransactionTests.cpp b/tests/chains/Theta/TransactionTests.cpp similarity index 100% rename from tests/Theta/TransactionTests.cpp rename to tests/chains/Theta/TransactionTests.cpp diff --git a/tests/ThunderToken/TWCoinTypeTests.cpp b/tests/chains/ThunderToken/TWCoinTypeTests.cpp similarity index 97% rename from tests/ThunderToken/TWCoinTypeTests.cpp rename to tests/chains/ThunderToken/TWCoinTypeTests.cpp index 3b31872c8c3..c001ea07218 100644 --- a/tests/ThunderToken/TWCoinTypeTests.cpp +++ b/tests/chains/ThunderToken/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/TomoChain/TWCoinTypeTests.cpp b/tests/chains/TomoChain/TWCoinTypeTests.cpp similarity index 97% rename from tests/TomoChain/TWCoinTypeTests.cpp rename to tests/chains/TomoChain/TWCoinTypeTests.cpp index 0cb99362b04..4b6ec3810b4 100644 --- a/tests/TomoChain/TWCoinTypeTests.cpp +++ b/tests/chains/TomoChain/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Tron/AddressTests.cpp b/tests/chains/Tron/AddressTests.cpp similarity index 100% rename from tests/Tron/AddressTests.cpp rename to tests/chains/Tron/AddressTests.cpp diff --git a/tests/Tron/SerializationTests.cpp b/tests/chains/Tron/SerializationTests.cpp similarity index 100% rename from tests/Tron/SerializationTests.cpp rename to tests/chains/Tron/SerializationTests.cpp diff --git a/tests/Tron/SignerTests.cpp b/tests/chains/Tron/SignerTests.cpp similarity index 100% rename from tests/Tron/SignerTests.cpp rename to tests/chains/Tron/SignerTests.cpp diff --git a/tests/Tron/TWAnySignerTests.cpp b/tests/chains/Tron/TWAnySignerTests.cpp similarity index 97% rename from tests/Tron/TWAnySignerTests.cpp rename to tests/chains/Tron/TWAnySignerTests.cpp index 0dc27c18583..ba7f2964e7b 100644 --- a/tests/Tron/TWAnySignerTests.cpp +++ b/tests/chains/Tron/TWAnySignerTests.cpp @@ -8,7 +8,7 @@ #include "proto/Tron.pb.h" #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include namespace TW::Tron { diff --git a/tests/Tron/TWCoinTypeTests.cpp b/tests/chains/Tron/TWCoinTypeTests.cpp similarity index 97% rename from tests/Tron/TWCoinTypeTests.cpp rename to tests/chains/Tron/TWCoinTypeTests.cpp index e496477156e..b549e7bae86 100644 --- a/tests/Tron/TWCoinTypeTests.cpp +++ b/tests/chains/Tron/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/VeChain/SignerTests.cpp b/tests/chains/VeChain/SignerTests.cpp similarity index 100% rename from tests/VeChain/SignerTests.cpp rename to tests/chains/VeChain/SignerTests.cpp diff --git a/tests/VeChain/TWAnySignerTests.cpp b/tests/chains/VeChain/TWAnySignerTests.cpp similarity index 97% rename from tests/VeChain/TWAnySignerTests.cpp rename to tests/chains/VeChain/TWAnySignerTests.cpp index 783ecf827b6..992e65dbc51 100644 --- a/tests/VeChain/TWAnySignerTests.cpp +++ b/tests/chains/VeChain/TWAnySignerTests.cpp @@ -6,7 +6,7 @@ #include "HexCoding.h" #include "proto/VeChain.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/VeChain/TWCoinTypeTests.cpp b/tests/chains/VeChain/TWCoinTypeTests.cpp similarity index 97% rename from tests/VeChain/TWCoinTypeTests.cpp rename to tests/chains/VeChain/TWCoinTypeTests.cpp index cf41c6cba08..60d7e2b709c 100644 --- a/tests/VeChain/TWCoinTypeTests.cpp +++ b/tests/chains/VeChain/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Viacoin/TWCoinTypeTests.cpp b/tests/chains/Viacoin/TWCoinTypeTests.cpp similarity index 97% rename from tests/Viacoin/TWCoinTypeTests.cpp rename to tests/chains/Viacoin/TWCoinTypeTests.cpp index 15ead27fdc1..3fcc86d7e37 100644 --- a/tests/Viacoin/TWCoinTypeTests.cpp +++ b/tests/chains/Viacoin/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Viacoin/TWViacoinAddressTests.cpp b/tests/chains/Viacoin/TWViacoinAddressTests.cpp similarity index 99% rename from tests/Viacoin/TWViacoinAddressTests.cpp rename to tests/chains/Viacoin/TWViacoinAddressTests.cpp index 55ef8fe74a5..d4ea5b115ea 100644 --- a/tests/Viacoin/TWViacoinAddressTests.cpp +++ b/tests/chains/Viacoin/TWViacoinAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Wanchain/TWCoinTypeTests.cpp b/tests/chains/Wanchain/TWCoinTypeTests.cpp similarity index 97% rename from tests/Wanchain/TWCoinTypeTests.cpp rename to tests/chains/Wanchain/TWCoinTypeTests.cpp index f3ba2ce8ee7..cc49f5ae5ae 100644 --- a/tests/Wanchain/TWCoinTypeTests.cpp +++ b/tests/chains/Wanchain/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Waves/AddressTests.cpp b/tests/chains/Waves/AddressTests.cpp similarity index 100% rename from tests/Waves/AddressTests.cpp rename to tests/chains/Waves/AddressTests.cpp diff --git a/tests/Waves/LeaseTests.cpp b/tests/chains/Waves/LeaseTests.cpp similarity index 100% rename from tests/Waves/LeaseTests.cpp rename to tests/chains/Waves/LeaseTests.cpp diff --git a/tests/Waves/SignerTests.cpp b/tests/chains/Waves/SignerTests.cpp similarity index 100% rename from tests/Waves/SignerTests.cpp rename to tests/chains/Waves/SignerTests.cpp diff --git a/tests/Waves/TWAnySignerTests.cpp b/tests/chains/Waves/TWAnySignerTests.cpp similarity index 97% rename from tests/Waves/TWAnySignerTests.cpp rename to tests/chains/Waves/TWAnySignerTests.cpp index bc57276977e..c814761a4f9 100644 --- a/tests/Waves/TWAnySignerTests.cpp +++ b/tests/chains/Waves/TWAnySignerTests.cpp @@ -7,7 +7,7 @@ #include "Base58.h" #include "HexCoding.h" #include "proto/Waves.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Waves/TWCoinTypeTests.cpp b/tests/chains/Waves/TWCoinTypeTests.cpp similarity index 97% rename from tests/Waves/TWCoinTypeTests.cpp rename to tests/chains/Waves/TWCoinTypeTests.cpp index b9043540b04..6460c3cbff0 100644 --- a/tests/Waves/TWCoinTypeTests.cpp +++ b/tests/chains/Waves/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Waves/TransactionTests.cpp b/tests/chains/Waves/TransactionTests.cpp similarity index 100% rename from tests/Waves/TransactionTests.cpp rename to tests/chains/Waves/TransactionTests.cpp diff --git a/tests/XRP/AddressTests.cpp b/tests/chains/XRP/AddressTests.cpp similarity index 100% rename from tests/XRP/AddressTests.cpp rename to tests/chains/XRP/AddressTests.cpp diff --git a/tests/XRP/TWAnySignerTests.cpp b/tests/chains/XRP/TWAnySignerTests.cpp similarity index 97% rename from tests/XRP/TWAnySignerTests.cpp rename to tests/chains/XRP/TWAnySignerTests.cpp index 6bf8bdf5986..1b9e05728e6 100644 --- a/tests/XRP/TWAnySignerTests.cpp +++ b/tests/chains/XRP/TWAnySignerTests.cpp @@ -9,7 +9,7 @@ #include "proto/Ripple.pb.h" #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/XRP/TWCoinTypeTests.cpp b/tests/chains/XRP/TWCoinTypeTests.cpp similarity index 97% rename from tests/XRP/TWCoinTypeTests.cpp rename to tests/chains/XRP/TWCoinTypeTests.cpp index 5f4249ca2e1..1f1a967a712 100644 --- a/tests/XRP/TWCoinTypeTests.cpp +++ b/tests/chains/XRP/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/XRP/TWRippleAddressTests.cpp b/tests/chains/XRP/TWRippleAddressTests.cpp similarity index 97% rename from tests/XRP/TWRippleAddressTests.cpp rename to tests/chains/XRP/TWRippleAddressTests.cpp index 36e738592c1..6c21a4a4bc5 100644 --- a/tests/XRP/TWRippleAddressTests.cpp +++ b/tests/chains/XRP/TWRippleAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/XRP/TransactionTests.cpp b/tests/chains/XRP/TransactionTests.cpp similarity index 100% rename from tests/XRP/TransactionTests.cpp rename to tests/chains/XRP/TransactionTests.cpp diff --git a/tests/Zcash/AddressTests.cpp b/tests/chains/Zcash/AddressTests.cpp similarity index 100% rename from tests/Zcash/AddressTests.cpp rename to tests/chains/Zcash/AddressTests.cpp diff --git a/tests/Zcash/TWCoinTypeTests.cpp b/tests/chains/Zcash/TWCoinTypeTests.cpp similarity index 97% rename from tests/Zcash/TWCoinTypeTests.cpp rename to tests/chains/Zcash/TWCoinTypeTests.cpp index 475ffafd17b..46deb231511 100644 --- a/tests/Zcash/TWCoinTypeTests.cpp +++ b/tests/chains/Zcash/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Zcash/TWZcashAddressTests.cpp b/tests/chains/Zcash/TWZcashAddressTests.cpp similarity index 99% rename from tests/Zcash/TWZcashAddressTests.cpp rename to tests/chains/Zcash/TWZcashAddressTests.cpp index bbaa4ad932e..d3820059c5a 100644 --- a/tests/Zcash/TWZcashAddressTests.cpp +++ b/tests/chains/Zcash/TWZcashAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "Zcash/TAddress.h" diff --git a/tests/Zcash/TWZcashTransactionTests.cpp b/tests/chains/Zcash/TWZcashTransactionTests.cpp similarity index 99% rename from tests/Zcash/TWZcashTransactionTests.cpp rename to tests/chains/Zcash/TWZcashTransactionTests.cpp index 96861a4a507..b0acaf0f132 100644 --- a/tests/Zcash/TWZcashTransactionTests.cpp +++ b/tests/chains/Zcash/TWZcashTransactionTests.cpp @@ -5,7 +5,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "Bitcoin/OutPoint.h" #include "Bitcoin/Script.h" diff --git a/tests/Zelcash/TWCoinTypeTests.cpp b/tests/chains/Zelcash/TWCoinTypeTests.cpp similarity index 97% rename from tests/Zelcash/TWCoinTypeTests.cpp rename to tests/chains/Zelcash/TWCoinTypeTests.cpp index ee7bce7b346..29ff10fe24e 100644 --- a/tests/Zelcash/TWCoinTypeTests.cpp +++ b/tests/chains/Zelcash/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Zelcash/TWZelcashAddressTests.cpp b/tests/chains/Zelcash/TWZelcashAddressTests.cpp similarity index 99% rename from tests/Zelcash/TWZelcashAddressTests.cpp rename to tests/chains/Zelcash/TWZelcashAddressTests.cpp index 6d2b5807778..f78524d8898 100644 --- a/tests/Zelcash/TWZelcashAddressTests.cpp +++ b/tests/chains/Zelcash/TWZelcashAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Zelcash/TWZelcashTransactionTests.cpp b/tests/chains/Zelcash/TWZelcashTransactionTests.cpp similarity index 99% rename from tests/Zelcash/TWZelcashTransactionTests.cpp rename to tests/chains/Zelcash/TWZelcashTransactionTests.cpp index 90d2b09cb41..74f3413670e 100644 --- a/tests/Zelcash/TWZelcashTransactionTests.cpp +++ b/tests/chains/Zelcash/TWZelcashTransactionTests.cpp @@ -5,7 +5,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "Bitcoin/OutPoint.h" #include "HexCoding.h" diff --git a/tests/Zilliqa/AddressTests.cpp b/tests/chains/Zilliqa/AddressTests.cpp similarity index 100% rename from tests/Zilliqa/AddressTests.cpp rename to tests/chains/Zilliqa/AddressTests.cpp diff --git a/tests/Zilliqa/SignatureTests.cpp b/tests/chains/Zilliqa/SignatureTests.cpp similarity index 97% rename from tests/Zilliqa/SignatureTests.cpp rename to tests/chains/Zilliqa/SignatureTests.cpp index cd3fe38e216..37684d1b11b 100644 --- a/tests/Zilliqa/SignatureTests.cpp +++ b/tests/chains/Zilliqa/SignatureTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include "HexCoding.h" #include "Data.h" #include diff --git a/tests/Zilliqa/SignerTests.cpp b/tests/chains/Zilliqa/SignerTests.cpp similarity index 100% rename from tests/Zilliqa/SignerTests.cpp rename to tests/chains/Zilliqa/SignerTests.cpp diff --git a/tests/Zilliqa/TWAnySignerTests.cpp b/tests/chains/Zilliqa/TWAnySignerTests.cpp similarity index 98% rename from tests/Zilliqa/TWAnySignerTests.cpp rename to tests/chains/Zilliqa/TWAnySignerTests.cpp index 876e6abec5b..acf610c7a29 100644 --- a/tests/Zilliqa/TWAnySignerTests.cpp +++ b/tests/chains/Zilliqa/TWAnySignerTests.cpp @@ -7,7 +7,7 @@ #include "HexCoding.h" #include "uint256.h" #include "proto/Zilliqa.pb.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Zilliqa/TWCoinTypeTests.cpp b/tests/chains/Zilliqa/TWCoinTypeTests.cpp similarity index 97% rename from tests/Zilliqa/TWCoinTypeTests.cpp rename to tests/chains/Zilliqa/TWCoinTypeTests.cpp index 0b1d57ea02b..d0d51a694b2 100644 --- a/tests/Zilliqa/TWCoinTypeTests.cpp +++ b/tests/chains/Zilliqa/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/Zilliqa/TWZilliqaAddressTests.cpp b/tests/chains/Zilliqa/TWZilliqaAddressTests.cpp similarity index 97% rename from tests/Zilliqa/TWZilliqaAddressTests.cpp rename to tests/chains/Zilliqa/TWZilliqaAddressTests.cpp index e2e19630cbe..2677af67c45 100644 --- a/tests/Zilliqa/TWZilliqaAddressTests.cpp +++ b/tests/chains/Zilliqa/TWZilliqaAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/ZkSyncV2/TWCoinTypeTests.cpp b/tests/chains/ZkSyncV2/TWCoinTypeTests.cpp similarity index 97% rename from tests/ZkSyncV2/TWCoinTypeTests.cpp rename to tests/chains/ZkSyncV2/TWCoinTypeTests.cpp index 9b00c8112a6..95b4854e53e 100644 --- a/tests/ZkSyncV2/TWCoinTypeTests.cpp +++ b/tests/chains/ZkSyncV2/TWCoinTypeTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/xDai/TWCoinTypeTests.cpp b/tests/chains/xDai/TWCoinTypeTests.cpp similarity index 97% rename from tests/xDai/TWCoinTypeTests.cpp rename to tests/chains/xDai/TWCoinTypeTests.cpp index 05d70075d8d..c49ec7395f1 100644 --- a/tests/xDai/TWCoinTypeTests.cpp +++ b/tests/chains/xDai/TWCoinTypeTests.cpp @@ -8,7 +8,7 @@ // Generated one-time (codegen/bin/cointests) // -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/AnyAddressTests.cpp b/tests/common/AnyAddressTests.cpp similarity index 100% rename from tests/AnyAddressTests.cpp rename to tests/common/AnyAddressTests.cpp diff --git a/tests/BCSTests.cpp b/tests/common/BCSTests.cpp similarity index 100% rename from tests/BCSTests.cpp rename to tests/common/BCSTests.cpp diff --git a/tests/Base64Tests.cpp b/tests/common/Base64Tests.cpp similarity index 100% rename from tests/Base64Tests.cpp rename to tests/common/Base64Tests.cpp diff --git a/tests/BaseEncoding.cpp b/tests/common/BaseEncoding.cpp similarity index 100% rename from tests/BaseEncoding.cpp rename to tests/common/BaseEncoding.cpp diff --git a/tests/Bech32AddressTests.cpp b/tests/common/Bech32AddressTests.cpp similarity index 100% rename from tests/Bech32AddressTests.cpp rename to tests/common/Bech32AddressTests.cpp diff --git a/tests/Bech32Tests.cpp b/tests/common/Bech32Tests.cpp similarity index 100% rename from tests/Bech32Tests.cpp rename to tests/common/Bech32Tests.cpp diff --git a/tests/BinaryCodingTests.cpp b/tests/common/BinaryCodingTests.cpp similarity index 100% rename from tests/BinaryCodingTests.cpp rename to tests/common/BinaryCodingTests.cpp diff --git a/tests/CborTests.cpp b/tests/common/CborTests.cpp similarity index 100% rename from tests/CborTests.cpp rename to tests/common/CborTests.cpp diff --git a/tests/CoinAddressDerivationTests.cpp b/tests/common/CoinAddressDerivationTests.cpp similarity index 100% rename from tests/CoinAddressDerivationTests.cpp rename to tests/common/CoinAddressDerivationTests.cpp diff --git a/tests/CoinAddressValidationTests.cpp b/tests/common/CoinAddressValidationTests.cpp similarity index 100% rename from tests/CoinAddressValidationTests.cpp rename to tests/common/CoinAddressValidationTests.cpp diff --git a/tests/DataTests.cpp b/tests/common/DataTests.cpp similarity index 100% rename from tests/DataTests.cpp rename to tests/common/DataTests.cpp diff --git a/tests/EncryptTests.cpp b/tests/common/EncryptTests.cpp similarity index 100% rename from tests/EncryptTests.cpp rename to tests/common/EncryptTests.cpp diff --git a/tests/HDWallet/HDWalletInternalTests.cpp b/tests/common/HDWallet/HDWalletInternalTests.cpp similarity index 99% rename from tests/HDWallet/HDWalletInternalTests.cpp rename to tests/common/HDWallet/HDWalletInternalTests.cpp index 10c7282a665..1f27ad22cca 100644 --- a/tests/HDWallet/HDWalletInternalTests.cpp +++ b/tests/common/HDWallet/HDWalletInternalTests.cpp @@ -11,7 +11,7 @@ #include "PublicKey.h" #include #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/HDWallet/HDWalletTests.cpp b/tests/common/HDWallet/HDWalletTests.cpp similarity index 99% rename from tests/HDWallet/HDWalletTests.cpp rename to tests/common/HDWallet/HDWalletTests.cpp index 893eefb3a5f..9bc90832bed 100644 --- a/tests/HDWallet/HDWalletTests.cpp +++ b/tests/common/HDWallet/HDWalletTests.cpp @@ -15,7 +15,7 @@ #include "Hash.h" #include "Base58.h" #include "Coin.h" -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include @@ -253,7 +253,7 @@ TEST(HDWallet, DeriveWithLeadingZerosEth) { } static nlohmann::json getVectors() { - const std::string vectorsJsonPath = std::string(TESTS_ROOT) + "/HDWallet/bip39_vectors.json"; + const std::string vectorsJsonPath = std::string(TESTS_ROOT) + "/common/HDWallet/bip39_vectors.json"; auto vectorsJson = loadJson(vectorsJsonPath)["english"]; return vectorsJson; } diff --git a/tests/HDWallet/bip39_vectors.json b/tests/common/HDWallet/bip39_vectors.json similarity index 100% rename from tests/HDWallet/bip39_vectors.json rename to tests/common/HDWallet/bip39_vectors.json diff --git a/tests/HashTests.cpp b/tests/common/HashTests.cpp similarity index 100% rename from tests/HashTests.cpp rename to tests/common/HashTests.cpp diff --git a/tests/HexCodingTests.cpp b/tests/common/HexCodingTests.cpp similarity index 100% rename from tests/HexCodingTests.cpp rename to tests/common/HexCodingTests.cpp diff --git a/tests/Keystore/Data/empty-accounts.json b/tests/common/Keystore/Data/empty-accounts.json similarity index 100% rename from tests/Keystore/Data/empty-accounts.json rename to tests/common/Keystore/Data/empty-accounts.json diff --git a/tests/Keystore/Data/ethereum-wallet-address-no-0x.json b/tests/common/Keystore/Data/ethereum-wallet-address-no-0x.json similarity index 100% rename from tests/Keystore/Data/ethereum-wallet-address-no-0x.json rename to tests/common/Keystore/Data/ethereum-wallet-address-no-0x.json diff --git a/tests/Keystore/Data/key.json b/tests/common/Keystore/Data/key.json similarity index 100% rename from tests/Keystore/Data/key.json rename to tests/common/Keystore/Data/key.json diff --git a/tests/Keystore/Data/key_bitcoin.json b/tests/common/Keystore/Data/key_bitcoin.json similarity index 100% rename from tests/Keystore/Data/key_bitcoin.json rename to tests/common/Keystore/Data/key_bitcoin.json diff --git a/tests/Keystore/Data/legacy-mnemonic.json b/tests/common/Keystore/Data/legacy-mnemonic.json similarity index 100% rename from tests/Keystore/Data/legacy-mnemonic.json rename to tests/common/Keystore/Data/legacy-mnemonic.json diff --git a/tests/Keystore/Data/legacy-private-key.json b/tests/common/Keystore/Data/legacy-private-key.json similarity index 100% rename from tests/Keystore/Data/legacy-private-key.json rename to tests/common/Keystore/Data/legacy-private-key.json diff --git a/tests/Keystore/Data/livepeer.json b/tests/common/Keystore/Data/livepeer.json similarity index 100% rename from tests/Keystore/Data/livepeer.json rename to tests/common/Keystore/Data/livepeer.json diff --git a/tests/Keystore/Data/missing-address.json b/tests/common/Keystore/Data/missing-address.json similarity index 100% rename from tests/Keystore/Data/missing-address.json rename to tests/common/Keystore/Data/missing-address.json diff --git a/tests/Keystore/Data/myetherwallet.uu b/tests/common/Keystore/Data/myetherwallet.uu similarity index 100% rename from tests/Keystore/Data/myetherwallet.uu rename to tests/common/Keystore/Data/myetherwallet.uu diff --git a/tests/Keystore/Data/pbkdf2.json b/tests/common/Keystore/Data/pbkdf2.json similarity index 100% rename from tests/Keystore/Data/pbkdf2.json rename to tests/common/Keystore/Data/pbkdf2.json diff --git a/tests/Keystore/Data/wallet.json b/tests/common/Keystore/Data/wallet.json similarity index 100% rename from tests/Keystore/Data/wallet.json rename to tests/common/Keystore/Data/wallet.json diff --git a/tests/Keystore/Data/watch.json b/tests/common/Keystore/Data/watch.json similarity index 100% rename from tests/Keystore/Data/watch.json rename to tests/common/Keystore/Data/watch.json diff --git a/tests/Keystore/Data/web3j.json b/tests/common/Keystore/Data/web3j.json similarity index 100% rename from tests/Keystore/Data/web3j.json rename to tests/common/Keystore/Data/web3j.json diff --git a/tests/Keystore/DerivationPathTests.cpp b/tests/common/Keystore/DerivationPathTests.cpp similarity index 100% rename from tests/Keystore/DerivationPathTests.cpp rename to tests/common/Keystore/DerivationPathTests.cpp diff --git a/tests/Keystore/StoredKeyTests.cpp b/tests/common/Keystore/StoredKeyTests.cpp similarity index 95% rename from tests/Keystore/StoredKeyTests.cpp rename to tests/common/Keystore/StoredKeyTests.cpp index e792c0f7ab5..51cc959968d 100644 --- a/tests/Keystore/StoredKeyTests.cpp +++ b/tests/common/Keystore/StoredKeyTests.cpp @@ -18,7 +18,7 @@ extern std::string TESTS_ROOT; -namespace TW::Keystore { +namespace TW::Keystore::tests { using namespace std; @@ -31,6 +31,10 @@ const TWCoinType coinTypeBsc = TWCoinTypeSmartChain; const TWCoinType coinTypeEth = TWCoinTypeEthereum; const TWCoinType coinTypeBscLegacy = TWCoinTypeSmartChainLegacy; +const std::string testDataPath(const char* subpath) { + return TESTS_ROOT + "/common/Keystore/Data/" + subpath; +} + TEST(StoredKey, CreateWithMnemonic) { auto key = StoredKey::createWithMnemonic("name", gPassword, gMnemonic, TWStoredKeyEncryptionLevelDefault); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); @@ -272,11 +276,11 @@ TEST(StoredKey, WalletInvalid) { } TEST(StoredKey, LoadNonexistent) { - ASSERT_THROW(StoredKey::load(TESTS_ROOT + "/Keystore/Data/nonexistent.json"), invalid_argument); + ASSERT_THROW(StoredKey::load(testDataPath("nonexistent.json")), invalid_argument); } TEST(StoredKey, LoadLegacyPrivateKey) { - const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/legacy-private-key.json"); + const auto key = StoredKey::load(testDataPath("legacy-private-key.json")); EXPECT_EQ(key.type, StoredKeyType::privateKey); EXPECT_EQ(key.id, "3051ca7d-3d36-4a4a-acc2-09e9083732b0"); EXPECT_EQ(key.accounts[0].coin, TWCoinTypeEthereum); @@ -284,7 +288,7 @@ TEST(StoredKey, LoadLegacyPrivateKey) { } TEST(StoredKey, LoadLivepeerKey) { - const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/livepeer.json"); + const auto key = StoredKey::load(testDataPath("livepeer.json")); EXPECT_EQ(key.type, StoredKeyType::privateKey); EXPECT_EQ(key.id, "70ea3601-ee21-4e94-a7e4-66255a987d22"); EXPECT_EQ(key.accounts[0].coin, TWCoinTypeEthereum); @@ -292,7 +296,7 @@ TEST(StoredKey, LoadLivepeerKey) { } TEST(StoredKey, LoadPBKDF2Key) { - const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/pbkdf2.json"); + const auto key = StoredKey::load(testDataPath("pbkdf2.json")); EXPECT_EQ(key.type, StoredKeyType::privateKey); EXPECT_EQ(key.id, "3198bc9c-6672-5ab3-d995-4942343ae5b6"); @@ -306,7 +310,7 @@ TEST(StoredKey, LoadPBKDF2Key) { } TEST(StoredKey, LoadLegacyMnemonic) { - const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/legacy-mnemonic.json"); + const auto key = StoredKey::load(testDataPath("legacy-mnemonic.json")); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); EXPECT_EQ(key.id, "629aad29-0b22-488e-a0e7-b4219d4f311c"); @@ -324,7 +328,7 @@ TEST(StoredKey, LoadLegacyMnemonic) { } TEST(StoredKey, LoadFromWeb3j) { - const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/web3j.json"); + const auto key = StoredKey::load(testDataPath("web3j.json")); EXPECT_EQ(key.type, StoredKeyType::privateKey); EXPECT_EQ(key.id, "86066d8c-8dba-4d81-afd4-934e2a2b72a2"); const auto password = parse_hex("2d6eefbfbd4622efbfbdefbfbd516718efbfbdefbfbdefbfbdefbfbd59efbfbd30efbfbdefbfbd3a4348efbfbd2aefbfbdefbfbd49efbfbd27efbfbd0638efbfbdefbfbdefbfbd4cefbfbd6befbfbdefbfbd6defbfbdefbfbd63efbfbd5aefbfbd61262b70efbfbdefbfbdefbfbdefbfbdefbfbdc7aa373163417cefbfbdefbfbdefbfbd44efbfbdefbfbd1d10efbfbdefbfbdefbfbd61dc9e5b124befbfbd11efbfbdefbfbd2fefbfbdefbfbd3d7c574868efbfbdefbfbdefbfbd37043b7b5c1a436471592f02efbfbd18efbfbdefbfbd2befbfbdefbfbd7218efbfbd6a68efbfbdcb8e5f3328773ec48174efbfbd67efbfbdefbfbdefbfbdefbfbdefbfbd2a31efbfbd7f60efbfbdd884efbfbd57efbfbd25efbfbd590459efbfbd37efbfbd2bdca20fefbfbdefbfbdefbfbdefbfbd39450113efbfbdefbfbdefbfbd454671efbfbdefbfbdd49fefbfbd47efbfbdefbfbdefbfbdefbfbd00efbfbdefbfbdefbfbdefbfbd05203f4c17712defbfbd7bd1bbdc967902efbfbdc98a77efbfbd707a36efbfbd12efbfbdefbfbd57c78cefbfbdefbfbdefbfbd10efbfbdefbfbdefbfbde1a1bb08efbfbdefbfbd26efbfbdefbfbd58efbfbdefbfbdc4b1efbfbd295fefbfbd0eefbfbdefbfbdefbfbd0e6eefbfbd"); @@ -333,7 +337,7 @@ TEST(StoredKey, LoadFromWeb3j) { } TEST(StoredKey, ReadWallet) { - const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/key.json"); + const auto key = StoredKey::load(testDataPath("key.json")); EXPECT_EQ(key.type, StoredKeyType::privateKey); EXPECT_EQ(key.id, "e13b209c-3b2f-4327-bab0-3bef2e51630d"); @@ -355,23 +359,23 @@ TEST(StoredKey, ReadWallet) { } TEST(StoredKey, ReadMyEtherWallet) { - ASSERT_NO_THROW(StoredKey::load(TESTS_ROOT + "/Keystore/Data/myetherwallet.uu")); + ASSERT_NO_THROW(StoredKey::load(testDataPath("myetherwallet.uu"))); } TEST(StoredKey, InvalidPassword) { - const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/key.json"); + const auto key = StoredKey::load(testDataPath("key.json")); ASSERT_THROW(key.payload.decrypt(gPassword), DecryptionError); } TEST(StoredKey, EmptyAccounts) { - const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/empty-accounts.json"); + const auto key = StoredKey::load(testDataPath("empty-accounts.json")); ASSERT_NO_THROW(key.payload.decrypt(TW::data("testpassword"))); } TEST(StoredKey, Decrypt) { - const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/key.json"); + const auto key = StoredKey::load(testDataPath("key.json")); const auto privateKey = key.payload.decrypt(TW::data("testpassword")); EXPECT_EQ(hex(privateKey), "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d"); @@ -400,19 +404,19 @@ TEST(StoredKey, CreateAccounts) { } TEST(StoredKey, DecodingEthereumAddress) { - const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/key.json"); + const auto key = StoredKey::load(testDataPath("key.json")); EXPECT_EQ(key.accounts[0].address, "0x008AeEda4D805471dF9b2A5B0f38A0C3bCBA786b"); } TEST(StoredKey, DecodingBitcoinAddress) { - const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/key_bitcoin.json"); + const auto key = StoredKey::load(testDataPath("key_bitcoin.json")); EXPECT_EQ(key.accounts[0].address, "3PWazDi9n1Hfyq9gXFxDxzADNL8RNYyK2y"); } TEST(StoredKey, RemoveAccount) { - auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/legacy-mnemonic.json"); + auto key = StoredKey::load(testDataPath("legacy-mnemonic.json")); EXPECT_EQ(key.accounts.size(), 2ul); key.removeAccount(TWCoinTypeEthereum); EXPECT_EQ(key.accounts.size(), 1ul); @@ -420,7 +424,7 @@ TEST(StoredKey, RemoveAccount) { } TEST(StoredKey, MissingAddressFix) { - auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/missing-address.json"); + auto key = StoredKey::load(testDataPath("missing-address.json")); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); const auto wallet = key.wallet(gPassword); @@ -439,7 +443,7 @@ TEST(StoredKey, MissingAddressFix) { } TEST(StoredKey, MissingAddressReadd) { - auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/missing-address.json"); + auto key = StoredKey::load(testDataPath("missing-address.json")); EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); const auto wallet = key.wallet(gPassword); @@ -460,7 +464,7 @@ TEST(StoredKey, MissingAddressReadd) { } TEST(StoredKey, EtherWalletAddressNo0x) { - auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/ethereum-wallet-address-no-0x.json"); + auto key = StoredKey::load(testDataPath("ethereum-wallet-address-no-0x.json")); key.fixAddresses(TW::data("15748c4e3dca6ae2110535576ab0c398cb79d985707c68ee6c9f9df9d421dd53")); const auto account = key.account(TWCoinTypeEthereum, nullptr); EXPECT_EQ(account->address, "0xAc1ec44E4f0ca7D172B7803f6836De87Fb72b309"); diff --git a/tests/MnemonicTests.cpp b/tests/common/MnemonicTests.cpp similarity index 100% rename from tests/MnemonicTests.cpp rename to tests/common/MnemonicTests.cpp diff --git a/tests/NumericLiteralTests.cpp b/tests/common/NumericLiteralTests.cpp similarity index 100% rename from tests/NumericLiteralTests.cpp rename to tests/common/NumericLiteralTests.cpp diff --git a/tests/PrivateKeyTests.cpp b/tests/common/PrivateKeyTests.cpp similarity index 100% rename from tests/PrivateKeyTests.cpp rename to tests/common/PrivateKeyTests.cpp diff --git a/tests/PublicKeyTests.cpp b/tests/common/PublicKeyTests.cpp similarity index 99% rename from tests/PublicKeyTests.cpp rename to tests/common/PublicKeyTests.cpp index a9e2f09d115..1dae03fb237 100644 --- a/tests/PublicKeyTests.cpp +++ b/tests/common/PublicKeyTests.cpp @@ -9,7 +9,7 @@ #include "Hash.h" #include "HexCoding.h" #include "PrivateKey.h" -#include "interface/TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/interface/TWTestUtilities.cpp b/tests/common/TestUtilities.cpp similarity index 96% rename from tests/interface/TWTestUtilities.cpp rename to tests/common/TestUtilities.cpp index 7a7fae7b15a..76e34fd35f1 100644 --- a/tests/interface/TWTestUtilities.cpp +++ b/tests/common/TestUtilities.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/interface/TWTestUtilities.h b/tests/common/TestUtilities.h similarity index 100% rename from tests/interface/TWTestUtilities.h rename to tests/common/TestUtilities.h diff --git a/tests/TransactionCompilerTests.cpp b/tests/common/TransactionCompilerTests.cpp similarity index 99% rename from tests/TransactionCompilerTests.cpp rename to tests/common/TransactionCompilerTests.cpp index 9590eb07ef6..e2d26f1d07d 100644 --- a/tests/TransactionCompilerTests.cpp +++ b/tests/common/TransactionCompilerTests.cpp @@ -23,7 +23,7 @@ #include "uint256.h" #include -#include "interface/TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace TW; diff --git a/tests/Uint256Tests.cpp b/tests/common/Uint256Tests.cpp similarity index 100% rename from tests/Uint256Tests.cpp rename to tests/common/Uint256Tests.cpp diff --git a/tests/WalletConsoleTests.cpp b/tests/common/WalletConsoleTests.cpp similarity index 100% rename from tests/WalletConsoleTests.cpp rename to tests/common/WalletConsoleTests.cpp diff --git a/tests/algorithm/erase_tests.cpp b/tests/common/algorithm/erase_tests.cpp similarity index 100% rename from tests/algorithm/erase_tests.cpp rename to tests/common/algorithm/erase_tests.cpp diff --git a/tests/algorithm/sort_copy_tests.cpp b/tests/common/algorithm/sort_copy_tests.cpp similarity index 100% rename from tests/algorithm/sort_copy_tests.cpp rename to tests/common/algorithm/sort_copy_tests.cpp diff --git a/tests/algorithm/to_array_tests.cpp b/tests/common/algorithm/to_array_tests.cpp similarity index 100% rename from tests/algorithm/to_array_tests.cpp rename to tests/common/algorithm/to_array_tests.cpp diff --git a/tests/memory/memzero_tests.cpp b/tests/common/memory/memzero_tests.cpp similarity index 100% rename from tests/memory/memzero_tests.cpp rename to tests/common/memory/memzero_tests.cpp diff --git a/tests/operators/equality_comparable_tests.cpp b/tests/common/operators/equality_comparable_tests.cpp similarity index 100% rename from tests/operators/equality_comparable_tests.cpp rename to tests/common/operators/equality_comparable_tests.cpp diff --git a/tests/interface/TWAESTests.cpp b/tests/interface/TWAESTests.cpp index 8f1229ae5ca..0ee04dfdc5b 100644 --- a/tests/interface/TWAESTests.cpp +++ b/tests/interface/TWAESTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/interface/TWAccountTests.cpp b/tests/interface/TWAccountTests.cpp index cfcf75d3ce9..5a8bcf4661d 100644 --- a/tests/interface/TWAccountTests.cpp +++ b/tests/interface/TWAccountTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/interface/TWAnyAddressTests.cpp b/tests/interface/TWAnyAddressTests.cpp index bf6e4e98c42..c0bef30ab93 100644 --- a/tests/interface/TWAnyAddressTests.cpp +++ b/tests/interface/TWAnyAddressTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include "HexCoding.h" #include diff --git a/tests/interface/TWBase32Tests.cpp b/tests/interface/TWBase32Tests.cpp index c8d826dad86..a8582fa23f5 100644 --- a/tests/interface/TWBase32Tests.cpp +++ b/tests/interface/TWBase32Tests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include "Data.h" #include diff --git a/tests/interface/TWBase58Tests.cpp b/tests/interface/TWBase58Tests.cpp index 79542447036..f2c35aa11fe 100644 --- a/tests/interface/TWBase58Tests.cpp +++ b/tests/interface/TWBase58Tests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/interface/TWBase64Tests.cpp b/tests/interface/TWBase64Tests.cpp index d3da4e2f747..fc5332dfdd5 100644 --- a/tests/interface/TWBase64Tests.cpp +++ b/tests/interface/TWBase64Tests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include "Data.h" #include diff --git a/tests/interface/TWCoinTypeTests.cpp b/tests/interface/TWCoinTypeTests.cpp index 0390b8ad1e0..5fd55733ef8 100644 --- a/tests/interface/TWCoinTypeTests.cpp +++ b/tests/interface/TWCoinTypeTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/interface/TWDataTests.cpp b/tests/interface/TWDataTests.cpp index 73c287d5a2e..015c5e12b00 100644 --- a/tests/interface/TWDataTests.cpp +++ b/tests/interface/TWDataTests.cpp @@ -5,7 +5,7 @@ // file LICENSE at the root of the source code distribution tree. #include -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/interface/TWDataVectorTests.cpp b/tests/interface/TWDataVectorTests.cpp index 38779f4bb92..36a984c2e2c 100644 --- a/tests/interface/TWDataVectorTests.cpp +++ b/tests/interface/TWDataVectorTests.cpp @@ -6,7 +6,7 @@ #include #include "HexCoding.h" -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/interface/TWDerivationPathTests.cpp b/tests/interface/TWDerivationPathTests.cpp index 22cef1e8b32..15db6b2645e 100644 --- a/tests/interface/TWDerivationPathTests.cpp +++ b/tests/interface/TWDerivationPathTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include "TrustWalletCore/TWDerivation.h" #include "TrustWalletCore/TWPurpose.h" #include diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp index c826186dbfd..63fc42fec3c 100644 --- a/tests/interface/TWHDWalletTests.cpp +++ b/tests/interface/TWHDWalletTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include "Coin.h" diff --git a/tests/interface/TWHRPTests.cpp b/tests/interface/TWHRPTests.cpp index a4a205cb75a..a24bda956ff 100644 --- a/tests/interface/TWHRPTests.cpp +++ b/tests/interface/TWHRPTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tests/interface/TWHashTests.cpp b/tests/interface/TWHashTests.cpp index 09b4498c690..e67d0aeb36f 100644 --- a/tests/interface/TWHashTests.cpp +++ b/tests/interface/TWHashTests.cpp @@ -9,7 +9,7 @@ #include -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include using namespace std; diff --git a/tests/interface/TWMnemonicTests.cpp b/tests/interface/TWMnemonicTests.cpp index 6ed7d3b1a9c..df507c553a9 100644 --- a/tests/interface/TWMnemonicTests.cpp +++ b/tests/interface/TWMnemonicTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/interface/TWPBKDF2Tests.cpp b/tests/interface/TWPBKDF2Tests.cpp index 646126fb3de..57c48c73083 100644 --- a/tests/interface/TWPBKDF2Tests.cpp +++ b/tests/interface/TWPBKDF2Tests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/interface/TWPrivateKeyTests.cpp b/tests/interface/TWPrivateKeyTests.cpp index 96df973cf57..2ce9d6be10c 100644 --- a/tests/interface/TWPrivateKeyTests.cpp +++ b/tests/interface/TWPrivateKeyTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include "PrivateKey.h" #include "PublicKey.h" diff --git a/tests/interface/TWPublicKeyTests.cpp b/tests/interface/TWPublicKeyTests.cpp index 5fd8fbd7af8..64d712cc96a 100644 --- a/tests/interface/TWPublicKeyTests.cpp +++ b/tests/interface/TWPublicKeyTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include "PublicKey.h" #include "PrivateKey.h" diff --git a/tests/interface/TWStoredKeyTests.cpp b/tests/interface/TWStoredKeyTests.cpp index 9c34ea41a89..6cfa96c04c8 100644 --- a/tests/interface/TWStoredKeyTests.cpp +++ b/tests/interface/TWStoredKeyTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include #include @@ -41,7 +41,7 @@ struct std::shared_ptr createDefaultStoredKey() { } TEST(TWStoredKey, loadPBKDF2Key) { - const auto filename = WRAPS(TWStringCreateWithUTF8Bytes((TESTS_ROOT + "/Keystore/Data/pbkdf2.json").c_str())); + const auto filename = WRAPS(TWStringCreateWithUTF8Bytes((TESTS_ROOT + "/common/Keystore/Data/pbkdf2.json").c_str())); const auto key = WRAP(TWStoredKey, TWStoredKeyLoad(filename.get())); const auto keyId = WRAPS(TWStoredKeyIdentifier(key.get())); EXPECT_EQ(string(TWStringUTF8Bytes(keyId.get())), "3198bc9c-6672-5ab3-d995-4942343ae5b6"); diff --git a/tests/interface/TWStringTests.cpp b/tests/interface/TWStringTests.cpp index 17d800b6782..e79755ba76d 100644 --- a/tests/interface/TWStringTests.cpp +++ b/tests/interface/TWStringTests.cpp @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "TWTestUtilities.h" +#include "TestUtilities.h" #include diff --git a/tests/interface/TWTransactionCompilerTests.cpp b/tests/interface/TWTransactionCompilerTests.cpp index 20cab4a754e..fa97c94b719 100644 --- a/tests/interface/TWTransactionCompilerTests.cpp +++ b/tests/interface/TWTransactionCompilerTests.cpp @@ -22,7 +22,7 @@ #include "uint256.h" #include -#include "../interface/TWTestUtilities.h" +#include "TestUtilities.h" #include #include diff --git a/tools/generate-files b/tools/generate-files index 54c041b5fbe..aa694add2cc 100755 --- a/tools/generate-files +++ b/tools/generate-files @@ -63,7 +63,7 @@ fi "$PROTOC" -I=$PREFIX/include -I=src/Tron/Protobuf --cpp_out=src/Tron/Protobuf src/Tron/Protobuf/*.proto "$PROTOC" -I=$PREFIX/include -I=src/Zilliqa/Protobuf --cpp_out=src/Zilliqa/Protobuf src/Zilliqa/Protobuf/*.proto "$PROTOC" -I=$PREFIX/include -I=src/Cosmos/Protobuf --cpp_out=src/Cosmos/Protobuf src/Cosmos/Protobuf/*.proto -"$PROTOC" -I=$PREFIX/include -I=tests/Cosmos/Protobuf --cpp_out=tests/Cosmos/Protobuf tests/Cosmos/Protobuf/*.proto +"$PROTOC" -I=$PREFIX/include -I=tests/chains/Cosmos/Protobuf --cpp_out=tests/chains/Cosmos/Protobuf tests/chains/Cosmos/Protobuf/*.proto # Generate Proto interface file "$PROTOC" -I=$PREFIX/include -I=src/proto --plugin=$PREFIX/bin/protoc-gen-c-typedef --c-typedef_out include/TrustWalletCore src/proto/*.proto From dd3a474e31518a289991d198503870fd944e98bc Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 12 Oct 2022 14:32:35 +0200 Subject: [PATCH 109/497] [Cosmos]: add voting capabilities (#2638) --- src/Cosmos/Protobuf/gov_tx.proto | 24 +++++++++++++++++++ src/Cosmos/ProtobufSerialization.cpp | 35 ++++++++++++++++++++++++++++ src/proto/Cosmos.proto | 22 +++++++++++++++++ tests/chains/Cosmos/SignerTests.cpp | 30 ++++++++++++++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 src/Cosmos/Protobuf/gov_tx.proto diff --git a/src/Cosmos/Protobuf/gov_tx.proto b/src/Cosmos/Protobuf/gov_tx.proto new file mode 100644 index 00000000000..4f018a37e93 --- /dev/null +++ b/src/Cosmos/Protobuf/gov_tx.proto @@ -0,0 +1,24 @@ +// Since: cosmos-sdk 0.43 +syntax = "proto3"; +package cosmos.gov.v1beta1; + +// VoteOption enumerates the valid vote options for a given governance proposal. +enum VoteOption { + // VOTE_OPTION_UNSPECIFIED defines a no-op vote option. + VOTE_OPTION_UNSPECIFIED = 0; + // VOTE_OPTION_YES defines a yes vote option. + VOTE_OPTION_YES = 1; + // VOTE_OPTION_ABSTAIN defines an abstain vote option. + VOTE_OPTION_ABSTAIN = 2; + // VOTE_OPTION_NO defines a no vote option. + VOTE_OPTION_NO = 3; + // VOTE_OPTION_NO_WITH_VETO defines a no with veto vote option. + VOTE_OPTION_NO_WITH_VETO = 4; +} + +// MsgVote defines a message to cast a vote. +message MsgVote { + uint64 proposal_id = 1; + string voter = 2; + VoteOption option = 3; +} diff --git a/src/Cosmos/ProtobufSerialization.cpp b/src/Cosmos/ProtobufSerialization.cpp index a59f64463c0..e2f2e070890 100644 --- a/src/Cosmos/ProtobufSerialization.cpp +++ b/src/Cosmos/ProtobufSerialization.cpp @@ -14,6 +14,7 @@ #include "Protobuf/staking_tx.pb.h" #include "Protobuf/authz_tx.pb.h" #include "Protobuf/tx.pb.h" +#include "Protobuf/gov_tx.pb.h" #include "Protobuf/crypto_secp256k1_keys.pb.h" #include "Protobuf/ibc_applications_transfer_tx.pb.h" #include "Protobuf/terra_wasm_v1beta1_tx.pb.h" @@ -254,6 +255,40 @@ google::protobuf::Any convertMessage(const Proto::Message& msg) { any.PackFrom(msgAuthRevoke, ProtobufAnyNamespacePrefix); return any; } + case Proto::Message::kMsgVote: { + assert(msg.has_msg_vote()); + const auto& vote = msg.msg_vote(); + auto msgVote = cosmos::gov::v1beta1::MsgVote(); + // LCOV_EXCL_START + switch (vote.option()) { + case Proto::Message_VoteOption__UNSPECIFIED: + msgVote.set_option(cosmos::gov::v1beta1::VOTE_OPTION_UNSPECIFIED); + break; + case Proto::Message_VoteOption_YES: + msgVote.set_option(cosmos::gov::v1beta1::VOTE_OPTION_YES); + break; + case Proto::Message_VoteOption_ABSTAIN: + msgVote.set_option(cosmos::gov::v1beta1::VOTE_OPTION_ABSTAIN); + break; + case Proto::Message_VoteOption_NO: + msgVote.set_option(cosmos::gov::v1beta1::VOTE_OPTION_NO); + break; + case Proto::Message_VoteOption_NO_WITH_VETO: + msgVote.set_option(cosmos::gov::v1beta1::VOTE_OPTION_NO_WITH_VETO); + break; + case Proto::Message_VoteOption_Message_VoteOption_INT_MIN_SENTINEL_DO_NOT_USE_: + msgVote.set_option(cosmos::gov::v1beta1::VoteOption_INT_MIN_SENTINEL_DO_NOT_USE_); + break; + case Proto::Message_VoteOption_Message_VoteOption_INT_MAX_SENTINEL_DO_NOT_USE_: + msgVote.set_option(cosmos::gov::v1beta1::VoteOption_INT_MAX_SENTINEL_DO_NOT_USE_); + break; + } + // LCOV_EXCL_STOP + msgVote.set_proposal_id(vote.proposal_id()); + msgVote.set_voter(vote.voter()); + any.PackFrom(msgVote, ProtobufAnyNamespacePrefix); + return any; + } default: throw std::invalid_argument(std::string("Message not supported ") + std::to_string(msg.message_oneof_case())); diff --git a/src/proto/Cosmos.proto b/src/proto/Cosmos.proto index e95b00daa37..97c8bb2e358 100644 --- a/src/proto/Cosmos.proto +++ b/src/proto/Cosmos.proto @@ -270,6 +270,27 @@ message Message { string msg_type_url = 3; } + // VoteOption enumerates the valid vote options for a given governance proposal. + enum VoteOption { + //_UNSPECIFIED defines a no-op vote option. + _UNSPECIFIED = 0; + // YES defines a yes vote option. + YES = 1; + // ABSTAIN defines an abstain vote option. + ABSTAIN = 2; + // NO defines a no vote option. + NO = 3; + // NO_WITH_VETO defines a no with veto vote option. + NO_WITH_VETO = 4; + } + + // cosmos-sdk/MsgVote defines a message to cast a vote. + message MsgVote { + uint64 proposal_id = 1; + string voter = 2; + VoteOption option = 3; + } + // The payload message oneof message_oneof { Send send_coins_message = 1; @@ -289,6 +310,7 @@ message Message { SignDirect sign_direct_message = 15; AuthGrant auth_grant = 16; AuthRevoke auth_revoke = 17; + MsgVote msg_vote = 18; } } diff --git a/tests/chains/Cosmos/SignerTests.cpp b/tests/chains/Cosmos/SignerTests.cpp index a791e7bd10f..d9202607cc0 100644 --- a/tests/chains/Cosmos/SignerTests.cpp +++ b/tests/chains/Cosmos/SignerTests.cpp @@ -292,4 +292,34 @@ TEST(CosmosSigner, SignDirect_0a90010a) { EXPECT_EQ(output.error(), ""); } +TEST(CosmosSigner, MsgVote) { + // Successfully broadcasted https://www.mintscan.io/cosmos/txs/2EFA054B842B1641B131137B13360F95164C6C1D51BB4A4AC6DE8F75F504AA4C + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(1366160); + input.set_chain_id("cosmoshub-4"); + input.set_memo(""); + input.set_sequence(0); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_msg_vote(); + message.set_voter("cosmos1mry47pkga5tdswtluy0m8teslpalkdq07pswu4"); + message.set_proposal_id(77); + message.set_option(TW::Cosmos::Proto::Message_VoteOption_YES); + + auto& fee = *input.mutable_fee(); + fee.set_gas(97681); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uatom"); + amountOfFee->set_amount("2418"); + + auto privateKey = parse_hex("a498a9ee41af9bab5ef2a8be63d5c970135c3c109e70efc8c56c534e6636b433"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeCosmos); + auto expected = R"( + {"mode":"BROADCAST_MODE_BLOCK","tx_bytes":"ClQKUgobL2Nvc21vcy5nb3YudjFiZXRhMS5Nc2dWb3RlEjMITRItY29zbW9zMW1yeTQ3cGtnYTV0ZHN3dGx1eTBtOHRlc2xwYWxrZHEwN3Bzd3U0GAESZQpOCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAsv9teRyiTMiKU5gzwiD1D30MeEInSnstEep5tVQRarlEgQKAggBEhMKDQoFdWF0b20SBDI0MTgQkfsFGkA+Nb3NULc38quGC1x+8ZXry4w9mMX3IA7wUjFboTv7kVOwPlleIc8UqIsjVvKTUFnUuW8dlGQzNR1KkvbvZ1NA"})"; + assertJSONEqual(output.serialized(), expected); +} + } // namespace TW::Cosmos::tests From 5e0319e2e6e697b9f416198408b30c747e1a6b45 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Wed, 12 Oct 2022 16:55:16 +0200 Subject: [PATCH 110/497] Constant time operation in Mnemonic::isValidWord (#2636) --- src/Mnemonic.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Mnemonic.cpp b/src/Mnemonic.cpp index 08a3112ec2a..1bff4d76ea7 100644 --- a/src/Mnemonic.cpp +++ b/src/Mnemonic.cpp @@ -28,16 +28,15 @@ inline const char* const* mnemonicWordlist() { return wordlist; } bool Mnemonic::isValidWord(const std::string& word) { const char* wordC = word.c_str(); const auto len = word.length(); + // Although this operation is not security-critical, we aim for constant-time operation here as well + // (i.e., no early exit on match) + auto found = false; for (const char* const* w = mnemonicWordlist(); *w != nullptr; ++w) { - if (strlen(*w) != len) { - continue; - } - if (strncmp(*w, wordC, len) == 0) { - return true; + if (strlen(*w) == len && strncmp(*w, wordC, len) == 0) { + found = true; } } - // not found - return false; + return found; } std::string Mnemonic::suggest(const std::string& prefix) { From d4fabe72f8ea782f69ed346695a3e431c5e561cb Mon Sep 17 00:00:00 2001 From: lolcathost <115231640+lolcathost@users.noreply.github.com> Date: Wed, 12 Oct 2022 19:54:53 +0400 Subject: [PATCH 111/497] add own implementation of crc32 checksum, remove boost dependancy (#2629) Co-authored-by: Angelo Laub --- src/Crc.cpp | 24 +++++++++--------------- src/Crc.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/Crc.cpp b/src/Crc.cpp index 37f4ea8ad6c..1cbbe6d2696 100644 --- a/src/Crc.cpp +++ b/src/Crc.cpp @@ -6,8 +6,7 @@ #include "Crc.h" -#include // for boost::crc_32_type - +#include #include using namespace TW; @@ -32,17 +31,12 @@ uint16_t Crc::crc16(uint8_t* bytes, uint32_t length) { return crc & 0xffff; } -uint32_t Crc::crc32(const Data& data) -{ - boost::crc_32_type result; - result.process_bytes((const void*)data.data(), data.size()); - return (uint32_t)result.checksum(); -} - -uint32_t Crc::crc32C(const Data& data) -{ - using crc_32c_type = boost::crc_optimal<32, 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true, true>; - crc_32c_type result; - result.process_bytes((const void*)data.data(), data.size()); - return (uint32_t)result.checksum(); +// Algorithm inspired by this old-style C implementation: +// https://web.mit.edu/freebsd/head/sys/libkern/crc32.c (Public Domain code) +uint32_t Crc::crc32(const Data& data) { + uint32_t c = std::numeric_limits::max(); + for (const auto byte : data) { + c = crc32_table[(c ^ byte) & 0xFF] ^ (c >> 8); + } + return ~c; } diff --git a/src/Crc.h b/src/Crc.h index 88bb3b28854..1180035491b 100644 --- a/src/Crc.h +++ b/src/Crc.h @@ -17,6 +17,50 @@ uint16_t crc16(uint8_t* bytes, uint32_t length); uint32_t crc32(const TW::Data& data); -uint32_t crc32C(const TW::Data& data); - +// Table taken from https://web.mit.edu/freebsd/head/sys/libkern/crc32.c (Public Domain code) +// This table is used to speed up the crc calculation. +static constexpr uint32_t crc32_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; } // namespace TW::Crc From 485e66dbf54e9b532c635601defaf384916c88a5 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 13 Oct 2022 11:16:04 +0200 Subject: [PATCH 112/497] [Aptos]: Transfer V2, automatic account creation (#2644) --- .../app/blockchains/aptos/TestAptosSigner.kt | 12 ++-- src/Aptos/MoveTypes.h | 4 ++ src/Aptos/Signer.cpp | 20 +++--- swift/Tests/Blockchains/AptosTests.swift | 12 ++-- tests/chains/Aptos/SignerTests.cpp | 61 +++---------------- tests/chains/Aptos/TWAnySignerTests.cpp | 22 +++---- 6 files changed, 44 insertions(+), 87 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt index 32df8c8e33e..6d52a4c9d1d 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt @@ -25,15 +25,15 @@ class TestAptosSigner { @Test fun AptosTransactionSigning() { - // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xbb3b3c33781c27e486afa2db854fb0a5c846d0967672feb2c6c3297a2b14e1ce?network=Devnet + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xb4d62afd3862116e060dd6ad9848ccb50c2bc177799819f1d29c059ae2042467?network=devnet val key = "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec".toHexBytesInByteString() val transfer = Aptos.TransferMessage.newBuilder().setAmount(1000) .setTo("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30").build() - val signingInput = Aptos.SigningInput.newBuilder().setChainId(32) + val signingInput = Aptos.SigningInput.newBuilder().setChainId(33) .setSender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30") - .setSequenceNumber(15) + .setSequenceNumber(99) .setGasUnitPrice(100) .setMaxGasAmount(3296766) .setExpirationTimestampSecs(3664390082) @@ -44,15 +44,15 @@ class TestAptosSigner { val result = AnySigner.sign(signingInput, CoinType.APTOS, Aptos.SigningOutput.parser()) assertEquals( Numeric.cleanHexPrefix(Numeric.toHexString(result.rawTxn.toByteArray())), - "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000020" + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000021" ) assertEquals( Numeric.cleanHexPrefix(Numeric.toHexString(result.authenticator.signature.toByteArray())), - "2ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05" + "5707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01" ) assertEquals( Numeric.cleanHexPrefix(Numeric.toHexString(result.encoded.toByteArray())), - "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000200020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c402ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05" + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000210020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c405707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01" ) } } diff --git a/src/Aptos/MoveTypes.h b/src/Aptos/MoveTypes.h index 7f77f9995ca..2a0b6728e3b 100644 --- a/src/Aptos/MoveTypes.h +++ b/src/Aptos/MoveTypes.h @@ -33,6 +33,10 @@ class ModuleId { Identifier mName; }; +inline ModuleId gAptosAccountModule{gAddressOne, "aptos_account"}; +inline ModuleId gAptosCoinModule{gAddressOne, "coin"}; +inline ModuleId gAptosTokenTransfersModule{gAddressThree, "token_transfers"}; + BCS::Serializer& operator<<(BCS::Serializer& stream, const ModuleId& module) noexcept; struct TypeTag; diff --git a/src/Aptos/Signer.cpp b/src/Aptos/Signer.cpp index e734c34edc4..d1c2684039d 100644 --- a/src/Aptos/Signer.cpp +++ b/src/Aptos/Signer.cpp @@ -33,23 +33,20 @@ std::pair, nlohmann::json> commonTransferPayload(const TPayloa TransactionPayload transferPayload(const Proto::SigningInput& input) { auto&& [args, argsJson] = commonTransferPayload(input.transfer()); - ModuleId module(gAddressOne, "coin"); - TransactionPayload payload = EntryFunction(module, "transfer", {gTransferTag}, args, argsJson); + TransactionPayload payload = EntryFunction(gAptosAccountModule, "transfer", {}, args, argsJson); return payload; } TransactionPayload createAccountPayload(const Proto::SigningInput& input) { - ModuleId module(gAddressOne, "aptos_account"); std::vector args; serializeToArgs(args, Address(input.create_account().auth_key())); nlohmann::json argsJson = nlohmann::json::array({input.create_account().auth_key()}); - TransactionPayload payload = EntryFunction(module, "create_account", {}, args, argsJson); + TransactionPayload payload = EntryFunction(gAptosAccountModule, "create_account", {}, args, argsJson); return payload; } TransactionPayload claimNftPayload(const Proto::ClaimNftMessage& msg) { std::vector args; - ModuleId module(gAddressThree, "token_transfers"); serializeToArgs(args, Address(msg.sender())); serializeToArgs(args, Address(msg.creator())); serializeToArgs(args, msg.collectionname()); @@ -65,13 +62,12 @@ TransactionPayload claimNftPayload(const Proto::ClaimNftMessage& msg) { std::to_string(msg.property_version()), }); // clang-format on - TransactionPayload payload = EntryFunction(module, "claim_script", {}, args, argsJson); + TransactionPayload payload = EntryFunction(gAptosTokenTransfersModule, "claim_script", {}, args, argsJson); return payload; } TransactionPayload nftOfferPayload(const Proto::OfferNftMessage& msg) { std::vector args; - ModuleId module(gAddressThree, "token_transfers"); serializeToArgs(args, Address(msg.receiver())); serializeToArgs(args, Address(msg.creator())); serializeToArgs(args, msg.collectionname()); @@ -89,13 +85,12 @@ TransactionPayload nftOfferPayload(const Proto::OfferNftMessage& msg) { std::to_string(msg.amount()) }); // clang-format on - TransactionPayload payload = EntryFunction(module, "offer_script", {}, args, argsJson); + TransactionPayload payload = EntryFunction(gAptosTokenTransfersModule, "offer_script", {}, args, argsJson); return payload; } TransactionPayload cancelNftOfferPayload(const Proto::CancelOfferNftMessage& msg) { std::vector args; - ModuleId module(gAddressThree, "token_transfers"); serializeToArgs(args, Address(msg.receiver())); serializeToArgs(args, Address(msg.creator())); serializeToArgs(args, msg.collectionname()); @@ -111,7 +106,7 @@ TransactionPayload cancelNftOfferPayload(const Proto::CancelOfferNftMessage& msg std::to_string(msg.property_version()), }); // clang-format on - TransactionPayload payload = EntryFunction(module, "cancel_offer_script", {}, args, argsJson); + TransactionPayload payload = EntryFunction(gAptosTokenTransfersModule, "cancel_offer_script", {}, args, argsJson); return payload; } @@ -121,8 +116,7 @@ TransactionPayload tokenTransferPayload(const Proto::SigningInput& input) { auto& function = input.token_transfer().function(); TypeTag tokenTransferTag = {TypeTag::TypeTagVariant(TStructTag{.st = StructTag(Address(function.account_address()), function.module(), function.name(), {})})}; - ModuleId module(gAddressOne, "coin"); - TransactionPayload payload = EntryFunction(module, "transfer", {tokenTransferTag}, args, argsJson); + TransactionPayload payload = EntryFunction(gAptosCoinModule, "transfer", {tokenTransferTag}, args, argsJson); return payload; } @@ -166,7 +160,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) { case Proto::NftMessage::kClaimNft: return claimNftPayload(nftMessage.claim_nft()); case Proto::NftMessage::NFT_TRANSACTION_PAYLOAD_NOT_SET: - throw std::runtime_error("Nft message payload not set"); + throw std::runtime_error("Nft message payload not set"); } }; auto payloadFunctor = [&input, &nftPayloadFunctor]() { diff --git a/swift/Tests/Blockchains/AptosTests.swift b/swift/Tests/Blockchains/AptosTests.swift index d617c67db98..3c54581dafe 100644 --- a/swift/Tests/Blockchains/AptosTests.swift +++ b/swift/Tests/Blockchains/AptosTests.swift @@ -21,26 +21,26 @@ class AptosTests: XCTestCase { } func testSign() { - // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xbb3b3c33781c27e486afa2db854fb0a5c846d0967672feb2c6c3297a2b14e1ce?network=Devnet + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xb4d62afd3862116e060dd6ad9848ccb50c2bc177799819f1d29c059ae2042467?network=devnet let privateKeyData = Data(hexString: "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")! let transferMsg = AptosTransferMessage.with { $0.to = "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30" $0.amount = 1000 } let input = AptosSigningInput.with { - $0.chainID = 32 + $0.chainID = 33 $0.sender = "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30" $0.expirationTimestampSecs = 3664390082 $0.gasUnitPrice = 100 $0.maxGasAmount = 3296766 - $0.sequenceNumber = 15 + $0.sequenceNumber = 99 $0.transfer = transferMsg $0.privateKey = privateKeyData } let output: AptosSigningOutput = AnySigner.sign(input: input, coin: .aptos) - let expectedRawTx = "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000020" - let expectedSignature = "2ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05" - let expectedSignedTx = "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000200020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c402ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05" + let expectedRawTx = "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000021" + let expectedSignature = "5707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01" + let expectedSignedTx = "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000210020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c405707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01" XCTAssertEqual(output.rawTxn.hexString, expectedRawTx) XCTAssertEqual(output.authenticator.signature.hexString, expectedSignature) XCTAssertEqual(output.encoded.hexString, expectedSignedTx) diff --git a/tests/chains/Aptos/SignerTests.cpp b/tests/chains/Aptos/SignerTests.cpp index 3e0145d677b..bd796c0576b 100644 --- a/tests/chains/Aptos/SignerTests.cpp +++ b/tests/chains/Aptos/SignerTests.cpp @@ -16,47 +16,6 @@ namespace TW::Aptos::tests { -TEST(AptosSigner, DummyTxSign) { - Proto::SigningInput input; - input.set_sender("0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b"); - input.set_sequence_number(1); - auto& tf = *input.mutable_transfer(); - tf.set_to("0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b"); - tf.set_amount(1000); - input.set_max_gas_amount(1); - input.set_gas_unit_price(1); - input.set_expiration_timestamp_secs(1); - input.set_chain_id(1); - auto privateKey = PrivateKey(parse_hex("7f2634c0e2414a621e96e39c41d09021700cee12ee43328ed094c5580cd0bd6f")); - input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - auto result = Signer::sign(input); - ASSERT_EQ(hex(result.raw_txn()), "eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b010000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e000220eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b08e80300000000000001000000000000000100000000000000010000000000000001"); - ASSERT_EQ(hex(result.authenticator().signature()), "9d3bd902bd358364c43fa65ece335dd4411527e72e1c6deb9148744eaa24e39b6bd74ff6b0195114243bdd2ee3a98511ff05883d9e79161b2b8f5029d883c309"); - ASSERT_EQ(hex(result.encoded()), "eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b010000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e000220eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b08e803000000000000010000000000000001000000000000000100000000000000010020633e5c7e355bdd484706436ce1f06fdf280bd7c2229a7f9b6489684412c6967c409d3bd902bd358364c43fa65ece335dd4411527e72e1c6deb9148744eaa24e39b6bd74ff6b0195114243bdd2ee3a98511ff05883d9e79161b2b8f5029d883c309"); - nlohmann::json expectedJson = R"( - { - "sender": "0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b", - "sequence_number": "1", - "max_gas_amount": "1", - "gas_unit_price": "1", - "expiration_timestamp_secs": "1", - "payload": { - "type":"entry_function_payload", - "function": "0x1::coin::transfer", - "type_arguments":["0x1::aptos_coin::AptosCoin"], - "arguments": ["0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b", "1000"] - }, - "signature": { - "type": "ed25519_signature", - "public_key": "0x633e5c7e355bdd484706436ce1f06fdf280bd7c2229a7f9b6489684412c6967c", - "signature": "0x9d3bd902bd358364c43fa65ece335dd4411527e72e1c6deb9148744eaa24e39b6bd74ff6b0195114243bdd2ee3a98511ff05883d9e79161b2b8f5029d883c309" - } - } - )"_json; - nlohmann::json parsedJson = nlohmann::json::parse(result.json()); - assertJSONEqual(expectedJson, parsedJson); -} - TEST(AptosSigner, ClaimNftTxSign) { // Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x60b51e15140ec0b7650334e948fb447ce3cb13ae63492260461ebfa9d02e85c4?network=testnet Proto::SigningInput input; @@ -203,23 +162,23 @@ TEST(AptosSigner, CancelNftOfferTxSign) { } TEST(AptosSigner, TxSign) { - // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xbb3b3c33781c27e486afa2db854fb0a5c846d0967672feb2c6c3297a2b14e1ce?network=Devnet + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xb4d62afd3862116e060dd6ad9848ccb50c2bc177799819f1d29c059ae2042467?network=devnet Proto::SigningInput input; input.set_sender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); - input.set_sequence_number(15); + input.set_sequence_number(99); auto& tf = *input.mutable_transfer(); tf.set_to("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); tf.set_amount(1000); input.set_max_gas_amount(3296766); input.set_gas_unit_price(100); input.set_expiration_timestamp_secs(3664390082); - input.set_chain_id(32); + input.set_chain_id(33); auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); auto result = Signer::sign(input); - ASSERT_EQ(hex(result.raw_txn()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000020"); - ASSERT_EQ(hex(result.authenticator().signature()), "2ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05"); - ASSERT_EQ(hex(result.encoded()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000200020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c402ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05"); + ASSERT_EQ(hex(result.raw_txn()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000021"); + ASSERT_EQ(hex(result.authenticator().signature()), "5707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01"); + ASSERT_EQ(hex(result.encoded()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000210020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c405707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01"); nlohmann::json expectedJson = R"( { "expiration_timestamp_secs": "3664390082", @@ -227,15 +186,15 @@ TEST(AptosSigner, TxSign) { "max_gas_amount": "3296766", "payload": { "arguments": ["0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30","1000"], - "function": "0x1::coin::transfer", + "function": "0x1::aptos_account::transfer", "type": "entry_function_payload", - "type_arguments": ["0x1::aptos_coin::AptosCoin"] + "type_arguments": [] }, "sender": "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", - "sequence_number": "15", + "sequence_number": "99", "signature": { "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", - "signature": "0x2ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05", + "signature": "0x5707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01", "type": "ed25519_signature" } } diff --git a/tests/chains/Aptos/TWAnySignerTests.cpp b/tests/chains/Aptos/TWAnySignerTests.cpp index e42890edf7b..e97b0977d9f 100644 --- a/tests/chains/Aptos/TWAnySignerTests.cpp +++ b/tests/chains/Aptos/TWAnySignerTests.cpp @@ -18,24 +18,24 @@ namespace TW::Aptos::tests { TEST(TWAnySignerAptos, TxSign) { - // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xbb3b3c33781c27e486afa2db854fb0a5c846d0967672feb2c6c3297a2b14e1ce?network=Devnet + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xb4d62afd3862116e060dd6ad9848ccb50c2bc177799819f1d29c059ae2042467?network=devnet Proto::SigningInput input; input.set_sender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); - input.set_sequence_number(15); + input.set_sequence_number(99); auto& tf = *input.mutable_transfer(); tf.set_to("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); tf.set_amount(1000); input.set_max_gas_amount(3296766); input.set_gas_unit_price(100); input.set_expiration_timestamp_secs(3664390082); - input.set_chain_id(32); + input.set_chain_id(33); auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); Proto::SigningOutput output; ANY_SIGN(input, TWCoinTypeAptos); - ASSERT_EQ(hex(output.raw_txn()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000020"); - ASSERT_EQ(hex(output.authenticator().signature()), "2ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05"); - ASSERT_EQ(hex(output.encoded()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f300f0000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e00022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000200020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c402ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05"); + ASSERT_EQ(hex(output.raw_txn()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000021"); + ASSERT_EQ(hex(output.authenticator().signature()), "5707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01"); + ASSERT_EQ(hex(output.encoded()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000210020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c405707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01"); nlohmann::json expectedJson = R"( { "expiration_timestamp_secs": "3664390082", @@ -43,21 +43,21 @@ TEST(TWAnySignerAptos, TxSign) { "max_gas_amount": "3296766", "payload": { "arguments": ["0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30","1000"], - "function": "0x1::coin::transfer", + "function": "0x1::aptos_account::transfer", "type": "entry_function_payload", - "type_arguments": ["0x1::aptos_coin::AptosCoin"] + "type_arguments": [] }, "sender": "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", - "sequence_number": "15", + "sequence_number": "99", "signature": { "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", - "signature": "0x2ac7acac0e597d04017b8d9ecad1ee7c2e07f3346957e507ac06508fe5c42c74892a347875d8d8826485a6e9b267bb7a0f24212be29c333c941c5db79c93ce05", + "signature": "0x5707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01", "type": "ed25519_signature" } } )"_json; nlohmann::json parsedJson = nlohmann::json::parse(output.json()); - ASSERT_EQ(expectedJson, parsedJson); + assertJSONEqual(expectedJson, parsedJson); } } // namespace TW::Aptos::tests From cbcdb3ec856074c6998a842d30f9ef08c8b542b2 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 14 Oct 2022 10:18:08 +0200 Subject: [PATCH 113/497] [Aptos]: add register token capabilities(#2645) --- src/Aptos/MoveTypes.h | 1 + src/Aptos/Signer.cpp | 16 +++++++++-- src/Aptos/TransactionPayload.cpp | 2 +- src/proto/Aptos.proto | 32 +++++++++++++--------- tests/chains/Aptos/SignerTests.cpp | 43 ++++++++++++++++++++++++++++++ 5 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/Aptos/MoveTypes.h b/src/Aptos/MoveTypes.h index 2a0b6728e3b..c4360afcd83 100644 --- a/src/Aptos/MoveTypes.h +++ b/src/Aptos/MoveTypes.h @@ -35,6 +35,7 @@ class ModuleId { inline ModuleId gAptosAccountModule{gAddressOne, "aptos_account"}; inline ModuleId gAptosCoinModule{gAddressOne, "coin"}; +inline ModuleId gAptosManagedCoinsModule{gAddressOne, "managed_coin"}; inline ModuleId gAptosTokenTransfersModule{gAddressThree, "token_transfers"}; BCS::Serializer& operator<<(BCS::Serializer& stream, const ModuleId& module) noexcept; diff --git a/src/Aptos/Signer.cpp b/src/Aptos/Signer.cpp index d1c2684039d..9c15ea200af 100644 --- a/src/Aptos/Signer.cpp +++ b/src/Aptos/Signer.cpp @@ -120,6 +120,15 @@ TransactionPayload tokenTransferPayload(const Proto::SigningInput& input) { return payload; } +TransactionPayload registerTokenPayload(const Proto::SigningInput& input) { + + auto& function = input.register_token().function(); + TypeTag tokenRegisterTag = {TypeTag::TypeTagVariant(TStructTag{.st = StructTag(Address(function.account_address()), + function.module(), function.name(), {})})}; + TransactionPayload payload = EntryFunction(gAptosManagedCoinsModule, "register", {tokenRegisterTag}, {}); + return payload; +} + Proto::SigningOutput blindSign(const Proto::SigningInput& input) { auto output = Proto::SigningOutput(); BCS::Serializer serializer; @@ -174,9 +183,12 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) { case Proto::SigningInput::kNftMessage: { return nftPayloadFunctor(input.nft_message()); } - case Proto::SigningInput::kCreateAccount: + case Proto::SigningInput::kCreateAccount: { return createAccountPayload(input); - + } + case Proto::SigningInput::kRegisterToken: { + return registerTokenPayload(input); + } case Proto::SigningInput::TRANSACTION_PAYLOAD_NOT_SET: throw std::runtime_error("Transaction payload should be set"); } diff --git a/src/Aptos/TransactionPayload.cpp b/src/Aptos/TransactionPayload.cpp index a37a6f7c60d..1e5b188e290 100644 --- a/src/Aptos/TransactionPayload.cpp +++ b/src/Aptos/TransactionPayload.cpp @@ -48,7 +48,7 @@ nlohmann::json EntryFunction::json() const noexcept { {"type", "entry_function_payload"}, {"function", mModule.shortString() + "::" + mFunction}, {"type_arguments", tyArgsJson}, - {"arguments", mJsonArgs} + {"arguments", mJsonArgs.empty() ? nlohmann::json::array() : mJsonArgs} }; // clang-format on return out; diff --git a/src/proto/Aptos.proto b/src/proto/Aptos.proto index 4d28f034868..1972c1ea349 100644 --- a/src/proto/Aptos.proto +++ b/src/proto/Aptos.proto @@ -37,6 +37,12 @@ message TokenTransferMessage { StructTag function = 3; } +// Necessary fields to process a ManagedTokensRegisterMessage +message ManagedTokensRegisterMessage { + // token function to register, e.g BTC: 0x43417434fd869edee76cca2a4d2301e528a1551b1d719b75c350c3c97d15b8b9::coins::BTC + StructTag function = 1; +} + // Necessary fields to process a CreateAccountMessage message CreateAccountMessage { // auth account address to create @@ -101,24 +107,26 @@ message SigningInput { string sender = 1; // Sequence number, incremented atomically for each tx present on the account, start at 0 (int64) int64 sequence_number = 2; - oneof transaction_payload { - TransferMessage transfer = 3; - TokenTransferMessage token_transfer = 4; - CreateAccountMessage create_account = 5; - NftMessage nft_message = 6; - } // Max gas amount that the user is willing to pay (uint64) - uint64 max_gas_amount = 7; + uint64 max_gas_amount = 3; // Gas unit price - queried through API (uint64) - uint64 gas_unit_price = 8; + uint64 gas_unit_price = 4; // Expiration timestamp for the transaction, can't be in the past (uint64) - uint64 expiration_timestamp_secs = 9; + uint64 expiration_timestamp_secs = 5; // Chain id 1 (mainnet) 32(devnet) (uint32 - casted in uint8_t later) - uint32 chain_id = 10; + uint32 chain_id = 6; // Private key to sign the transaction (bytes) - bytes private_key = 11; + bytes private_key = 7; // hex encoded function to sign, use it for smart contract approval (string) - string any_encoded = 12; + string any_encoded = 8; + + oneof transaction_payload { + TransferMessage transfer = 9; + TokenTransferMessage token_transfer = 10; + CreateAccountMessage create_account = 11; + NftMessage nft_message = 12; + ManagedTokensRegisterMessage register_token = 13; + } } // Information related to the signed transaction diff --git a/tests/chains/Aptos/SignerTests.cpp b/tests/chains/Aptos/SignerTests.cpp index bd796c0576b..c47c05bc3e5 100644 --- a/tests/chains/Aptos/SignerTests.cpp +++ b/tests/chains/Aptos/SignerTests.cpp @@ -288,6 +288,49 @@ TEST(AptosSigner, BlindSign) { assertJSONEqual(expectedJson, parsedJson); } +TEST(AptosSigner, TokenRegisterTxSign) { + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xe591252daed785641bfbbcf72a5d17864568cf32e04c0cc9129f3a13834d0e8e?network=testnet + Proto::SigningInput input; + input.set_sender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); + input.set_sequence_number(23); + auto& tf = *input.mutable_register_token(); + tf.mutable_function()->set_account_address("0xe4497a32bf4a9fd5601b27661aa0b933a923191bf403bd08669ab2468d43b379"); + tf.mutable_function()->set_module("move_coin"); + tf.mutable_function()->set_name("MoveCoin"); + input.set_max_gas_amount(2000000); + input.set_gas_unit_price(100); + input.set_expiration_timestamp_secs(3664390082); + input.set_chain_id(2); + auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.raw_txn()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3017000000000000000200000000000000000000000000000000000000000000000000000000000000010c6d616e616765645f636f696e0872656769737465720107e4497a32bf4a9fd5601b27661aa0b933a923191bf403bd08669ab2468d43b379096d6f76655f636f696e084d6f7665436f696e000080841e00000000006400000000000000c2276ada0000000002"); + ASSERT_EQ(hex(result.authenticator().signature()), "e230b49f552fb85356dbec9df13f0dc56228eb7a9c29a8af3a99f4ae95b86c72bdcaa4ff1e9beb0bd81c298b967b9d97449856ec8bc672a08e2efef345c37100"); + ASSERT_EQ(hex(result.encoded()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3017000000000000000200000000000000000000000000000000000000000000000000000000000000010c6d616e616765645f636f696e0872656769737465720107e4497a32bf4a9fd5601b27661aa0b933a923191bf403bd08669ab2468d43b379096d6f76655f636f696e084d6f7665436f696e000080841e00000000006400000000000000c2276ada00000000020020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c40e230b49f552fb85356dbec9df13f0dc56228eb7a9c29a8af3a99f4ae95b86c72bdcaa4ff1e9beb0bd81c298b967b9d97449856ec8bc672a08e2efef345c37100"); + nlohmann::json expectedJson = R"( + { + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "2000000", + "payload": { + "arguments": [], + "function": "0x1::managed_coin::register", + "type": "entry_function_payload", + "type_arguments": ["0xe4497a32bf4a9fd5601b27661aa0b933a923191bf403bd08669ab2468d43b379::move_coin::MoveCoin"] + }, + "sender": "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "23", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0xe230b49f552fb85356dbec9df13f0dc56228eb7a9c29a8af3a99f4ae95b86c72bdcaa4ff1e9beb0bd81c298b967b9d97449856ec8bc672a08e2efef345c37100", + "type": "ed25519_signature" + } + } + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(result.json()); + assertJSONEqual(expectedJson, parsedJson); +} + TEST(AptosSigner, TokenTxSign) { // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xb5b383a5c7f99b2edb3bed9533f8169a89051b149d65876a82f4c0b9bf78a15b?network=Devnet Proto::SigningInput input; From 9e31eaf5ee338ac28de2fd823c9f948d81e67393 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 14 Oct 2022 11:02:12 +0200 Subject: [PATCH 114/497] [AnyAddress] Make AnyAddress work with arbitrary hrp (IBC chains) (#2643) --- .../app/blockchains/juno/TestJunoAddress.kt | 35 +++++++++++++ include/TrustWalletCore/TWAnyAddress.h | 28 +++++++++++ src/AnyAddress.cpp | 8 +-- src/AnyAddress.h | 4 +- src/Coin.cpp | 32 ++++++------ src/Coin.h | 10 ++-- src/Cosmos/Address.h | 5 ++ src/Cosmos/Entry.cpp | 14 ++++-- src/interface/TWAnyAddress.cpp | 23 +++++++++ swift/Tests/Addresses/JunoAddressTests.swift | 25 ++++++++++ tests/chains/Juno/TWAnyAddressTests.cpp | 50 +++++++++++++++++++ 11 files changed, 204 insertions(+), 30 deletions(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/juno/TestJunoAddress.kt create mode 100644 swift/Tests/Addresses/JunoAddressTests.swift create mode 100644 tests/chains/Juno/TWAnyAddressTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/juno/TestJunoAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/juno/TestJunoAddress.kt new file mode 100644 index 00000000000..d7db293adf0 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/juno/TestJunoAddress.kt @@ -0,0 +1,35 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.juno + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert +import org.junit.Test +import wallet.core.jni.* + +class TestJunoAddress { + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAnyAddressValidation() { + val addr = "juno1gckvjxau7k56f8wg8c8xj80khyp83y8x8eqc94" + val anyAddr = AnyAddress(addr, CoinType.COSMOS, "juno") + assert(AnyAddress.isValidBech32(anyAddr.description(), CoinType.COSMOS, "juno")) + assert(!AnyAddress.isValidBech32(anyAddr.description(), CoinType.BITCOIN, "juno")) + assert(!AnyAddress.isValid(anyAddr.description(), CoinType.BITCOIN)) + assert(!AnyAddress.isValid(anyAddr.description(), CoinType.COSMOS)) + } + + @Test + fun testAnyAddressFromPubkey() { + val pubKey = PublicKey("02753f5c275e1847ba4d2fd3df36ad00af2e165650b35fe3991e9c9c46f68b12bc".toHexByteArray(), PublicKeyType.SECP256K1) + val anyAddr = AnyAddress(pubKey, CoinType.COSMOS, "juno") + Assert.assertEquals(anyAddr.description(), "juno1cj2vfjec3c3luf9fx9vddnglhh9gawmncn4k5n"); + } +} diff --git a/include/TrustWalletCore/TWAnyAddress.h b/include/TrustWalletCore/TWAnyAddress.h index a815607989e..449d518ba2c 100644 --- a/include/TrustWalletCore/TWAnyAddress.h +++ b/include/TrustWalletCore/TWAnyAddress.h @@ -35,6 +35,15 @@ bool TWAnyAddressEqual(struct TWAnyAddress* _Nonnull lhs, struct TWAnyAddress* _ TW_EXPORT_STATIC_METHOD bool TWAnyAddressIsValid(TWString* _Nonnull string, enum TWCoinType coin); +/// Determines if the string is a valid Any address with the given hrp. +/// +/// \param string address to validate. +/// \param coin coin type of the address. +/// \param hrp explicit given hrp of the given address. +/// \return bool indicating if the address is valid. +TW_EXPORT_STATIC_METHOD +bool TWAnyAddressIsValidBech32(TWString* _Nonnull string, enum TWCoinType coin, TWString* _Nonnull hrp); + /// Creates an address from a string representation and a coin type. Must be deleted with TWAnyAddressDelete after use. /// /// \param string address to create. @@ -43,6 +52,16 @@ bool TWAnyAddressIsValid(TWString* _Nonnull string, enum TWCoinType coin); TW_EXPORT_STATIC_METHOD struct TWAnyAddress* _Nullable TWAnyAddressCreateWithString(TWString* _Nonnull string, enum TWCoinType coin); +/// Creates an bech32 address from a string representation, a coin type and the given hrp. Must be deleted with TWAnyAddressDelete after use. +/// +/// \param string address to create. +/// \param coin coin type of the address. +/// \param hrp hrp of the address. +/// \return TWAnyAddress pointer or nullptr if address and coin are invalid. +TW_EXPORT_STATIC_METHOD +struct TWAnyAddress* _Nullable TWAnyAddressCreateBech32(TWString* _Nonnull string, enum TWCoinType coin, TWString* _Nonnull hrp); + + /// Creates an address from a public key. /// /// \param publicKey derivates the address from the public key. @@ -51,6 +70,15 @@ struct TWAnyAddress* _Nullable TWAnyAddressCreateWithString(TWString* _Nonnull s TW_EXPORT_STATIC_METHOD struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKey(struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin); +/// Creates an bech32 address from a public key and a given hrp. +/// +/// \param publicKey derivates the address from the public key. +/// \param coin coin type of the address. +/// \param hrp hrp of the address. +/// \return TWAnyAddress pointer or nullptr if public key is invalid. +TW_EXPORT_STATIC_METHOD +struct TWAnyAddress* _Nonnull TWAnyAddressCreateBech32WithPublicKey(struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin, TWString* _Nonnull hrp); + /// Deletes an address. /// /// \param address address to delete. diff --git a/src/AnyAddress.cpp b/src/AnyAddress.cpp index 504e309da1c..9bb265cc041 100644 --- a/src/AnyAddress.cpp +++ b/src/AnyAddress.cpp @@ -15,8 +15,8 @@ Data AnyAddress::getData() const { return TW::addressToData(coin, address); } -AnyAddress* AnyAddress::createAddress(const std::string& address, enum TWCoinType coin) { - auto normalized = TW::normalizeAddress(coin, address); +AnyAddress* AnyAddress::createAddress(const std::string& address, enum TWCoinType coin, const std::string& hrp) { + auto normalized = TW::normalizeAddress(coin, address, hrp); if (normalized.empty()) { return nullptr; } @@ -24,8 +24,8 @@ AnyAddress* AnyAddress::createAddress(const std::string& address, enum TWCoinTyp return new AnyAddress{.address = std::move(normalized), .coin = coin}; } -AnyAddress* AnyAddress::createAddress(const PublicKey& publicKey, enum TWCoinType coin) { - auto derivedAddress = TW::deriveAddress(coin, publicKey); +AnyAddress* AnyAddress::createAddress(const PublicKey& publicKey, enum TWCoinType coin, const std::string& hrp) { + auto derivedAddress = TW::deriveAddress(coin, publicKey, TWDerivationDefault, hrp); return new AnyAddress{.address = std::move(derivedAddress), .coin = coin}; } diff --git a/src/AnyAddress.h b/src/AnyAddress.h index 78e8878a2fd..7bf773eaf07 100644 --- a/src/AnyAddress.h +++ b/src/AnyAddress.h @@ -22,8 +22,8 @@ class AnyAddress { enum TWCoinType coin; - static AnyAddress* createAddress(const std::string& address, enum TWCoinType coin); - static AnyAddress* createAddress(const PublicKey& publicKey, enum TWCoinType coin); + static AnyAddress* createAddress(const std::string& address, enum TWCoinType coin, const std::string& hrp = ""); + static AnyAddress* createAddress(const PublicKey& publicKey, enum TWCoinType coin, const std::string& hrp = ""); Data getData() const; }; diff --git a/src/Coin.cpp b/src/Coin.cpp index b727c1488ed..efe10e47e56 100644 --- a/src/Coin.cpp +++ b/src/Coin.cpp @@ -25,6 +25,7 @@ #include "EOS/Entry.h" #include "Elrond/Entry.h" #include "Ethereum/Entry.h" +#include "Everscale/Entry.h" #include "FIO/Entry.h" #include "Filecoin/Entry.h" #include "Groestlcoin/Entry.h" @@ -42,7 +43,6 @@ #include "Oasis/Entry.h" #include "Ontology/Entry.h" #include "Polkadot/Entry.h" -#include "XRP/Entry.h" #include "Ronin/Entry.h" #include "Solana/Entry.h" #include "Stellar/Entry.h" @@ -52,9 +52,9 @@ #include "Tron/Entry.h" #include "VeChain/Entry.h" #include "Waves/Entry.h" +#include "XRP/Entry.h" #include "Zcash/Entry.h" #include "Zilliqa/Entry.h" -#include "Everscale/Entry.h" // end_of_coin_includes_marker_do_not_modify using namespace TW; @@ -165,7 +165,7 @@ const Derivation CoinInfo::derivationByName(TWDerivation nameIn) const { if (nameIn == TWDerivationDefault && derivation.size() > 0) { return derivation[0]; } - for (auto deriv: derivation) { + for (auto deriv : derivation) { if (deriv.name == nameIn) { return deriv; } @@ -173,10 +173,9 @@ const Derivation CoinInfo::derivationByName(TWDerivation nameIn) const { return Derivation(); } -bool TW::validateAddress(TWCoinType coin, const std::string& string) { +bool TW::validateAddress(TWCoinType coin, const std::string& string, const char* hrp) { auto p2pkh = TW::p2pkhPrefix(coin); auto p2sh = TW::p2shPrefix(coin); - const auto* hrp = stringForHRP(TW::hrp(coin)); // dispatch auto* dispatcher = coinDispatcher(coin); @@ -184,8 +183,14 @@ bool TW::validateAddress(TWCoinType coin, const std::string& string) { return dispatcher->validateAddress(coin, string, p2pkh, p2sh, hrp); } -std::string TW::normalizeAddress(TWCoinType coin, const std::string& address) { - if (!TW::validateAddress(coin, address)) { +bool TW::validateAddress(TWCoinType coin, const std::string& string) { + const auto* hrp = stringForHRP(TW::hrp(coin)); + return TW::validateAddress(coin, string, hrp); +} + +std::string TW::normalizeAddress(TWCoinType coin, const std::string& address, const std::string& hrp) { + const char* rawHrp = hrp.empty() ? stringForHRP(TW::hrp(coin)) : hrp.c_str(); + if (!TW::validateAddress(coin, address, rawHrp)) { // invalid address, not normalizing return ""; } @@ -205,18 +210,15 @@ std::string TW::deriveAddress(TWCoinType coin, const PrivateKey& privateKey, TWD return TW::deriveAddress(coin, privateKey.getPublicKey(keyType), derivation); } -std::string TW::deriveAddress(TWCoinType coin, const PublicKey& publicKey) { - return deriveAddress(coin, publicKey, TWDerivationDefault); -} - -std::string TW::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation) { +std::string TW::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const std::string& hrp) { auto p2pkh = TW::p2pkhPrefix(coin); - const auto* hrp = stringForHRP(TW::hrp(coin)); - + const char* hrpRaw = [&hrp, coin]() { + return hrp.empty() ? stringForHRP(TW::hrp(coin)) : hrp.c_str(); + }(); // dispatch auto* dispatcher = coinDispatcher(coin); assert(dispatcher != nullptr); - return dispatcher->deriveAddress(coin, derivation, publicKey, p2pkh, hrp); + return dispatcher->deriveAddress(coin, derivation, publicKey, p2pkh, hrpRaw); } Data TW::addressToData(TWCoinType coin, const std::string& address) { diff --git a/src/Coin.h b/src/Coin.h index e18cc7b88ea..aba8e7adef5 100644 --- a/src/Coin.h +++ b/src/Coin.h @@ -32,8 +32,11 @@ std::vector getCoinTypes(); /// Validates an address for a particular coin. bool validateAddress(TWCoinType coin, const std::string& address); +/// Validates an address for a particular coin. +bool validateAddress(TWCoinType coin, const std::string& address, const char* hrp); + /// Validates and normalizes an address for a particular coin. -std::string normalizeAddress(TWCoinType coin, const std::string& address); +std::string normalizeAddress(TWCoinType coin, const std::string& address, const std::string& hrp = ""); /// Returns the blockchain for a coin type. TWBlockchain blockchain(TWCoinType coin); @@ -74,11 +77,8 @@ std::string deriveAddress(TWCoinType coin, const PrivateKey& privateKey); /// Derives the address for a particular coin from the private key, with given derivation. std::string deriveAddress(TWCoinType coin, const PrivateKey& privateKey, TWDerivation derivation); -/// Derives the address for a particular coin from the public key. -std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey); - /// Derives the address for a particular coin from the public key, with given derivation. -std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation); +std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation = TWDerivationDefault, const std::string& hrp = ""); /// Returns the binary representation of a string address Data addressToData(TWCoinType coin, const std::string& address); diff --git a/src/Cosmos/Address.h b/src/Cosmos/Address.h index f13753db89a..cb629cfa607 100644 --- a/src/Cosmos/Address.h +++ b/src/Cosmos/Address.h @@ -40,6 +40,11 @@ class Address: public Bech32Address { return Bech32Address::isValid(addr, hrp); } + /// Determines whether a string makes a valid Bech32 address with the given hrp. + static bool isValid(const std::string& addr, const std::string& hrp) { + return Bech32Address::isValid(addr, hrp); + } + /// Creates an address object from the given string, if valid. Returns success. static bool decode(const std::string& addr, Address& obj_out) { return Bech32Address::decode(addr, obj_out, ""); diff --git a/src/Cosmos/Entry.cpp b/src/Cosmos/Entry.cpp index bb8ee4698d1..6cf9026fddd 100644 --- a/src/Cosmos/Entry.cpp +++ b/src/Cosmos/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -16,11 +16,17 @@ namespace TW::Cosmos { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, [[maybe_unused]] const char* hrp) const { - return Address::isValid(coin, address); +bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char* hrp) const { + if (hrpForString(hrp) != TWHRPUnknown) { + return Address::isValid(coin, address); + } + return Address::isValid(address, hrp); } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, [[maybe_unused]] const char* hrp) const { +string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char* hrp) const { + if (!std::string(hrp).empty()) { + return Address(hrp, publicKey, coin).string(); + } return Address(coin, publicKey).string(); } diff --git a/src/interface/TWAnyAddress.cpp b/src/interface/TWAnyAddress.cpp index 57594be3847..6ad7a9fb9ce 100644 --- a/src/interface/TWAnyAddress.cpp +++ b/src/interface/TWAnyAddress.cpp @@ -21,6 +21,12 @@ bool TWAnyAddressIsValid(TWString* _Nonnull string, enum TWCoinType coin) { return TW::validateAddress(coin, address); } +bool TWAnyAddressIsValidBech32(TWString* _Nonnull string, enum TWCoinType coin, TWString* _Nonnull hrp) { + const auto& address = *reinterpret_cast(string); + const auto& hrpStr = *reinterpret_cast(hrp); + return TW::validateAddress(coin, address, hrpStr.c_str()); +} + struct TWAnyAddress* _Nullable TWAnyAddressCreateWithString(TWString* _Nonnull string, enum TWCoinType coin) { const auto& address = *reinterpret_cast(string); @@ -31,11 +37,28 @@ struct TWAnyAddress* _Nullable TWAnyAddressCreateWithString(TWString* _Nonnull s return new TWAnyAddress{impl}; } +struct TWAnyAddress* _Nullable TWAnyAddressCreateBech32(TWString* _Nonnull string, + enum TWCoinType coin, TWString* _Nonnull hrp) { + const auto& address = *reinterpret_cast(string); + const auto& hrpStr = *reinterpret_cast(hrp); + auto *impl = TW::AnyAddress::createAddress(address, coin, hrpStr); + if (impl == nullptr) { + return nullptr; + } + return new TWAnyAddress{impl}; +} + struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKey( struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin) { return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin)}; } +struct TWAnyAddress* _Nonnull TWAnyAddressCreateBech32WithPublicKey( + struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin, TWString* _Nonnull hrp) { + const auto& hrpStr = *reinterpret_cast(hrp); + return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin, hrpStr)}; +} + void TWAnyAddressDelete(struct TWAnyAddress* _Nonnull address) { delete address->impl; delete address; diff --git a/swift/Tests/Addresses/JunoAddressTests.swift b/swift/Tests/Addresses/JunoAddressTests.swift new file mode 100644 index 00000000000..02935c98c3a --- /dev/null +++ b/swift/Tests/Addresses/JunoAddressTests.swift @@ -0,0 +1,25 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import WalletCore +import XCTest + +class JunoAddressTests: XCTestCase { + func testAnyAddressValidation() { + let addr = AnyAddress(string: "juno1gckvjxau7k56f8wg8c8xj80khyp83y8x8eqc94", coin: .cosmos, hrp: "juno")!; + XCTAssertTrue(AnyAddress.isValidBech32(string: addr.description, coin: .cosmos, hrp: "juno")); + XCTAssertFalse(AnyAddress.isValidBech32(string: addr.description, coin: .bitcoin, hrp: "juno")); + XCTAssertFalse(AnyAddress.isValid(string: addr.description, coin: .bitcoin)); + XCTAssertFalse(AnyAddress.isValid(string: addr.description, coin: .cosmos)); + } + + func testAnyAddressFromPubkey() { + let data = Data(hexString: "02753f5c275e1847ba4d2fd3df36ad00af2e165650b35fe3991e9c9c46f68b12bc")!; + let pubkey = PublicKey(data: data, type: .secp256k1)!; + let anyAddr = AnyAddress(publicKey: pubkey, coin: .cosmos, hrp: "juno"); + XCTAssertEqual(anyAddr.description, "juno1cj2vfjec3c3luf9fx9vddnglhh9gawmncn4k5n"); + } +} diff --git a/tests/chains/Juno/TWAnyAddressTests.cpp b/tests/chains/Juno/TWAnyAddressTests.cpp new file mode 100644 index 00000000000..992176b9510 --- /dev/null +++ b/tests/chains/Juno/TWAnyAddressTests.cpp @@ -0,0 +1,50 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include "HexCoding.h" +#include "Hash.h" + +#include "TestUtilities.h" +#include + +using namespace TW; + +TEST(TWJunoAnyAddress, IsValid) { + EXPECT_TRUE(TWAnyAddressIsValidBech32(STRING("juno1gckvjxau7k56f8wg8c8xj80khyp83y8x8eqc94").get(), TWCoinTypeCosmos, STRING("juno").get())); + EXPECT_FALSE(TWAnyAddressIsValidBech32(STRING("juno1gckvjxau7k56f8wg8c8xj80khyp83y8x8eqc94").get(), TWCoinTypeBitcoin, STRING("juno").get())); + EXPECT_FALSE(TWAnyAddressIsValid(STRING("juno1gckvjxau7k56f8wg8c8xj80khyp83y8x8eqc94").get(), TWCoinTypeCosmos)); + EXPECT_FALSE(TWAnyAddressIsValid(STRING("juno1gckvjxau7k56f8wg8c8xj80khyp83y8x8eqc94").get(), TWCoinTypeBitcoin)); + +} + +TEST(TWJunoAnyAddress, createFromPubKeyJuno) { + const auto hrp = STRING("juno"); + const auto data = DATA("02753f5c275e1847ba4d2fd3df36ad00af2e165650b35fe3991e9c9c46f68b12bc"); + const auto pubkey = TWPublicKeyCreateWithData(data.get(), TWPublicKeyTypeSECP256k1); + const auto twAddress = TWAnyAddressCreateBech32WithPublicKey(pubkey, TWCoinTypeCosmos, hrp.get()); + auto twData = TWAnyAddressData(twAddress); + auto hexData = hex(*reinterpret_cast(twData)); + ASSERT_EQ(hexData, "c494c4cb388e23fe24a93158d6cd1fbdca8ebb73"); + ASSERT_EQ(hex(Bech32Address("juno", TW::Hash::HasherSha256ripemd, pubkey->impl).getKeyHash()), hexData); + auto address = TWAnyAddressDescription(twAddress); + EXPECT_EQ("juno1cj2vfjec3c3luf9fx9vddnglhh9gawmncn4k5n", *reinterpret_cast(address)); + TWStringDelete(address); + TWAnyAddressDelete(twAddress); + TWDataDelete(twData); + TWPublicKeyDelete(pubkey); +} + +TEST(TWJunoAnyAddress, createFromStringJuno) { + const auto junoAddress = STRING("juno1cj2vfjec3c3luf9fx9vddnglhh9gawmncn4k5n"); + const auto hrp = STRING("juno"); + const auto anyAddr = TWAnyAddressCreateBech32(junoAddress.get(), TWCoinTypeCosmos, hrp.get()); + const auto addrDescription = TWAnyAddressDescription(anyAddr); + ASSERT_TRUE(TWAnyAddressIsValidBech32(addrDescription, TWCoinTypeCosmos, hrp.get())); + TWStringDelete(addrDescription); + TWAnyAddressDelete(anyAddr); + +} From 8892ee9d3b909901783cb42761cf7b256b05d379 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 17 Oct 2022 15:52:09 +0200 Subject: [PATCH 115/497] [AnySigner] Add IBC (Juno) chain signing test (#2646) --- tests/chains/Juno/TWAnySignerTests.cpp | 56 +++++++++++++++++++++++ tests/chains/Osmosis/TWAnySignerTests.cpp | 1 - 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/chains/Juno/TWAnySignerTests.cpp diff --git a/tests/chains/Juno/TWAnySignerTests.cpp b/tests/chains/Juno/TWAnySignerTests.cpp new file mode 100644 index 00000000000..f40103c1027 --- /dev/null +++ b/tests/chains/Juno/TWAnySignerTests.cpp @@ -0,0 +1,56 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Cosmos/Address.h" +#include "HexCoding.h" +#include "proto/Cosmos.pb.h" +#include + +#include "TestUtilities.h" +#include + +namespace TW::Cosmos::tests { + +TEST(TWAnySignerJuno, Sign) { + auto privateKey = parse_hex("a498a9ee41af9bab5ef2a8be63d5c970135c3c109e70efc8c56c534e6636b433"); + Proto::SigningInput input; + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(376606); + input.set_chain_id("juno-1"); + input.set_memo(""); + input.set_sequence(0); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_send_coins_message(); + message.set_from_address("juno1mry47pkga5tdswtluy0m8teslpalkdq0gnn4mf"); + message.set_to_address("juno1mry47pkga5tdswtluy0m8teslpalkdq0gnn4mf"); + auto amountOfTx = message.add_amounts(); + amountOfTx->set_denom("ujuno"); + amountOfTx->set_amount("10000"); + + auto& fee = *input.mutable_fee(); + fee.set_gas(80000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("ujuno"); + amountOfFee->set_amount("1000"); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeCosmos); + + // https://www.mintscan.io/juno/txs/3DCE6AAF19657BCF11D44FD6BE124D57B44E04CA34851DE0ECCE619F70ECC46F + auto expectedJson = R"( + { + "mode": "BROADCAST_MODE_BLOCK", + "tx_bytes": "Co0BCooBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmoKK2p1bm8xbXJ5NDdwa2dhNXRkc3d0bHV5MG04dGVzbHBhbGtkcTBnbm40bWYSK2p1bm8xbXJ5NDdwa2dhNXRkc3d0bHV5MG04dGVzbHBhbGtkcTBnbm40bWYaDgoFdWp1bm8SBTEwMDAwEmUKTgpGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQLL/bXkcokzIilOYM8Ig9Q99DHhCJ0p7LRHqebVUEWq5RIECgIIARITCg0KBXVqdW5vEgQxMDAwEIDxBBpABrA2SUNtur1XqAIzNjM4UYtFylKARkfMd2YJUi11qqMkX0rZfmHrELL+QqjERn0o3vsR231fmPGJe4P0Isjwjw==" + })"; + assertJSONEqual(output.serialized(), expectedJson); + EXPECT_EQ(hex(output.signature()), "06b03649436dbabd57a80233363338518b45ca52804647cc776609522d75aaa3245f4ad97e61eb10b2fe42a8c4467d28defb11db7d5f98f1897b83f422c8f08f"); + EXPECT_EQ(output.json(), ""); + EXPECT_EQ(output.error(), ""); +} + +} // namespace TW::Cosmos::tests diff --git a/tests/chains/Osmosis/TWAnySignerTests.cpp b/tests/chains/Osmosis/TWAnySignerTests.cpp index 95f230551a8..64aa657c25c 100644 --- a/tests/chains/Osmosis/TWAnySignerTests.cpp +++ b/tests/chains/Osmosis/TWAnySignerTests.cpp @@ -47,7 +47,6 @@ TEST(TWAnySignerOsmosis, Sign) { ANY_SIGN(input, TWCoinTypeOsmosis); // https://www.mintscan.io/osmosis/txs/81B4F01BDE72AF7FF4536E5D7E66EB218E9FC9ACAA7C5EB5DB237DD0595D5F5F - // curl -H 'Content-Type: application/json' --data-binary '{"tx_bytes": "Co0B...rYVj", "mode": "BROADCAST_MODE_BLOCK"}' https://lcd-osmosis.keplr.app/cosmos/tx/v1beta1/txs assertJSONEqual(output.serialized(), "{\"tx_bytes\":\"Co0BCooBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmoKK29zbW8xbWt5Njljbjhla3R3eTA4NDV2ZWM5dXBzZHBoa3R4dDBlbjk3ZjUSK29zbW8xOHMwaGRuc2xsZ2NjbHdldTlheW13NG5na3RyMmswcmt2bjdqbW4aDgoFdW9zbW8SBTk5ODAwEmQKTgpGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQLs71zkN6MCxn+VRo3ksx826RH0Z9fmpStBweE+HVY2SRIECgIIARISCgwKBXVvc21vEgMyMDAQwJoMGkAMY//Md5GRUR4lVZhk558hFS3kii9QZYoYKfg4+ac/xgNeyoiEweVDhcmEvlH1orVwjLUOnYs4ly2a/yIurYVj\",\"mode\":\"BROADCAST_MODE_BLOCK\"}"); EXPECT_EQ(hex(output.signature()), "0c63ffcc779191511e25559864e79f21152de48a2f50658a1829f838f9a73fc6035eca8884c1e54385c984be51f5a2b5708cb50e9d8b38972d9aff222ead8563"); EXPECT_EQ(output.json(), ""); From f03a6be12bd4fff33d4d4bb9556acf8a61653e89 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 18 Oct 2022 08:56:03 +0200 Subject: [PATCH 116/497] feat(aptos): update aptos registry.json with mainnet values (#2658) --- registry.json | 8 ++++---- tests/chains/Aptos/TWCoinTypeTests.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/registry.json b/registry.json index d77105beebe..4de03d0c13e 100644 --- a/registry.json +++ b/registry.json @@ -419,14 +419,14 @@ "url": "https://explorer.aptoslabs.com", "txPath": "/txn/", "accountPath": "/account/", - "sampleTx": "91424546", - "sampleAccount": "0x6af7d07b8a541913dfa87a9f99628faa255c70241ef9ebd9b82a7e715ee13108" + "sampleTx": "0xedc88058e27f6c065fd6607e262cb2a83a65f74301df90c61923014c59f9d465", + "sampleAccount": "0x60ad80e8cdadb81399e8a738014bc9ec865cef842f7c2cf7d84fbf7e40d065" }, "info": { "url": "https://aptoslabs.com/", "source": "https://github.com/aptos-labs/aptos-core", - "rpc": "https://fullnode.devnet.aptoslabs.com", - "documentation": "https://fullnode.devnet.aptoslabs.com/v1/spec#/" + "rpc": "https://fullnode.mainnet.aptoslabs.com/v1", + "documentation": "https://fullnode.mainnet.aptoslabs.com/v1/spec#/" } }, { diff --git a/tests/chains/Aptos/TWCoinTypeTests.cpp b/tests/chains/Aptos/TWCoinTypeTests.cpp index af10a478945..25f89208b5d 100644 --- a/tests/chains/Aptos/TWCoinTypeTests.cpp +++ b/tests/chains/Aptos/TWCoinTypeTests.cpp @@ -18,9 +18,9 @@ TEST(TWAptosCoinType, TWCoinType) { const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); - const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("91424546")); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("0xedc88058e27f6c065fd6607e262cb2a83a65f74301df90c61923014c59f9d465")); const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); - const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0x6af7d07b8a541913dfa87a9f99628faa255c70241ef9ebd9b82a7e715ee13108")); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0x60ad80e8cdadb81399e8a738014bc9ec865cef842f7c2cf7d84fbf7e40d065")); const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); assertStringsEqual(id, "aptos"); @@ -30,6 +30,6 @@ TEST(TWAptosCoinType, TWCoinType) { ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainAptos); ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); - assertStringsEqual(txUrl, "https://explorer.aptoslabs.com/txn/91424546"); - assertStringsEqual(accUrl, "https://explorer.aptoslabs.com/account/0x6af7d07b8a541913dfa87a9f99628faa255c70241ef9ebd9b82a7e715ee13108"); + assertStringsEqual(txUrl, "https://explorer.aptoslabs.com/txn/0xedc88058e27f6c065fd6607e262cb2a83a65f74301df90c61923014c59f9d465"); + assertStringsEqual(accUrl, "https://explorer.aptoslabs.com/account/0x60ad80e8cdadb81399e8a738014bc9ec865cef842f7c2cf7d84fbf7e40d065"); } From 49877b1792b78851979ed3fa90fd8d400729464a Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Tue, 18 Oct 2022 12:21:17 +0100 Subject: [PATCH 117/497] [Fix/Codegen]: make Entry class final by default, fix include path (#2662) --- codegen/lib/templates/newcoin/Address.h.erb | 2 +- codegen/lib/templates/newcoin/Entry.h.erb | 2 +- codegen/lib/templates/newcoin/Signer.h.erb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/codegen/lib/templates/newcoin/Address.h.erb b/codegen/lib/templates/newcoin/Address.h.erb index 9c6f60df4f6..74997f6330c 100644 --- a/codegen/lib/templates/newcoin/Address.h.erb +++ b/codegen/lib/templates/newcoin/Address.h.erb @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PublicKey.h" #include diff --git a/codegen/lib/templates/newcoin/Entry.h.erb b/codegen/lib/templates/newcoin/Entry.h.erb index 1b58f5f78cd..fa115a9a30b 100644 --- a/codegen/lib/templates/newcoin/Entry.h.erb +++ b/codegen/lib/templates/newcoin/Entry.h.erb @@ -12,7 +12,7 @@ namespace TW::<%= format_name(coin) %> { /// Entry point for implementation of <%= format_name(coin) %> coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry : public CoinEntry { +class Entry final : public CoinEntry { public: virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; diff --git a/codegen/lib/templates/newcoin/Signer.h.erb b/codegen/lib/templates/newcoin/Signer.h.erb index 1261f9c6149..6be63a95699 100644 --- a/codegen/lib/templates/newcoin/Signer.h.erb +++ b/codegen/lib/templates/newcoin/Signer.h.erb @@ -6,7 +6,7 @@ #pragma once -#include "../Data.h" +#include "Data.h" #include "../PrivateKey.h" #include "../proto/<%= name %>.pb.h" From 55993e9b9418d5af30e1138455076343445e5071 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 21 Oct 2022 18:02:41 +0200 Subject: [PATCH 118/497] [PrivateKey]: add new C interface to get public key with cointype (#2661) --- .../core/app/utils/TestPrivateKey.kt | 13 +++++++---- include/TrustWalletCore/TWCoinType.h | 5 +++- include/TrustWalletCore/TWPrivateKey.h | 17 ++++++++++++++ src/interface/TWPrivateKey.cpp | 23 +++++++++++++------ .../BinanceSmartChain/TWAnyAddressTests.cpp | 1 + tests/chains/Bitcoin/MessageSignerTests.cpp | 1 + tests/chains/Evmos/TWAnyAddressTests.cpp | 1 + tests/chains/Juno/TWAnyAddressTests.cpp | 3 +++ .../chains/NativeEvmos/TWAnyAddressTests.cpp | 1 + tests/interface/TWPrivateKeyTests.cpp | 17 ++++++++++++++ 10 files changed, 69 insertions(+), 13 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPrivateKey.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPrivateKey.kt index abdbc8050ab..4b6b4908db8 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPrivateKey.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPrivateKey.kt @@ -3,11 +3,7 @@ package com.trustwallet.core.app.utils import com.trustwallet.core.app.utils.toHexBytes import org.junit.Assert.* import org.junit.Test -import wallet.core.jni.Curve -import wallet.core.jni.Hash -import wallet.core.jni.PrivateKey -import wallet.core.jni.PublicKey -import wallet.core.jni.PublicKeyType +import wallet.core.jni.* class TestPrivateKey { private val validPrivateKeyData = "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5".toHexBytes() @@ -80,6 +76,13 @@ class TestPrivateKey { assertEquals(derivedData?.toHex(), "0xef2cf705af8714b35c0855030f358f2bee356ff3579cea2607b2025d80133c3a") } + @Test + fun testGetPublicKeyCoinType() { + val privateKeyData = "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5".toHexBytes() + val privateKey = PrivateKey(privateKeyData) + assertEquals(privateKey.getPublicKey(CoinType.ETHEREUM).data().toHex(), "0x0499c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c166b489a4b7c491e7688e6ebea3a71fc3a1a48d60f98d5ce84c93b65e423fde91"); + } + @Test fun testGetSharedKeyWycherproof() { val privateKeyData = "f4b7ff7cccc98813a69fae3df222bfe3f4e28f764bf91b4a10d8096ce446b254".toHexBytes() diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 52e5f2d50f5..4ed7c86a3da 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -11,13 +11,16 @@ #include "TWCurve.h" #include "TWHDVersion.h" #include "TWHRP.h" -#include "TWPrivateKey.h" #include "TWPurpose.h" #include "TWString.h" #include "TWDerivation.h" +#include "TWPublicKeyType.h" TW_EXTERN_C_BEGIN +/// Represents a private key. +struct TWPrivateKey; + /// Coin type for Level 2 of BIP44. /// /// \see https://github.com/satoshilabs/slips/blob/master/slip-0044.md diff --git a/include/TrustWalletCore/TWPrivateKey.h b/include/TrustWalletCore/TWPrivateKey.h index ee4cf3fc7e2..d84a988d79a 100644 --- a/include/TrustWalletCore/TWPrivateKey.h +++ b/include/TrustWalletCore/TWPrivateKey.h @@ -10,6 +10,7 @@ #include "TWCurve.h" #include "TWData.h" #include "TWPublicKey.h" +#include "TWCoinType.h" TW_EXTERN_C_BEGIN @@ -63,6 +64,22 @@ bool TWPrivateKeyIsValid(TWData* _Nonnull data, enum TWCurve curve); TW_EXPORT_PROPERTY TWData* _Nonnull TWPrivateKeyData(struct TWPrivateKey* _Nonnull pk); +/// Returns the public key associated with the given coinType and privateKey +/// +/// \param pk Non-null pointer to the private key +/// \param coinType coinType of the given private key +/// \return Non-null pointer to the corresponding public key +TW_EXPORT_METHOD +struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKey(struct TWPrivateKey* _Nonnull pk, enum TWCoinType coinType); + +/// Returns the public key associated with the given pubkeyType and privateKey +/// +/// \param pk Non-null pointer to the private key +/// \param pubkeyType pubkeyType of the given private key +/// \return Non-null pointer to the corresponding public key +TW_EXPORT_METHOD +struct TWPublicKey* _Nonnull TWPrivateKeyGetPublicKeyByType(struct TWPrivateKey* _Nonnull pk, enum TWPublicKeyType pubkeyType); + /// Returns the Secp256k1 public key associated with the given private key /// /// \param pk Non-null pointer to the private key diff --git a/src/interface/TWPrivateKey.cpp b/src/interface/TWPrivateKey.cpp index ab91378d9ca..08e9eb49490 100644 --- a/src/interface/TWPrivateKey.cpp +++ b/src/interface/TWPrivateKey.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -62,31 +63,31 @@ TWData *TWPrivateKeyData(struct TWPrivateKey *_Nonnull pk) { } struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyNist256p1(struct TWPrivateKey *_Nonnull pk) { - return new TWPublicKey{ pk->impl.getPublicKey(TWPublicKeyTypeNIST256p1) }; + return TWPrivateKeyGetPublicKeyByType(pk, TWPublicKeyTypeNIST256p1); } struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeySecp256k1(struct TWPrivateKey *_Nonnull pk, bool compressed) { if (compressed) { - return new TWPublicKey{ pk->impl.getPublicKey(TWPublicKeyTypeSECP256k1) }; + return TWPrivateKeyGetPublicKeyByType(pk, TWPublicKeyTypeSECP256k1); } else { - return new TWPublicKey{ pk->impl.getPublicKey(TWPublicKeyTypeSECP256k1Extended) }; + return TWPrivateKeyGetPublicKeyByType(pk, TWPublicKeyTypeSECP256k1Extended); } } struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519(struct TWPrivateKey *_Nonnull pk) { - return new TWPublicKey{ pk->impl.getPublicKey(TWPublicKeyTypeED25519) }; + return TWPrivateKeyGetPublicKeyByType(pk, TWPublicKeyTypeED25519); } struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519Blake2b(struct TWPrivateKey *_Nonnull pk) { - return new TWPublicKey{ pk->impl.getPublicKey(TWPublicKeyTypeED25519Blake2b) }; + return TWPrivateKeyGetPublicKeyByType(pk, TWPublicKeyTypeED25519Blake2b); } struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyEd25519Cardano(struct TWPrivateKey *_Nonnull pk) { - return new TWPublicKey{ pk->impl.getPublicKey(TWPublicKeyTypeED25519Cardano) }; + return TWPrivateKeyGetPublicKeyByType(pk, TWPublicKeyTypeED25519Cardano); } struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyCurve25519(struct TWPrivateKey *_Nonnull pk) { - return new TWPublicKey{pk->impl.getPublicKey(TWPublicKeyTypeCURVE25519)}; + return TWPrivateKeyGetPublicKeyByType(pk, TWPublicKeyTypeCURVE25519); } TWData *_Nullable TWPrivateKeyGetSharedKey(const struct TWPrivateKey *_Nonnull pk, const struct TWPublicKey *_Nonnull publicKey, enum TWCurve curve) { @@ -128,3 +129,11 @@ TWData *TWPrivateKeySignZilliqaSchnorr(struct TWPrivateKey *_Nonnull pk, TWData return TWDataCreateWithBytes(result.data(), result.size()); } } + +struct TWPublicKey* TWPrivateKeyGetPublicKey(struct TWPrivateKey* pk, enum TWCoinType coinType) { + return TWPrivateKeyGetPublicKeyByType(pk, TWCoinTypePublicKeyType(coinType)); +} + +struct TWPublicKey* TWPrivateKeyGetPublicKeyByType(struct TWPrivateKey* pk, enum TWPublicKeyType pubkeyType) { + return new TWPublicKey{ pk->impl.getPublicKey(pubkeyType) }; +} diff --git a/tests/chains/BinanceSmartChain/TWAnyAddressTests.cpp b/tests/chains/BinanceSmartChain/TWAnyAddressTests.cpp index f7769d5c198..747f722a61e 100644 --- a/tests/chains/BinanceSmartChain/TWAnyAddressTests.cpp +++ b/tests/chains/BinanceSmartChain/TWAnyAddressTests.cpp @@ -5,6 +5,7 @@ // file LICENSE at the root of the source code distribution tree. #include +#include #include "HexCoding.h" #include "TestUtilities.h" diff --git a/tests/chains/Bitcoin/MessageSignerTests.cpp b/tests/chains/Bitcoin/MessageSignerTests.cpp index 5ec7d6d361a..df617721300 100644 --- a/tests/chains/Bitcoin/MessageSignerTests.cpp +++ b/tests/chains/Bitcoin/MessageSignerTests.cpp @@ -13,6 +13,7 @@ #include "Base64.h" #include "Coin.h" #include "Data.h" +#include "TestUtilities.h" #include #include diff --git a/tests/chains/Evmos/TWAnyAddressTests.cpp b/tests/chains/Evmos/TWAnyAddressTests.cpp index de3468d4cce..63b9462654a 100644 --- a/tests/chains/Evmos/TWAnyAddressTests.cpp +++ b/tests/chains/Evmos/TWAnyAddressTests.cpp @@ -8,6 +8,7 @@ #include #include +#include #include diff --git a/tests/chains/Juno/TWAnyAddressTests.cpp b/tests/chains/Juno/TWAnyAddressTests.cpp index 992176b9510..2eddab2c3c7 100644 --- a/tests/chains/Juno/TWAnyAddressTests.cpp +++ b/tests/chains/Juno/TWAnyAddressTests.cpp @@ -5,6 +5,9 @@ // file LICENSE at the root of the source code distribution tree. #include +#include +#include "PublicKey.h" +#include "Bech32Address.h" #include "HexCoding.h" #include "Hash.h" diff --git a/tests/chains/NativeEvmos/TWAnyAddressTests.cpp b/tests/chains/NativeEvmos/TWAnyAddressTests.cpp index ed2a02cd50f..cb76b9cc310 100644 --- a/tests/chains/NativeEvmos/TWAnyAddressTests.cpp +++ b/tests/chains/NativeEvmos/TWAnyAddressTests.cpp @@ -7,6 +7,7 @@ #include "TestUtilities.h" #include +#include #include #include diff --git a/tests/interface/TWPrivateKeyTests.cpp b/tests/interface/TWPrivateKeyTests.cpp index 2ce9d6be10c..fd9787e2732 100644 --- a/tests/interface/TWPrivateKeyTests.cpp +++ b/tests/interface/TWPrivateKeyTests.cpp @@ -83,6 +83,23 @@ TEST(TWPrivateKeyTests, PublicKey) { const auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyCurve25519(privateKey.get())); ASSERT_EQ(TW::hex(publicKey.get()->impl.bytes), "686cfce9108566dd43fc6aa75e31f9a9f319c9e9c04d6ad0a52505b86bc17c3a"); } + { + const auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKey(privateKey.get(), TWCoinTypeEthereum)); + ASSERT_EQ(TW::hex(publicKey.get()->impl.bytes), "0499c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c166b489a4b7c491e7688e6ebea3a71fc3a1a48d60f98d5ce84c93b65e423fde91"); + + auto pubkeyType = TWCoinTypePublicKeyType(TWCoinTypeEthereum); + const auto publicKeyByType = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyByType(privateKey.get(), pubkeyType)); + + ASSERT_EQ(TW::hex(publicKey.get()->impl.bytes), TW::hex(publicKeyByType.get()->impl.bytes)); + } + { + const auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKey(privateKey.get(), TWCoinTypeNEO)); + ASSERT_EQ(TW::hex(publicKey.get()->impl.bytes), "026d786ab8fda678cf50f71d13641049a393b325063b8c0d4e5070de48a2caf9ab"); + } + { + const auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKey(privateKey.get(), TWCoinTypeWaves)); + ASSERT_EQ(TW::hex(publicKey.get()->impl.bytes), "686cfce9108566dd43fc6aa75e31f9a9f319c9e9c04d6ad0a52505b86bc17c3a"); + } } TEST(TWPrivateKeyTests, GetSharedKey) { From 9a5a44361eb4fb5c556a8ca8665b541751abf83f Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 25 Oct 2022 06:33:16 +0200 Subject: [PATCH 119/497] [Polkadot]: Runtime network id for polkadot (#2663) --- .../blockchains/kusama/TestKusamaSigner.kt | 2 +- .../polkadot/TestPolkadotSigner.kt | 6 +- codegen/lib/templates/CoinInfoData.cpp.erb | 2 + codegen/lib/templates/newcoin/Entry.cpp.erb | 2 +- include/TrustWalletCore/TWAnyAddress.h | 27 ++++++++ include/TrustWalletCore/TWCoinType.h | 7 ++ registry.json | 2 + src/Aeternity/Entry.cpp | 2 +- src/Aeternity/Entry.h | 2 +- src/Aion/Entry.cpp | 2 +- src/Aion/Entry.h | 2 +- src/Algorand/Entry.cpp | 2 +- src/Algorand/Entry.h | 2 +- src/AnyAddress.cpp | 12 +++- src/AnyAddress.h | 4 +- src/Aptos/Entry.cpp | 2 +- src/Aptos/Entry.h | 2 +- src/Binance/Entry.cpp | 2 +- src/Binance/Entry.h | 2 +- src/Bitcoin/Entry.cpp | 21 +++--- src/Bitcoin/Entry.h | 3 +- src/Cardano/Entry.cpp | 2 +- src/Cardano/Entry.h | 2 +- src/Coin.cpp | 64 +++++++++++++++---- src/Coin.h | 11 +++- src/CoinEntry.h | 16 ++++- src/Cosmos/Entry.cpp | 11 ++-- src/Cosmos/Entry.h | 2 +- src/Decred/Entry.cpp | 2 +- src/Decred/Entry.h | 10 +-- src/EOS/Entry.cpp | 2 +- src/EOS/Entry.h | 6 +- src/Elrond/Entry.cpp | 2 +- src/Elrond/Entry.h | 14 ++-- src/Ethereum/Entry.cpp | 2 +- src/Ethereum/Entry.h | 2 +- src/Everscale/Entry.cpp | 2 +- src/Everscale/Entry.h | 2 +- src/FIO/Entry.cpp | 2 +- src/FIO/Entry.h | 2 +- src/Filecoin/Entry.cpp | 3 +- src/Filecoin/Entry.h | 3 +- src/Groestlcoin/Entry.cpp | 7 +- src/Groestlcoin/Entry.h | 2 +- src/Harmony/Entry.cpp | 2 +- src/Harmony/Entry.h | 2 +- src/Icon/Address.cpp | 8 +-- src/Icon/Entry.cpp | 2 +- src/Icon/Entry.h | 2 +- src/IoTeX/Entry.cpp | 2 +- src/IoTeX/Entry.h | 2 +- src/Kusama/Entry.cpp | 2 +- src/Kusama/Entry.h | 2 +- src/NEAR/Entry.cpp | 2 +- src/NEAR/Entry.h | 2 +- src/NEO/Entry.cpp | 2 +- src/NEO/Entry.h | 2 +- src/NULS/Entry.cpp | 2 +- src/NULS/Entry.h | 2 +- src/Nano/Entry.cpp | 2 +- src/Nano/Entry.h | 2 +- src/Nebulas/Entry.cpp | 2 +- src/Nebulas/Entry.h | 2 +- src/Nervos/Entry.cpp | 6 +- src/Nervos/Entry.h | 3 +- src/Nimiq/Entry.cpp | 2 +- src/Nimiq/Entry.h | 2 +- src/Oasis/Entry.cpp | 2 +- src/Oasis/Entry.h | 2 +- src/Ontology/Entry.cpp | 2 +- src/Ontology/Entry.h | 2 +- src/Polkadot/Address.h | 7 +- src/Polkadot/Entry.cpp | 12 +++- src/Polkadot/Entry.h | 9 +-- src/Polkadot/SS58Address.cpp | 2 +- src/Polkadot/SS58Address.h | 2 +- src/Ronin/Entry.cpp | 2 +- src/Ronin/Entry.h | 2 +- src/Solana/Entry.cpp | 2 +- src/Solana/Entry.h | 2 +- src/Stellar/Entry.cpp | 2 +- src/Stellar/Entry.h | 2 +- src/Tezos/Entry.cpp | 2 +- src/Tezos/Entry.h | 2 +- src/Tron/Entry.cpp | 2 +- src/Tron/Entry.h | 2 +- src/Waves/Entry.cpp | 2 +- src/Waves/Entry.h | 2 +- src/XRP/Entry.cpp | 2 +- src/XRP/Entry.h | 2 +- src/Zcash/Entry.cpp | 2 +- src/Zcash/Entry.h | 2 +- src/Zilliqa/Entry.cpp | 2 +- src/Zilliqa/Entry.h | 2 +- src/interface/TWAnyAddress.cpp | 21 +++++- src/interface/TWCoinType.cpp | 4 ++ src/proto/Polkadot.proto | 8 +-- swift/Tests/Blockchains/KusamaTests.swift | 2 +- swift/Tests/Blockchains/PolkadotTests.swift | 10 +-- tests/chains/Acala/TWAnyAddressTests.cpp | 49 ++++++++++++++ tests/chains/Juno/TWAnyAddressTests.cpp | 2 + tests/chains/Kusama/SignerTests.cpp | 3 +- tests/chains/Kusama/TWAnySignerTests.cpp | 2 +- tests/chains/Polkadot/SignerTests.cpp | 25 ++++---- 104 files changed, 367 insertions(+), 171 deletions(-) create mode 100644 tests/chains/Acala/TWAnyAddressTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kusama/TestKusamaSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kusama/TestKusamaSigner.kt index 738ff2a4c1f..388a38bd150 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kusama/TestKusamaSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/kusama/TestKusamaSigner.kt @@ -36,7 +36,7 @@ class TestKusamaSigner { blockHash = hash nonce = 1 specVersion = 2019 - network = Polkadot.Network.KUSAMA + network = KUSAMA.ss58Prefix() transactionVersion = 2 privateKey = key balanceCall = Polkadot.Balance.newBuilder().apply { diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotSigner.kt index 2e5a09f2885..9da312ca3ea 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotSigner.kt @@ -39,7 +39,7 @@ class TestPolkadotSigner { blockHash = genesisHashStr nonce = 0 specVersion = 17 - network = Polkadot.Network.POLKADOT + network = POLKADOT.ss58Prefix() transactionVersion = 3 privateKey = key stakingCall = Polkadot.Staking.newBuilder().apply { @@ -69,7 +69,7 @@ class TestPolkadotSigner { blockHash = genesisHashStr nonce = 4 specVersion = 30 - network = Polkadot.Network.POLKADOT + network = POLKADOT.ss58Prefix() transactionVersion = 7 privateKey = iOSTestKey stakingCall = Polkadot.Staking.newBuilder().apply { @@ -96,7 +96,7 @@ class TestPolkadotSigner { blockHash = "0x35ba668bb19453e8da6334cadcef2a27c8d4141bfc8b49e78e853c3d73e1ecd0".toHexBytesInByteString() nonce = 6 specVersion = 9200 - network = Polkadot.Network.POLKADOT + network = POLKADOT.ss58Prefix() transactionVersion = 12 privateKey = "298fcced2b497ed48367261d8340f647b3fca2d9415d57c2e3c5ef90482a2266".toHexBytesInByteString() era = Polkadot.Era.newBuilder().apply { diff --git a/codegen/lib/templates/CoinInfoData.cpp.erb b/codegen/lib/templates/CoinInfoData.cpp.erb index 44dd8acd044..78aed10c204 100644 --- a/codegen/lib/templates/CoinInfoData.cpp.erb +++ b/codegen/lib/templates/CoinInfoData.cpp.erb @@ -36,6 +36,7 @@ static const CoinInfo defaultsForMissing = { "", "", 0, + 0 }; /// Get coin from map, if missing returns defaults (not to have contains-check in each accessor method) @@ -73,6 +74,7 @@ const CoinInfo getCoinInfo(TWCoinType coin) { "<%= explorer_tx_url(coin) %>", "<%= explorer_account_url(coin) %>", <% if coin['slip44'].nil? -%><%= coin['coinId'] %><% else -%><%= coin['slip44'] %><% end -%>, + <% if coin['ss58Prefix'].nil? -%>0<% else -%><%= coin['ss58Prefix'] %><% end -%>, }; <% end -%> default: diff --git a/codegen/lib/templates/newcoin/Entry.cpp.erb b/codegen/lib/templates/newcoin/Entry.cpp.erb index d0585ed64b9..a29ceb91951 100644 --- a/codegen/lib/templates/newcoin/Entry.cpp.erb +++ b/codegen/lib/templates/newcoin/Entry.cpp.erb @@ -13,7 +13,7 @@ namespace TW::<%= format_name(coin) %> { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress(TWCoinType coin, [[maybe_unused]] const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/include/TrustWalletCore/TWAnyAddress.h b/include/TrustWalletCore/TWAnyAddress.h index 449d518ba2c..86dcdc51bd9 100644 --- a/include/TrustWalletCore/TWAnyAddress.h +++ b/include/TrustWalletCore/TWAnyAddress.h @@ -44,6 +44,15 @@ bool TWAnyAddressIsValid(TWString* _Nonnull string, enum TWCoinType coin); TW_EXPORT_STATIC_METHOD bool TWAnyAddressIsValidBech32(TWString* _Nonnull string, enum TWCoinType coin, TWString* _Nonnull hrp); +/// Determines if the string is a valid Any address with the given SS58 network prefix. +/// +/// \param string address to validate. +/// \param coin coin type of the address. +/// \param ss58Prefix ss58Prefix of the given address. +/// \return bool indicating if the address is valid. +TW_EXPORT_STATIC_METHOD +bool TWAnyAddressIsValidSS58(TWString* _Nonnull string, enum TWCoinType coin, uint32_t ss58Prefix); + /// Creates an address from a string representation and a coin type. Must be deleted with TWAnyAddressDelete after use. /// /// \param string address to create. @@ -61,6 +70,15 @@ struct TWAnyAddress* _Nullable TWAnyAddressCreateWithString(TWString* _Nonnull s TW_EXPORT_STATIC_METHOD struct TWAnyAddress* _Nullable TWAnyAddressCreateBech32(TWString* _Nonnull string, enum TWCoinType coin, TWString* _Nonnull hrp); +/// Creates an SS58 address from a string representation, a coin type and the given ss58Prefix. Must be deleted with TWAnyAddressDelete after use. +/// +/// \param string address to create. +/// \param coin coin type of the address. +/// \param ss58Prefix ss58Prefix of the SS58 address. +/// \return TWAnyAddress pointer or nullptr if address and coin are invalid. +TW_EXPORT_STATIC_METHOD +struct TWAnyAddress* _Nullable TWAnyAddressCreateSS58(TWString* _Nonnull string, enum TWCoinType coin, uint32_t ss58Prefix); + /// Creates an address from a public key. /// @@ -79,6 +97,15 @@ struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKey(struct TWPublicKey TW_EXPORT_STATIC_METHOD struct TWAnyAddress* _Nonnull TWAnyAddressCreateBech32WithPublicKey(struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin, TWString* _Nonnull hrp); +/// Creates an SS58 address from a public key and a given ss58Prefix. +/// +/// \param publicKey derivates the address from the public key. +/// \param coin coin type of the address. +/// \param ss58Prefix ss58Prefix of the SS58 address. +/// \return TWAnyAddress pointer or nullptr if public key is invalid. +TW_EXPORT_STATIC_METHOD +struct TWAnyAddress* _Nonnull TWAnyAddressCreateSS58WithPublicKey(struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin, uint32_t ss58Prefix); + /// Deletes an address. /// /// \param address address to delete. diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 4ed7c86a3da..4c009702001 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -242,6 +242,13 @@ TWString* _Nonnull TWCoinTypeChainId(enum TWCoinType coin); TW_EXPORT_PROPERTY uint32_t TWCoinTypeSlip44Id(enum TWCoinType coin); +/// SS58Prefix for this coin type +/// +/// \param coin A coin type +/// \return SS58Prefix for the given coin type +TW_EXPORT_PROPERTY +uint32_t TWCoinTypeSS58Prefix(enum TWCoinType coin); + /// public key type for this coin type /// /// \param coin A coin type diff --git a/registry.json b/registry.json index 4de03d0c13e..96dedfb41e8 100644 --- a/registry.json +++ b/registry.json @@ -1022,6 +1022,7 @@ "curve": "ed25519", "publicKeyType": "ed25519", "addressHasher": "keccak256", + "ss58Prefix": 0, "explorer": { "url": "https://polkadot.subscan.io", "txPath": "/extrinsic/", @@ -1129,6 +1130,7 @@ "curve": "ed25519", "publicKeyType": "ed25519", "addressHasher": "keccak256", + "ss58Prefix": 2, "explorer": { "url": "https://kusama.subscan.io", "txPath": "/extrinsic/", diff --git a/src/Aeternity/Entry.cpp b/src/Aeternity/Entry.cpp index cab15ca9d26..0c1fcc95dce 100644 --- a/src/Aeternity/Entry.cpp +++ b/src/Aeternity/Entry.cpp @@ -14,7 +14,7 @@ using namespace std; namespace TW::Aeternity { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Aeternity/Entry.h b/src/Aeternity/Entry.h index b344b0ebb1f..211ffd707c2 100644 --- a/src/Aeternity/Entry.h +++ b/src/Aeternity/Entry.h @@ -14,7 +14,7 @@ namespace TW::Aeternity { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Aion/Entry.cpp b/src/Aion/Entry.cpp index f32ef1e3491..922e368f611 100644 --- a/src/Aion/Entry.cpp +++ b/src/Aion/Entry.cpp @@ -16,7 +16,7 @@ namespace TW::Aion { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Aion/Entry.h b/src/Aion/Entry.h index 1ff2ed22dc1..551016bc95c 100644 --- a/src/Aion/Entry.h +++ b/src/Aion/Entry.h @@ -14,7 +14,7 @@ namespace TW::Aion { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Algorand/Entry.cpp b/src/Algorand/Entry.cpp index 2f090b1ca5b..135434fc5cc 100644 --- a/src/Algorand/Entry.cpp +++ b/src/Algorand/Entry.cpp @@ -13,7 +13,7 @@ namespace TW::Algorand { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Algorand/Entry.h b/src/Algorand/Entry.h index a2e2548839b..7fa4a1f91a3 100644 --- a/src/Algorand/Entry.h +++ b/src/Algorand/Entry.h @@ -14,7 +14,7 @@ namespace TW::Algorand { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; bool supportsJSONSigning() const { return true; } diff --git a/src/AnyAddress.cpp b/src/AnyAddress.cpp index 9bb265cc041..be44ccb2e95 100644 --- a/src/AnyAddress.cpp +++ b/src/AnyAddress.cpp @@ -15,8 +15,9 @@ Data AnyAddress::getData() const { return TW::addressToData(coin, address); } -AnyAddress* AnyAddress::createAddress(const std::string& address, enum TWCoinType coin, const std::string& hrp) { - auto normalized = TW::normalizeAddress(coin, address, hrp); +AnyAddress* AnyAddress::createAddress(const std::string& address, enum TWCoinType coin, const PrefixVariant& prefix) { + const bool hasPrefix = !std::holds_alternative(prefix); + auto normalized = hasPrefix ? TW::normalizeAddress(coin, address, prefix) : TW::normalizeAddress(coin, address); if (normalized.empty()) { return nullptr; } @@ -25,8 +26,15 @@ AnyAddress* AnyAddress::createAddress(const std::string& address, enum TWCoinTyp } AnyAddress* AnyAddress::createAddress(const PublicKey& publicKey, enum TWCoinType coin, const std::string& hrp) { + auto derivedAddress = TW::deriveAddress(coin, publicKey, TWDerivationDefault, hrp); return new AnyAddress{.address = std::move(derivedAddress), .coin = coin}; } +AnyAddress* AnyAddress::createAddress(const PublicKey& publicKey, enum TWCoinType coin, const PrefixVariant& addressPrefix) { + + auto derivedAddress = TW::deriveAddress(coin, publicKey, addressPrefix); + return new AnyAddress{.address = std::move(derivedAddress), .coin = coin}; +} + } // namespace TW diff --git a/src/AnyAddress.h b/src/AnyAddress.h index 7bf773eaf07..a40be466a8e 100644 --- a/src/AnyAddress.h +++ b/src/AnyAddress.h @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace TW { @@ -22,8 +23,9 @@ class AnyAddress { enum TWCoinType coin; - static AnyAddress* createAddress(const std::string& address, enum TWCoinType coin, const std::string& hrp = ""); + static AnyAddress* createAddress(const std::string& address, enum TWCoinType coin, const PrefixVariant& prefix = std::monostate()); static AnyAddress* createAddress(const PublicKey& publicKey, enum TWCoinType coin, const std::string& hrp = ""); + static AnyAddress* createAddress(const PublicKey& publicKey, enum TWCoinType coin, const PrefixVariant& prefix); Data getData() const; }; diff --git a/src/Aptos/Entry.cpp b/src/Aptos/Entry.cpp index 4c299f946a2..44261fc64ac 100644 --- a/src/Aptos/Entry.cpp +++ b/src/Aptos/Entry.cpp @@ -11,7 +11,7 @@ namespace TW::Aptos { -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Aptos/Entry.h b/src/Aptos/Entry.h index 0fd1ab1d008..3496e72e8ac 100644 --- a/src/Aptos/Entry.h +++ b/src/Aptos/Entry.h @@ -14,7 +14,7 @@ namespace TW::Aptos { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Binance/Entry.cpp b/src/Binance/Entry.cpp index 48d39fc64c2..a92d97c4a2d 100644 --- a/src/Binance/Entry.cpp +++ b/src/Binance/Entry.cpp @@ -12,7 +12,7 @@ namespace TW::Binance { -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Binance/Entry.h b/src/Binance/Entry.h index da927b68166..ee8cd5b158b 100644 --- a/src/Binance/Entry.h +++ b/src/Binance/Entry.h @@ -14,7 +14,7 @@ namespace TW::Binance { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Bitcoin/Entry.cpp b/src/Bitcoin/Entry.cpp index 36ee93a94f6..861e239c61e 100644 --- a/src/Bitcoin/Entry.cpp +++ b/src/Bitcoin/Entry.cpp @@ -13,8 +13,12 @@ namespace TW::Bitcoin { -bool Entry::validateAddress(TWCoinType coin, const std::string& address, byte p2pkh, byte p2sh, - const char* hrp) const { +bool Entry::validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const { + auto* base58Prefix = std::get_if(&addressPrefix); + auto* hrp = std::get_if(&addressPrefix); + bool isValidBase58 = base58Prefix ? Address::isValid(address, {{base58Prefix->p2pkh}, {base58Prefix->p2sh}}) : false; + bool isValidHrp = hrp ? SegwitAddress::isValid(address, *hrp) : false; + switch (coin) { case TWCoinTypeBitcoin: case TWCoinTypeDigiByte: @@ -23,20 +27,17 @@ bool Entry::validateAddress(TWCoinType coin, const std::string& address, byte p2 case TWCoinTypeQtum: case TWCoinTypeViacoin: case TWCoinTypeBitcoinGold: - return SegwitAddress::isValid(address, hrp) || Address::isValid(address, {{p2pkh}, {p2sh}}); - + return isValidBase58 || isValidHrp; case TWCoinTypeBitcoinCash: - return BitcoinCashAddress::isValid(address) || Address::isValid(address, {{p2pkh}, {p2sh}}); - + return base58Prefix ? isValidBase58 : BitcoinCashAddress::isValid(address); case TWCoinTypeECash: - return ECashAddress::isValid(address) || Address::isValid(address, {{p2pkh}, {p2sh}}); - + return base58Prefix ? isValidBase58 : ECashAddress::isValid(address); case TWCoinTypeDash: case TWCoinTypeDogecoin: case TWCoinTypeRavencoin: case TWCoinTypeFiro: default: - return Address::isValid(address, {{p2pkh}, {p2sh}}); + return isValidBase58; } } @@ -63,7 +64,7 @@ std::string Entry::normalizeAddress(TWCoinType coin, const std::string& address) } std::string Entry::deriveAddress(TWCoinType coin, TWDerivation derivation, const PublicKey& publicKey, - byte p2pkh, const char* hrp) const { + byte p2pkh, const char* hrp) const { switch (coin) { case TWCoinTypeBitcoin: case TWCoinTypeLitecoin: diff --git a/src/Bitcoin/Entry.h b/src/Bitcoin/Entry.h index 713f97685d2..aec706f5d5f 100644 --- a/src/Bitcoin/Entry.h +++ b/src/Bitcoin/Entry.h @@ -15,8 +15,7 @@ namespace TW::Bitcoin { /// includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, - const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string normalizeAddress(TWCoinType coin, const std::string& address) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const { diff --git a/src/Cardano/Entry.cpp b/src/Cardano/Entry.cpp index 154b44ac407..2bf09dde28d 100644 --- a/src/Cardano/Entry.cpp +++ b/src/Cardano/Entry.cpp @@ -13,7 +13,7 @@ namespace TW::Cardano { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return AddressV3::isValidLegacy(address); } diff --git a/src/Cardano/Entry.h b/src/Cardano/Entry.h index 94766b32303..7cac8650256 100644 --- a/src/Cardano/Entry.h +++ b/src/Cardano/Entry.h @@ -14,7 +14,7 @@ namespace TW::Cardano { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Coin.cpp b/src/Coin.cpp index efe10e47e56..9b88d7eb252 100644 --- a/src/Coin.cpp +++ b/src/Coin.cpp @@ -173,32 +173,62 @@ const Derivation CoinInfo::derivationByName(TWDerivation nameIn) const { return Derivation(); } -bool TW::validateAddress(TWCoinType coin, const std::string& string, const char* hrp) { +bool TW::validateAddress(TWCoinType coin, const string& address, const PrefixVariant& prefix) { + // dispatch + auto* dispatcher = coinDispatcher(coin); + assert(dispatcher != nullptr); + return dispatcher->validateAddress(coin, address, prefix); +} + +bool TW::validateAddress(TWCoinType coin, const std::string& string) { + const auto* hrp = stringForHRP(TW::hrp(coin)); auto p2pkh = TW::p2pkhPrefix(coin); auto p2sh = TW::p2shPrefix(coin); // dispatch auto* dispatcher = coinDispatcher(coin); assert(dispatcher != nullptr); - return dispatcher->validateAddress(coin, string, p2pkh, p2sh, hrp); + bool isValid = false; + // First check HRP. + if (hrp != nullptr && !std::string(hrp).empty()) { + isValid = dispatcher->validateAddress(coin, string, Bech32Prefix(hrp)); + } + // Then check UTXO + if ((p2pkh != 0 || p2sh != 0) && !isValid) { + return isValid || dispatcher->validateAddress(coin, string, Base58Prefix{.p2pkh = p2pkh, .p2sh = p2sh}); + } + // Then check normal + if (!isValid) { + isValid = dispatcher->validateAddress(coin, string, std::monostate()); + } + return isValid; } -bool TW::validateAddress(TWCoinType coin, const std::string& string) { - const auto* hrp = stringForHRP(TW::hrp(coin)); - return TW::validateAddress(coin, string, hrp); +namespace TW::internal { + inline std::string normalizeAddress(TWCoinType coin, const string& address) { + // dispatch + auto* dispatcher = coinDispatcher(coin); + assert(dispatcher != nullptr); + return dispatcher->normalizeAddress(coin, address); + } } -std::string TW::normalizeAddress(TWCoinType coin, const std::string& address, const std::string& hrp) { - const char* rawHrp = hrp.empty() ? stringForHRP(TW::hrp(coin)) : hrp.c_str(); - if (!TW::validateAddress(coin, address, rawHrp)) { +std::string TW::normalizeAddress(TWCoinType coin, const string& address) {; + if (!TW::validateAddress(coin, address)) { // invalid address, not normalizing return ""; } - // dispatch - auto* dispatcher = coinDispatcher(coin); - assert(dispatcher != nullptr); - return dispatcher->normalizeAddress(coin, address); + return internal::normalizeAddress(coin, address); +} + +std::string TW::normalizeAddress(TWCoinType coin, const std::string& address, const PrefixVariant& prefix) { + if (!TW::validateAddress(coin, address, prefix)) { + // invalid address, not normalizing + return ""; + } + + return internal::normalizeAddress(coin, address); } std::string TW::deriveAddress(TWCoinType coin, const PrivateKey& privateKey) { @@ -210,6 +240,12 @@ std::string TW::deriveAddress(TWCoinType coin, const PrivateKey& privateKey, TWD return TW::deriveAddress(coin, privateKey.getPublicKey(keyType), derivation); } +std::string TW::deriveAddress(TWCoinType coin, const PublicKey& publicKey, const PrefixVariant& addressPrefix, TWDerivation derivation) { + auto const* dispatcher = coinDispatcher(coin); + assert(dispatcher != nullptr); + return dispatcher->deriveAddress(coin, publicKey, derivation, addressPrefix); +} + std::string TW::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const std::string& hrp) { auto p2pkh = TW::p2pkhPrefix(coin); const char* hrpRaw = [&hrp, coin]() { @@ -353,6 +389,10 @@ uint32_t TW::slip44Id(TWCoinType coin) { return getCoinInfo(coin).slip44; } +std::uint32_t TW::ss58Prefix(TWCoinType coin) { + return getCoinInfo(coin).ss58Prefix; +} + TWString* _Nullable TWCoinTypeConfigurationGetSymbol(enum TWCoinType coin) { return TWStringCreateWithUTF8Bytes(getCoinInfo(coin).symbol); } diff --git a/src/Coin.h b/src/Coin.h index aba8e7adef5..3a994267d1b 100644 --- a/src/Coin.h +++ b/src/Coin.h @@ -33,10 +33,11 @@ std::vector getCoinTypes(); bool validateAddress(TWCoinType coin, const std::string& address); /// Validates an address for a particular coin. -bool validateAddress(TWCoinType coin, const std::string& address, const char* hrp); +bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& prefix); /// Validates and normalizes an address for a particular coin. -std::string normalizeAddress(TWCoinType coin, const std::string& address, const std::string& hrp = ""); +std::string normalizeAddress(TWCoinType coin, const std::string& address); +std::string normalizeAddress(TWCoinType coin, const std::string& address, const PrefixVariant& prefix); /// Returns the blockchain for a coin type. TWBlockchain blockchain(TWCoinType coin); @@ -79,6 +80,8 @@ std::string deriveAddress(TWCoinType coin, const PrivateKey& privateKey, TWDeriv /// Derives the address for a particular coin from the public key, with given derivation. std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation = TWDerivationDefault, const std::string& hrp = ""); +/// Derives the address for a particular coin from the public key, with given derivation and explicit addressPrefix. +std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, const PrefixVariant& addressPrefix, TWDerivation derivation = TWDerivationDefault); /// Returns the binary representation of a string address Data addressToData(TWCoinType coin, const std::string& address); @@ -104,6 +107,9 @@ byte p2shPrefix(TWCoinType coin); /// Returns human readable part for a coin type. enum TWHRP hrp(TWCoinType coin); +/// Returns the ss58 prefix of a coin type. +std::uint32_t ss58Prefix(TWCoinType coin); + /// Returns chain ID. const char* chainId(TWCoinType coin); @@ -155,6 +161,7 @@ struct CoinInfo { const char* explorerTransactionUrl; const char* explorerAccountUrl; uint32_t slip44; + std::uint32_t ss58Prefix; // returns default derivation const Derivation defaultDerivation() const { diff --git a/src/CoinEntry.h b/src/CoinEntry.h index b0ab4bd72d3..99a56942ff8 100644 --- a/src/CoinEntry.h +++ b/src/CoinEntry.h @@ -17,22 +17,36 @@ #include #include +#include #include namespace TW { typedef std::vector> HashPubkeyList; +struct Base58Prefix { + TW::byte p2pkh; + TW::byte p2sh; +}; + +using Bech32Prefix = const char *; +using SS58Prefix = uint32_t; + +using PrefixVariant = std::variant; + /// Interface for coin-specific entry, used to dispatch calls to coins /// Implement this for all coins. class CoinEntry { public: virtual ~CoinEntry() noexcept = default; - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const = 0; + virtual bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const = 0; // normalizeAddress is optional, it may leave this default, no-change implementation virtual std::string normalizeAddress([[maybe_unused]] TWCoinType coin, const std::string& address) const { return address; } // Address derivation, default derivation virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const = 0; + virtual std::string deriveAddress([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { + return ""; + }; // Address derivation, by default invoking default virtual std::string deriveAddress(TWCoinType coin, [[maybe_unused]] TWDerivation derivation, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const { return deriveAddress(coin, publicKey, p2pkh, hrp); diff --git a/src/Cosmos/Entry.cpp b/src/Cosmos/Entry.cpp index 6cf9026fddd..7de1049e24e 100644 --- a/src/Cosmos/Entry.cpp +++ b/src/Cosmos/Entry.cpp @@ -16,11 +16,14 @@ namespace TW::Cosmos { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char* hrp) const { - if (hrpForString(hrp) != TWHRPUnknown) { - return Address::isValid(coin, address); +bool Entry::validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const { + if (auto* hrp = std::get_if(&addressPrefix); hrp) { + if (hrpForString(*hrp) != TWHRPUnknown) { + return Address::isValid(coin, address); + } + return Address::isValid(address, *hrp); } - return Address::isValid(address, hrp); + return false; } string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char* hrp) const { diff --git a/src/Cosmos/Entry.h b/src/Cosmos/Entry.h index e5be0796622..599bb623f01 100644 --- a/src/Cosmos/Entry.h +++ b/src/Cosmos/Entry.h @@ -14,7 +14,7 @@ namespace TW::Cosmos { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const final; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const final; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const final; Data addressToData(TWCoinType coin, const std::string& address) const final; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const override; diff --git a/src/Decred/Entry.cpp b/src/Decred/Entry.cpp index 2bfc7149e39..36e0b21d1e7 100644 --- a/src/Decred/Entry.cpp +++ b/src/Decred/Entry.cpp @@ -11,7 +11,7 @@ namespace TW::Decred { -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] TW::byte p2sh, [[maybe_unused]] const char* hrp) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Decred/Entry.h b/src/Decred/Entry.h index 0d21789afa8..d6d2dccb262 100644 --- a/src/Decred/Entry.h +++ b/src/Decred/Entry.h @@ -14,11 +14,11 @@ namespace TW::Decred { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - Data addressToData(TWCoinType coin, const std::string& address) const; - void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Decred diff --git a/src/EOS/Entry.cpp b/src/EOS/Entry.cpp index fa3af508bb4..f2ecbbfa138 100644 --- a/src/EOS/Entry.cpp +++ b/src/EOS/Entry.cpp @@ -13,7 +13,7 @@ namespace TW::EOS { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/EOS/Entry.h b/src/EOS/Entry.h index 63823c8c020..3d5c1fda040 100644 --- a/src/EOS/Entry.h +++ b/src/EOS/Entry.h @@ -14,9 +14,9 @@ namespace TW::EOS { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::EOS diff --git a/src/Elrond/Entry.cpp b/src/Elrond/Entry.cpp index 2535f0bec96..ff04f37b8ed 100644 --- a/src/Elrond/Entry.cpp +++ b/src/Elrond/Entry.cpp @@ -15,7 +15,7 @@ using namespace std; namespace TW::Elrond { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Elrond/Entry.h b/src/Elrond/Entry.h index e0c4ed7b0a1..27b1270a462 100644 --- a/src/Elrond/Entry.h +++ b/src/Elrond/Entry.h @@ -12,14 +12,14 @@ namespace TW::Elrond { /// Entry point for implementation of Elrond coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file -class Entry final: public CoinEntry { +class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - Data addressToData(TWCoinType coin, const std::string& address) const; - void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - bool supportsJSONSigning() const { return true; } - std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool supportsJSONSigning() const { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; } // namespace TW::Elrond diff --git a/src/Ethereum/Entry.cpp b/src/Ethereum/Entry.cpp index f5a7c7ab87e..789384a4068 100644 --- a/src/Ethereum/Entry.cpp +++ b/src/Ethereum/Entry.cpp @@ -15,7 +15,7 @@ namespace TW::Ethereum { using namespace std; -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Ethereum/Entry.h b/src/Ethereum/Entry.h index 23a31b2c8d1..b92042e91dc 100644 --- a/src/Ethereum/Entry.h +++ b/src/Ethereum/Entry.h @@ -14,7 +14,7 @@ namespace TW::Ethereum { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const final; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const final; std::string normalizeAddress(TWCoinType coin, const std::string& address) const final; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const final; Data addressToData(TWCoinType coin, const std::string& address) const final; diff --git a/src/Everscale/Entry.cpp b/src/Everscale/Entry.cpp index e17aa9d5997..216cca93ec4 100644 --- a/src/Everscale/Entry.cpp +++ b/src/Everscale/Entry.cpp @@ -17,7 +17,7 @@ namespace TW::Everscale { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Everscale/Entry.h b/src/Everscale/Entry.h index c83a0d133ad..d24d55ebceb 100644 --- a/src/Everscale/Entry.h +++ b/src/Everscale/Entry.h @@ -14,7 +14,7 @@ namespace TW::Everscale { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string normalizeAddress(TWCoinType coin, const std::string& address) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* d) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/FIO/Entry.cpp b/src/FIO/Entry.cpp index a9194cb53ae..c435b98ff4f 100644 --- a/src/FIO/Entry.cpp +++ b/src/FIO/Entry.cpp @@ -13,7 +13,7 @@ namespace TW::FIO { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/FIO/Entry.h b/src/FIO/Entry.h index cb9ab8c38a2..49fa7e95002 100644 --- a/src/FIO/Entry.h +++ b/src/FIO/Entry.h @@ -14,7 +14,7 @@ namespace TW::FIO { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Filecoin/Entry.cpp b/src/Filecoin/Entry.cpp index 5ab6065a3ca..0317621d6a4 100644 --- a/src/Filecoin/Entry.cpp +++ b/src/Filecoin/Entry.cpp @@ -13,8 +13,7 @@ namespace TW::Filecoin { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, - const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Filecoin/Entry.h b/src/Filecoin/Entry.h index a989db0676e..7db1f33b6b0 100644 --- a/src/Filecoin/Entry.h +++ b/src/Filecoin/Entry.h @@ -15,8 +15,7 @@ namespace TW::Filecoin { /// includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, - TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Groestlcoin/Entry.cpp b/src/Groestlcoin/Entry.cpp index ae12284620a..6235c416271 100644 --- a/src/Groestlcoin/Entry.cpp +++ b/src/Groestlcoin/Entry.cpp @@ -12,8 +12,11 @@ namespace TW::Groestlcoin { -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const { - return TW::Bitcoin::SegwitAddress::isValid(address, hrp) || Address::isValid(address, {p2pkh, p2sh}); +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const { + if (auto* prefix = std::get_if(&addressPrefix); prefix) { + return Address::isValid(address, {prefix->p2pkh, prefix->p2sh}); + } + return TW::Bitcoin::SegwitAddress::isValid(address, std::get(addressPrefix)); } std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TW::byte p2pkh, const char* hrp) const { diff --git a/src/Groestlcoin/Entry.h b/src/Groestlcoin/Entry.h index 069cc75074e..37ea8ed1bc2 100644 --- a/src/Groestlcoin/Entry.h +++ b/src/Groestlcoin/Entry.h @@ -14,7 +14,7 @@ namespace TW::Groestlcoin { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Harmony/Entry.cpp b/src/Harmony/Entry.cpp index ad652105739..750f4d735ab 100644 --- a/src/Harmony/Entry.cpp +++ b/src/Harmony/Entry.cpp @@ -16,7 +16,7 @@ namespace TW::Harmony { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Harmony/Entry.h b/src/Harmony/Entry.h index 1feefb3ca70..167779f8292 100644 --- a/src/Harmony/Entry.h +++ b/src/Harmony/Entry.h @@ -14,7 +14,7 @@ namespace TW::Harmony { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Icon/Address.cpp b/src/Icon/Address.cpp index 6f219a3b537..79a680098d2 100644 --- a/src/Icon/Address.cpp +++ b/src/Icon/Address.cpp @@ -12,14 +12,14 @@ namespace TW::Icon { -static const std::string addressPrefix = "hx"; +static const std::string gAddressPrefix = "hx"; static const std::string contractPrefix = "cx"; bool Address::isValid(const std::string& string) { if (string.size() != Address::size * 2 + 2) { return false; } - if (!std::equal(addressPrefix.begin(), addressPrefix.end(), string.begin()) && + if (!std::equal(gAddressPrefix.begin(), gAddressPrefix.end(), string.begin()) && !std::equal(contractPrefix.begin(), contractPrefix.end(), string.begin())) { return false; } @@ -31,7 +31,7 @@ Address::Address(const std::string& string) { throw std::invalid_argument("Invalid address data"); } - if (std::equal(addressPrefix.begin(), addressPrefix.end(), string.begin())) { + if (std::equal(gAddressPrefix.begin(), gAddressPrefix.end(), string.begin())) { type = TypeAddress; } else if (std::equal(contractPrefix.begin(), contractPrefix.end(), string.begin())) { type = TypeContract; @@ -53,7 +53,7 @@ Address::Address(const PublicKey& publicKey, enum AddressType type) std::string Address::string() const { switch (type) { case TypeAddress: - return addressPrefix + hex(bytes); + return gAddressPrefix + hex(bytes); case TypeContract: return contractPrefix + hex(bytes); default: diff --git a/src/Icon/Entry.cpp b/src/Icon/Entry.cpp index 66c6ff5d2ad..4df47c1728a 100644 --- a/src/Icon/Entry.cpp +++ b/src/Icon/Entry.cpp @@ -13,7 +13,7 @@ namespace TW::Icon { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Icon/Entry.h b/src/Icon/Entry.h index 9547997f419..feeed6df284 100644 --- a/src/Icon/Entry.h +++ b/src/Icon/Entry.h @@ -14,7 +14,7 @@ namespace TW::Icon { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/IoTeX/Entry.cpp b/src/IoTeX/Entry.cpp index 5e427d85a67..85db67fe256 100644 --- a/src/IoTeX/Entry.cpp +++ b/src/IoTeX/Entry.cpp @@ -15,7 +15,7 @@ namespace TW::IoTeX { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/IoTeX/Entry.h b/src/IoTeX/Entry.h index ecf04236fc7..8793f9bcab9 100644 --- a/src/IoTeX/Entry.h +++ b/src/IoTeX/Entry.h @@ -14,7 +14,7 @@ namespace TW::IoTeX { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Kusama/Entry.cpp b/src/Kusama/Entry.cpp index 28e56d9bfb0..98876e41124 100644 --- a/src/Kusama/Entry.cpp +++ b/src/Kusama/Entry.cpp @@ -13,7 +13,7 @@ namespace TW::Kusama { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Kusama/Entry.h b/src/Kusama/Entry.h index f9d566239a1..0398c6f4acf 100644 --- a/src/Kusama/Entry.h +++ b/src/Kusama/Entry.h @@ -14,7 +14,7 @@ namespace TW::Kusama { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/NEAR/Entry.cpp b/src/NEAR/Entry.cpp index c33987cc422..63d69948969 100644 --- a/src/NEAR/Entry.cpp +++ b/src/NEAR/Entry.cpp @@ -16,7 +16,7 @@ namespace TW::NEAR { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/NEAR/Entry.h b/src/NEAR/Entry.h index 20a0870762c..41c5f52fc20 100644 --- a/src/NEAR/Entry.h +++ b/src/NEAR/Entry.h @@ -14,7 +14,7 @@ namespace TW::NEAR { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string normalizeAddress(TWCoinType coin, const std::string& address) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; diff --git a/src/NEO/Entry.cpp b/src/NEO/Entry.cpp index f9e55d72637..27a5d53fd92 100644 --- a/src/NEO/Entry.cpp +++ b/src/NEO/Entry.cpp @@ -14,7 +14,7 @@ using namespace std; namespace TW::NEO { -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const string& address, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] TW::byte p2sh, [[maybe_unused]] const char* hrp) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/NEO/Entry.h b/src/NEO/Entry.h index 6a396f753c2..8881a48a2ba 100644 --- a/src/NEO/Entry.h +++ b/src/NEO/Entry.h @@ -14,7 +14,7 @@ namespace TW::NEO { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/NULS/Entry.cpp b/src/NULS/Entry.cpp index db59dba1bb1..27aba6043d9 100644 --- a/src/NULS/Entry.cpp +++ b/src/NULS/Entry.cpp @@ -15,7 +15,7 @@ namespace TW::NULS { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/NULS/Entry.h b/src/NULS/Entry.h index b11bcc629bb..1060cc41c8e 100644 --- a/src/NULS/Entry.h +++ b/src/NULS/Entry.h @@ -14,7 +14,7 @@ namespace TW::NULS { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Nano/Entry.cpp b/src/Nano/Entry.cpp index 6cfdb73e52b..86858b9b1d3 100644 --- a/src/Nano/Entry.cpp +++ b/src/Nano/Entry.cpp @@ -13,7 +13,7 @@ namespace TW::Nano { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Nano/Entry.h b/src/Nano/Entry.h index 1a27f029e23..9ca84e41eb0 100644 --- a/src/Nano/Entry.h +++ b/src/Nano/Entry.h @@ -14,7 +14,7 @@ namespace TW::Nano { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Nebulas/Entry.cpp b/src/Nebulas/Entry.cpp index a8b4571e527..0487bb74e7d 100644 --- a/src/Nebulas/Entry.cpp +++ b/src/Nebulas/Entry.cpp @@ -14,7 +14,7 @@ using namespace std; namespace TW::Nebulas { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Nebulas/Entry.h b/src/Nebulas/Entry.h index 0bdcaded71c..7fa88305c1c 100644 --- a/src/Nebulas/Entry.h +++ b/src/Nebulas/Entry.h @@ -14,7 +14,7 @@ namespace TW::Nebulas { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Nervos/Entry.cpp b/src/Nervos/Entry.cpp index 44e725ae6a3..b4e9b071d55 100644 --- a/src/Nervos/Entry.cpp +++ b/src/Nervos/Entry.cpp @@ -12,9 +12,9 @@ namespace TW::Nervos { using namespace std; -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, byte, byte, - const char* hrp) const { - return Address::isValid(address, hrp); +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const { + auto* hrpPrefix = std::get_if(&addressPrefix); + return Address::isValid(address, hrpPrefix ? *hrpPrefix : HRP_NERVOS); } string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, byte, diff --git a/src/Nervos/Entry.h b/src/Nervos/Entry.h index 0d3919dcefb..e91a777e7fa 100644 --- a/src/Nervos/Entry.h +++ b/src/Nervos/Entry.h @@ -17,8 +17,7 @@ namespace TW::Nervos { /// includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, byte p2pkh, byte p2sh, - const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Nimiq/Entry.cpp b/src/Nimiq/Entry.cpp index 92279053f4f..c063fe2d977 100644 --- a/src/Nimiq/Entry.cpp +++ b/src/Nimiq/Entry.cpp @@ -13,7 +13,7 @@ namespace TW::Nimiq { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Nimiq/Entry.h b/src/Nimiq/Entry.h index cad09e0fc65..6e19d3e24af 100644 --- a/src/Nimiq/Entry.h +++ b/src/Nimiq/Entry.h @@ -14,7 +14,7 @@ namespace TW::Nimiq { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Oasis/Entry.cpp b/src/Oasis/Entry.cpp index 3dbaeeb4d24..a9e1f4172bf 100644 --- a/src/Oasis/Entry.cpp +++ b/src/Oasis/Entry.cpp @@ -15,7 +15,7 @@ namespace TW::Oasis { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Oasis/Entry.h b/src/Oasis/Entry.h index c4b3fb6240f..4ae19abbf0a 100644 --- a/src/Oasis/Entry.h +++ b/src/Oasis/Entry.h @@ -14,7 +14,7 @@ namespace TW::Oasis { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Ontology/Entry.cpp b/src/Ontology/Entry.cpp index 9f4de742362..51d251e24d0 100644 --- a/src/Ontology/Entry.cpp +++ b/src/Ontology/Entry.cpp @@ -13,7 +13,7 @@ namespace TW::Ontology { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Ontology/Entry.h b/src/Ontology/Entry.h index 68df17b8baf..836a0f391e3 100644 --- a/src/Ontology/Entry.h +++ b/src/Ontology/Entry.h @@ -14,7 +14,7 @@ namespace TW::Ontology { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Polkadot/Address.h b/src/Polkadot/Address.h index 10f3828c2a0..f695ad85798 100644 --- a/src/Polkadot/Address.h +++ b/src/Polkadot/Address.h @@ -19,12 +19,15 @@ class Address: public SS58Address { public: /// Determines whether a string makes a valid address. static bool isValid(const std::string& string) { return SS58Address::isValid(string, TWSS58AddressTypePolkadot); } + static bool isValid(const std::string& string, uint32_t ss58Prefix) { return SS58Address::isValid(string, ss58Prefix); } /// Initializes a Polkadot address with a string representation. - Address(const std::string& string): SS58Address(string, TWSS58AddressTypePolkadot) {} + explicit Address(const std::string& string): SS58Address(string, TWSS58AddressTypePolkadot) {} /// Initializes a Polkadot address with a public key. - Address(const PublicKey& publicKey): SS58Address(publicKey, TWSS58AddressTypePolkadot) {} + explicit Address(const PublicKey& publicKey): SS58Address(publicKey, TWSS58AddressTypePolkadot) {} + /// Initializes a Polkadot address with a public key and a given ss58Prefix. + explicit Address(const PublicKey& publicKey, std::uint32_t ss58Prefix): SS58Address(publicKey, ss58Prefix) {} }; } // namespace TW::Polkadot diff --git a/src/Polkadot/Entry.cpp b/src/Polkadot/Entry.cpp index f97ae843ca9..db51b204ec1 100644 --- a/src/Polkadot/Entry.cpp +++ b/src/Polkadot/Entry.cpp @@ -13,7 +13,10 @@ namespace TW::Polkadot { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const { + if (auto* prefix = std::get_if(&addressPrefix); prefix) { + return Address::isValid(address, *prefix); + } return Address::isValid(address); } @@ -30,4 +33,11 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D signTemplate(dataIn, dataOut); } +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, const PrefixVariant& addressPrefix) const { + if (auto* ss58Prefix = std::get_if(&addressPrefix); ss58Prefix) { + return Address(publicKey, *ss58Prefix).string(); + } + return ""; +} + } // namespace TW::Polkadot diff --git a/src/Polkadot/Entry.h b/src/Polkadot/Entry.h index d36ac8845af..5c19d70c6db 100644 --- a/src/Polkadot/Entry.h +++ b/src/Polkadot/Entry.h @@ -14,10 +14,11 @@ namespace TW::Polkadot { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - Data addressToData(TWCoinType coin, const std::string& address) const; - void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; + Data addressToData(TWCoinType coin, const std::string& address) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Polkadot diff --git a/src/Polkadot/SS58Address.cpp b/src/Polkadot/SS58Address.cpp index 34a25f7c263..2c99b764ba9 100644 --- a/src/Polkadot/SS58Address.cpp +++ b/src/Polkadot/SS58Address.cpp @@ -34,7 +34,7 @@ bool SS58Address::isValid(const std::string& string, uint32_t network) { template Data SS58Address::computeChecksum(const T& data) { - auto prefix = Data(SS58Prefix.begin(), SS58Prefix.end()); + auto prefix = Data(gSS58Prefix.begin(), gSS58Prefix.end()); append(prefix, Data(data.begin(), data.end())); auto hash = Hash::blake2b(prefix, 64); auto checksum = Data(checksumSize); diff --git a/src/Polkadot/SS58Address.h b/src/Polkadot/SS58Address.h index 20d4e292f70..4feaaacd760 100644 --- a/src/Polkadot/SS58Address.h +++ b/src/Polkadot/SS58Address.h @@ -12,7 +12,7 @@ #include -inline const std::string SS58Prefix{"SS58PRE"}; +inline const std::string gSS58Prefix{"SS58PRE"}; namespace TW { diff --git a/src/Ronin/Entry.cpp b/src/Ronin/Entry.cpp index d69ac356390..6eaf45cf2d8 100644 --- a/src/Ronin/Entry.cpp +++ b/src/Ronin/Entry.cpp @@ -14,7 +14,7 @@ using namespace std; namespace TW::Ronin { -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Ronin/Entry.h b/src/Ronin/Entry.h index 9bb7f96aa40..8723a549db1 100644 --- a/src/Ronin/Entry.h +++ b/src/Ronin/Entry.h @@ -13,7 +13,7 @@ namespace TW::Ronin { /// Entry point for Ronin (EVM side chain) class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string normalizeAddress(TWCoinType coin, const std::string& address) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; diff --git a/src/Solana/Entry.cpp b/src/Solana/Entry.cpp index 765c9c1927f..1e216d426ab 100644 --- a/src/Solana/Entry.cpp +++ b/src/Solana/Entry.cpp @@ -16,7 +16,7 @@ namespace TW::Solana { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Solana/Entry.h b/src/Solana/Entry.h index b6bc8b4f1d4..2735b866e69 100644 --- a/src/Solana/Entry.h +++ b/src/Solana/Entry.h @@ -14,7 +14,7 @@ namespace TW::Solana { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Stellar/Entry.cpp b/src/Stellar/Entry.cpp index a2412dcb5dd..ce6cded2f72 100644 --- a/src/Stellar/Entry.cpp +++ b/src/Stellar/Entry.cpp @@ -13,7 +13,7 @@ namespace TW::Stellar { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Stellar/Entry.h b/src/Stellar/Entry.h index f4236c325df..14f9dc4b6cd 100644 --- a/src/Stellar/Entry.h +++ b/src/Stellar/Entry.h @@ -14,7 +14,7 @@ namespace TW::Stellar { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Tezos/Entry.cpp b/src/Tezos/Entry.cpp index 71aa8246a81..19a6dc9f66c 100644 --- a/src/Tezos/Entry.cpp +++ b/src/Tezos/Entry.cpp @@ -13,7 +13,7 @@ namespace TW::Tezos { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Tezos/Entry.h b/src/Tezos/Entry.h index bea87ca0aa3..ae744e64236 100644 --- a/src/Tezos/Entry.h +++ b/src/Tezos/Entry.h @@ -14,7 +14,7 @@ namespace TW::Tezos { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; bool supportsJSONSigning() const { return true; } diff --git a/src/Tron/Entry.cpp b/src/Tron/Entry.cpp index 056728c4bc6..8a0feb4d29b 100644 --- a/src/Tron/Entry.cpp +++ b/src/Tron/Entry.cpp @@ -14,7 +14,7 @@ using namespace std; namespace TW::Tron { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Tron/Entry.h b/src/Tron/Entry.h index 0d25c65da8b..531f2ef9127 100644 --- a/src/Tron/Entry.h +++ b/src/Tron/Entry.h @@ -14,7 +14,7 @@ namespace TW::Tron { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Waves/Entry.cpp b/src/Waves/Entry.cpp index 9635e2d30cd..30b5e730871 100644 --- a/src/Waves/Entry.cpp +++ b/src/Waves/Entry.cpp @@ -15,7 +15,7 @@ namespace TW::Waves { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Waves/Entry.h b/src/Waves/Entry.h index ea114e04c45..fe30cd62120 100644 --- a/src/Waves/Entry.h +++ b/src/Waves/Entry.h @@ -14,7 +14,7 @@ namespace TW::Waves { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/XRP/Entry.cpp b/src/XRP/Entry.cpp index b28a843c670..7fd7c10f85e 100644 --- a/src/XRP/Entry.cpp +++ b/src/XRP/Entry.cpp @@ -14,7 +14,7 @@ namespace TW::Ripple { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, TW::byte, TW::byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address) || XAddress::isValid(address); } diff --git a/src/XRP/Entry.h b/src/XRP/Entry.h index 6736133286e..f30c07fb4bc 100644 --- a/src/XRP/Entry.h +++ b/src/XRP/Entry.h @@ -14,7 +14,7 @@ namespace TW::Ripple { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Zcash/Entry.cpp b/src/Zcash/Entry.cpp index ff5f1ac21ce..883cf768027 100644 --- a/src/Zcash/Entry.cpp +++ b/src/Zcash/Entry.cpp @@ -11,7 +11,7 @@ namespace TW::Zcash { -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const std::string& address, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] TW::byte p2sh, [[maybe_unused]] const char* hrp) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return TAddress::isValid(address); } diff --git a/src/Zcash/Entry.h b/src/Zcash/Entry.h index 626f8105131..c50bcfc8ea7 100644 --- a/src/Zcash/Entry.h +++ b/src/Zcash/Entry.h @@ -14,7 +14,7 @@ namespace TW::Zcash { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Zilliqa/Entry.cpp b/src/Zilliqa/Entry.cpp index 9ab22662f0d..249c2e2b5b0 100644 --- a/src/Zilliqa/Entry.cpp +++ b/src/Zilliqa/Entry.cpp @@ -13,7 +13,7 @@ namespace TW::Zilliqa { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, byte, byte, const char*) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Zilliqa/Entry.h b/src/Zilliqa/Entry.h index fa1335f5838..90eda0931d1 100644 --- a/src/Zilliqa/Entry.h +++ b/src/Zilliqa/Entry.h @@ -14,7 +14,7 @@ namespace TW::Zilliqa { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/interface/TWAnyAddress.cpp b/src/interface/TWAnyAddress.cpp index 6ad7a9fb9ce..d67496008d4 100644 --- a/src/interface/TWAnyAddress.cpp +++ b/src/interface/TWAnyAddress.cpp @@ -21,6 +21,11 @@ bool TWAnyAddressIsValid(TWString* _Nonnull string, enum TWCoinType coin) { return TW::validateAddress(coin, address); } +bool TWAnyAddressIsValidSS58([[maybe_unused]] TWString* string, [[maybe_unused]] enum TWCoinType coin, [[maybe_unused]] uint32_t ss58Prefix) { + const auto& address = *reinterpret_cast(string); + return TW::validateAddress(coin, address, ss58Prefix); +} + bool TWAnyAddressIsValidBech32(TWString* _Nonnull string, enum TWCoinType coin, TWString* _Nonnull hrp) { const auto& address = *reinterpret_cast(string); const auto& hrpStr = *reinterpret_cast(hrp); @@ -41,7 +46,17 @@ struct TWAnyAddress* _Nullable TWAnyAddressCreateBech32(TWString* _Nonnull strin enum TWCoinType coin, TWString* _Nonnull hrp) { const auto& address = *reinterpret_cast(string); const auto& hrpStr = *reinterpret_cast(hrp); - auto *impl = TW::AnyAddress::createAddress(address, coin, hrpStr); + auto *impl = TW::AnyAddress::createAddress(address, coin, hrpStr.c_str()); + if (impl == nullptr) { + return nullptr; + } + return new TWAnyAddress{impl}; +} + + +struct TWAnyAddress* TWAnyAddressCreateSS58(TWString* _Nonnull string, enum TWCoinType coin, uint32_t ss58Prefix) { + const auto& address = *reinterpret_cast(string); + auto *impl = TW::AnyAddress::createAddress(address, coin, ss58Prefix); if (impl == nullptr) { return nullptr; } @@ -59,6 +74,10 @@ struct TWAnyAddress* _Nonnull TWAnyAddressCreateBech32WithPublicKey( return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin, hrpStr)}; } +struct TWAnyAddress* TWAnyAddressCreateSS58WithPublicKey(struct TWPublicKey* publicKey, enum TWCoinType coin, uint32_t ss58Prefix) { + return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin, ss58Prefix)}; +} + void TWAnyAddressDelete(struct TWAnyAddress* _Nonnull address) { delete address->impl; delete address; diff --git a/src/interface/TWCoinType.cpp b/src/interface/TWCoinType.cpp index 2d58d5a7be5..e63373a98c8 100644 --- a/src/interface/TWCoinType.cpp +++ b/src/interface/TWCoinType.cpp @@ -82,3 +82,7 @@ uint32_t TWCoinTypeSlip44Id(enum TWCoinType coin) { enum TWPublicKeyType TWCoinTypePublicKeyType(enum TWCoinType coin) { return TW::publicKeyType(coin); } + +uint32_t TWCoinTypeSS58Prefix(enum TWCoinType coin) { + return TW::ss58Prefix(coin); +} diff --git a/src/proto/Polkadot.proto b/src/proto/Polkadot.proto index 178a26485de..8fa16926363 100644 --- a/src/proto/Polkadot.proto +++ b/src/proto/Polkadot.proto @@ -3,12 +3,6 @@ syntax = "proto3"; package TW.Polkadot.Proto; option java_package = "wallet.core.jni.proto"; -// Known networks -enum Network { - POLKADOT = 0; - KUSAMA = 2; -} - // Destination options for reward enum RewardDestination { STAKED = 0; @@ -142,7 +136,7 @@ message SigningInput { bytes private_key = 8; // Network type - Network network = 9; + uint32 network = 9; // Payload message oneof message_oneof { diff --git a/swift/Tests/Blockchains/KusamaTests.swift b/swift/Tests/Blockchains/KusamaTests.swift index 0b93a1cd118..ae5fd1ea397 100644 --- a/swift/Tests/Blockchains/KusamaTests.swift +++ b/swift/Tests/Blockchains/KusamaTests.swift @@ -51,7 +51,7 @@ class KusamaTests: XCTestCase { $0.value = Data(hexString: "0x02540be400")! } } - $0.network = .kusama + $0.network = CoinType.kusama.ss58Prefix $0.transactionVersion = 2 $0.privateKey = key.data } diff --git a/swift/Tests/Blockchains/PolkadotTests.swift b/swift/Tests/Blockchains/PolkadotTests.swift index aae9c432a70..c4414e5f607 100644 --- a/swift/Tests/Blockchains/PolkadotTests.swift +++ b/swift/Tests/Blockchains/PolkadotTests.swift @@ -44,7 +44,7 @@ class PolkadotTests: XCTestCase { $0.blockHash = Data(hexString: "0x7d5fa17b70251d0806f26156b1b698dfd09e040642fa092595ce0a78e9e84fcd")! $0.nonce = 1 $0.specVersion = 28 - $0.network = .polkadot + $0.network = CoinType.polkadot.ss58Prefix $0.transactionVersion = 6 $0.privateKey = key.data $0.era = PolkadotEra.with { @@ -73,7 +73,7 @@ class PolkadotTests: XCTestCase { $0.blockHash = genesisHash $0.nonce = 0 $0.specVersion = 17 - $0.network = .polkadot + $0.network = CoinType.polkadot.ss58Prefix $0.transactionVersion = 3 $0.privateKey = key.data $0.stakingCall.bond = PolkadotStaking.Bond.with { @@ -97,7 +97,7 @@ class PolkadotTests: XCTestCase { $0.blockHash = genesisHash $0.nonce = 4 $0.specVersion = 30 - $0.network = .polkadot + $0.network = CoinType.polkadot.ss58Prefix $0.transactionVersion = 7 $0.privateKey = key.data $0.stakingCall.bondAndNominate = PolkadotStaking.BondAndNominate.with { @@ -125,7 +125,7 @@ class PolkadotTests: XCTestCase { $0.blockHash = genesisHash $0.nonce = 5 $0.specVersion = 30 - $0.network = .polkadot + $0.network = CoinType.polkadot.ss58Prefix $0.transactionVersion = 7 $0.privateKey = key.data $0.stakingCall.bondExtra = PolkadotStaking.BondExtra.with { @@ -151,7 +151,7 @@ class PolkadotTests: XCTestCase { } $0.nonce = 6 $0.specVersion = 9200 - $0.network = .polkadot + $0.network = CoinType.polkadot.ss58Prefix $0.transactionVersion = 12 $0.privateKey = key.data $0.stakingCall.chillAndUnbond = PolkadotStaking.ChillAndUnbond.with { diff --git a/tests/chains/Acala/TWAnyAddressTests.cpp b/tests/chains/Acala/TWAnyAddressTests.cpp new file mode 100644 index 00000000000..47f9a823974 --- /dev/null +++ b/tests/chains/Acala/TWAnyAddressTests.cpp @@ -0,0 +1,49 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include +#include "HexCoding.h" +#include "Hash.h" +#include "PublicKey.h" +#include "Bech32Address.h" + +#include "TestUtilities.h" +#include + +namespace TW::Polkadot::tests { + +inline constexpr uint32_t acalaPrefix{10}; + +TEST(TWAcalaAnyAddress, IsValid) { + EXPECT_TRUE(TWAnyAddressIsValidSS58(STRING("212ywJGVK2Nxnt5bjKXVHi4YY7FCFd4rVvhyt95CjpeHGZee").get(), TWCoinTypePolkadot, acalaPrefix)); + EXPECT_FALSE(TWAnyAddressIsValid(STRING("212ywJGVK2Nxnt5bjKXVHi4YY7FCFd4rVvhyt95CjpeHGZee").get(), TWCoinTypePolkadot)); + EXPECT_FALSE(TWAnyAddressIsValid(STRING("212ywJGVK2Nxnt5bjKXVHi4YY7FCFd4rVvhyt95CjpeHGZee").get(), TWCoinTypeBitcoin)); + EXPECT_FALSE(TWAnyAddressIsValidSS58(STRING("15KRsCq9LLNmCxNFhGk55s5bEyazKefunDxUH24GFZwsTxyu").get(), TWCoinTypePolkadot, acalaPrefix)); +} + +TEST(TWAcalaAnyAddress, createFromPubKeyAcala) { + const auto data = DATA("92fd9c237030356e26cfcc4568dc71055d5ec92dfe0ff903767e00611971bad3"); + const auto pubkey = TWPublicKeyCreateWithData(data.get(), TWPublicKeyTypeED25519); + const auto twAddress = TWAnyAddressCreateSS58WithPublicKey(pubkey, TWCoinTypePolkadot, acalaPrefix); + auto address = TWAnyAddressDescription(twAddress); + EXPECT_EQ("24CKv1LJ1T3U9ujCN63YzTPuQjcmURGA2xTjim98UKXxgNXT", *reinterpret_cast(address)); + TWStringDelete(address); + TWAnyAddressDelete(twAddress); + TWPublicKeyDelete(pubkey); +} + +TEST(TWAcalaAnyAddress, createFromStringAcala) { + const auto acalaAddress = STRING("24CKv1LJ1T3U9ujCN63YzTPuQjcmURGA2xTjim98UKXxgNXT"); + const auto anyAddr = TWAnyAddressCreateSS58(acalaAddress.get(), TWCoinTypePolkadot, acalaPrefix); + const auto addrDescription = TWAnyAddressDescription(anyAddr); + ASSERT_TRUE(TWAnyAddressIsValidSS58(addrDescription, TWCoinTypePolkadot, acalaPrefix)); + TWStringDelete(addrDescription); + TWAnyAddressDelete(anyAddr); + +} + +} diff --git a/tests/chains/Juno/TWAnyAddressTests.cpp b/tests/chains/Juno/TWAnyAddressTests.cpp index 2eddab2c3c7..491bcd20a78 100644 --- a/tests/chains/Juno/TWAnyAddressTests.cpp +++ b/tests/chains/Juno/TWAnyAddressTests.cpp @@ -10,6 +10,8 @@ #include "Bech32Address.h" #include "HexCoding.h" #include "Hash.h" +#include "PublicKey.h" +#include "Bech32Address.h" #include "TestUtilities.h" #include diff --git a/tests/chains/Kusama/SignerTests.cpp b/tests/chains/Kusama/SignerTests.cpp index 3af2df1c9ec..eac82e1a890 100644 --- a/tests/chains/Kusama/SignerTests.cpp +++ b/tests/chains/Kusama/SignerTests.cpp @@ -8,6 +8,7 @@ #include "Polkadot/Extrinsic.h" #include "Polkadot/SS58Address.h" #include "HexCoding.h" +#include "Coin.h" #include "PrivateKey.h" #include "PublicKey.h" #include "proto/Polkadot.pb.h" @@ -32,7 +33,7 @@ TEST(PolkadotSigner, SignTransferKSM) { input.set_nonce(0); input.set_spec_version(2019); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - input.set_network(Proto::Network::KUSAMA); + input.set_network(ss58Prefix(TWCoinType::TWCoinTypeKusama)); input.set_transaction_version(2); auto balanceCall = input.mutable_balance_call(); diff --git a/tests/chains/Kusama/TWAnySignerTests.cpp b/tests/chains/Kusama/TWAnySignerTests.cpp index c23abdd9acb..60905a5633b 100644 --- a/tests/chains/Kusama/TWAnySignerTests.cpp +++ b/tests/chains/Kusama/TWAnySignerTests.cpp @@ -24,7 +24,7 @@ TEST(TWAnySignerKusama, Sign) { input.set_nonce(1); input.set_spec_version(2019); input.set_private_key(key.data(), key.size()); - input.set_network(Proto::Network::KUSAMA); + input.set_network(TWCoinTypeSS58Prefix(TWCoinTypeKusama)); input.set_transaction_version(2); auto balanceCall = input.mutable_balance_call(); diff --git a/tests/chains/Polkadot/SignerTests.cpp b/tests/chains/Polkadot/SignerTests.cpp index 17164a45ea4..c3ee02fe27b 100644 --- a/tests/chains/Polkadot/SignerTests.cpp +++ b/tests/chains/Polkadot/SignerTests.cpp @@ -12,6 +12,7 @@ #include "PrivateKey.h" #include "PublicKey.h" #include "proto/Polkadot.pb.h" +#include "Coin.h" #include "uint256.h" #include @@ -43,7 +44,7 @@ TEST(PolkadotSigner, SignTransfer_9fd062) { EXPECT_EQ(address.string(), addressThrow2); } input.set_private_key(privateKeyThrow2.bytes.data(), privateKeyThrow2.bytes.size()); - input.set_network(Proto::Network::POLKADOT); + input.set_network(ss58Prefix(TWCoinTypePolkadot)); input.set_transaction_version(5); // era: for blockhash and block number, use curl -H "Content-Type: application/json" -H "Accept: text/plain" https:///transaction/material?noMeta=true @@ -78,7 +79,7 @@ TEST(PolkadotSigner, SignTransferDOT) { input.set_nonce(0); input.set_spec_version(17); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - input.set_network(Proto::Network::POLKADOT); + input.set_network(ss58Prefix(TWCoinTypePolkadot)); input.set_transaction_version(3); auto& era = *input.mutable_era(); @@ -110,7 +111,7 @@ TEST(PolkadotSigner, SignTransfer_72dd5b) { input.set_nonce(1); input.set_spec_version(28); input.set_private_key(privateKeyIOS.bytes.data(), privateKeyIOS.bytes.size()); - input.set_network(Proto::Network::POLKADOT); + input.set_network(ss58Prefix(TWCoinTypePolkadot)); input.set_transaction_version(6); auto& era = *input.mutable_era(); @@ -144,7 +145,7 @@ TEST(PolkadotSigner, SignBond_8da66d) { EXPECT_EQ(address.string(), addressThrow2); } input.set_private_key(privateKeyThrow2.bytes.data(), privateKeyThrow2.bytes.size()); - input.set_network(Proto::Network::POLKADOT); + input.set_network(ss58Prefix(TWCoinTypePolkadot)); input.set_transaction_version(5); // era: for blockhash and block number, use curl -H "Content-Type: application/json" -H "Accept: text/plain" https:///transaction/material?noMeta=true @@ -173,7 +174,7 @@ TEST(PolkadotSigner, SignBondAndNominate_4955314_2) { input.set_nonce(4); input.set_spec_version(30); input.set_private_key(key.data(), key.size()); - input.set_network(Proto::Network::POLKADOT); + input.set_network(ss58Prefix(TWCoinTypePolkadot)); input.set_transaction_version(7); auto stakingCall = input.mutable_staking_call(); @@ -198,7 +199,7 @@ TEST(PolkadotSigner, SignNominate_452522) { input.set_nonce(1); input.set_spec_version(26); input.set_private_key(privateKeyThrow2.bytes.data(), privateKeyThrow2.bytes.size()); - input.set_network(Proto::Network::POLKADOT); + input.set_network(ss58Prefix(TWCoinTypePolkadot)); input.set_transaction_version(5); // era: for blockhash and block number, use curl -H "Content-Type: application/json" -H "Accept: text/plain" https:///transaction/material?noMeta=true @@ -226,7 +227,7 @@ TEST(PolkadotSigner, SignNominate2) { input.set_nonce(0); input.set_spec_version(17); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - input.set_network(Proto::Network::POLKADOT); + input.set_network(ss58Prefix(TWCoinTypePolkadot)); input.set_transaction_version(3); auto stakingCall = input.mutable_staking_call(); @@ -253,7 +254,7 @@ TEST(PolkadotSigner, SignChill) { input.set_nonce(0); input.set_spec_version(17); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - input.set_network(Proto::Network::POLKADOT); + input.set_network(ss58Prefix(TWCoinTypePolkadot)); input.set_transaction_version(3); auto stakingCall = input.mutable_staking_call(); @@ -272,7 +273,7 @@ TEST(PolkadotSigner, SignWithdraw) { input.set_nonce(0); input.set_spec_version(17); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); - input.set_network(Proto::Network::POLKADOT); + input.set_network(ss58Prefix(TWCoinTypePolkadot)); input.set_transaction_version(3); auto stakingCall = input.mutable_staking_call(); @@ -293,7 +294,7 @@ TEST(PolkadotSigner, SignUnbond_070957) { input.set_nonce(2); input.set_spec_version(26); input.set_private_key(privateKeyThrow2.bytes.data(), privateKeyThrow2.bytes.size()); - input.set_network(Proto::Network::POLKADOT); + input.set_network(ss58Prefix(TWCoinTypePolkadot)); input.set_transaction_version(5); auto era = input.mutable_era(); @@ -319,7 +320,7 @@ TEST(PolkadotSigner, SignChillAndUnbond) { input.set_nonce(6); input.set_spec_version(9200); input.set_private_key(privateKeyPolkadot.bytes.data(), privateKeyPolkadot.bytes.size()); - input.set_network(Proto::Network::POLKADOT); + input.set_network(ss58Prefix(TWCoinTypePolkadot)); input.set_transaction_version(12); auto era = input.mutable_era(); @@ -336,4 +337,4 @@ TEST(PolkadotSigner, SignChillAndUnbond) { ASSERT_EQ(hex(output.encoded()), "d10184008361bd08ddca5fda28b5e2aa84dc2621de566e23e089e555a42194c3eaf2da7900c891ba102db672e378945d74cf7f399226a76b43cab502436971599255451597fc2599902e4b62c7ce85ecc3f653c693fef3232be620984b5bb5bcecbbd7b209d50318001a02080706070207004d446617"); } -} // namespace TW::Polkadot::tests +} // namespace Polkadot::tests From a21834107b5646907961dd7680f0068f313feca0 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 26 Oct 2022 06:59:29 +0200 Subject: [PATCH 120/497] [Elrond]: add elrond staking unit tests (#2675) --- .../blockchains/elrond/TestElrondSigner.kt | 66 +++++++ swift/Tests/Blockchains/ElrondTests.swift | 58 ++++++ tests/chains/Elrond/SignerTests.cpp | 186 ++++++++++++++++++ 3 files changed, 310 insertions(+) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt index a99a949bdb4..44a9e16b2a3 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt @@ -57,6 +57,72 @@ class TestElrondSigner { assertEquals("""{"nonce":7,"value":"0","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":1000000000,"gasLimit":50000,"data":"Zm9v","chainID":"1","version":1,"signature":"$expectedSignature"}""", output.encoded) } + @Test + fun signGenericActionUndelegate() { + // Successfully broadcasted https://explorer.elrond.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 + val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) + + val accounts = Elrond.Accounts.newBuilder() + .setSenderNonce(6) + .setSender("erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa") + .setReceiver("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r") + .build() + + val genericAction = Elrond.GenericAction.newBuilder() + .setAccounts(accounts) + .setValue("0") + .setData("unDelegate@0de0b6b3a7640000") + .setVersion(1) + .build() + + val signingInput = Elrond.SigningInput.newBuilder() + .setGenericAction(genericAction) + .setGasPrice(1000000000) + .setGasLimit(12000000) + .setChainId("1") + .setPrivateKey(privateKey) + .build() + + val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) + val expectedSignature = "89f9683af92f7b835bff4e1d0dbfcff5245b3367df4d23538eb799e0ad0a90be29ac3bd3598ce55b35b35ebef68bfa5738eed39fd01adc33476f65bd1b966e0b" + + assertEquals(expectedSignature, output.signature) + assertEquals("""{"nonce":6,"value":"0","receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r","sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa","gasPrice":1000000000,"gasLimit":12000000,"data":"dW5EZWxlZ2F0ZUAwZGUwYjZiM2E3NjQwMDAw","chainID":"1","version":1,"signature":"$expectedSignature"}""", output.encoded) + } + + @Test + fun signGenericActionDelegate() { + // Successfully broadcasted https://explorer.elrond.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 + val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) + + val accounts = Elrond.Accounts.newBuilder() + .setSenderNonce(1) + .setSender("erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa") + .setReceiver("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r") + .build() + + val genericAction = Elrond.GenericAction.newBuilder() + .setAccounts(accounts) + .setValue("1") + .setData("delegate") + .setVersion(1) + .build() + + val signingInput = Elrond.SigningInput.newBuilder() + .setGenericAction(genericAction) + .setGasPrice(1000000000) + .setGasLimit(12000000) + .setChainId("1") + .setPrivateKey(privateKey) + .build() + + val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) + val expectedSignature = "3b9164d47a4e3c0330ae387cd29ba6391f9295acf5e43a16a4a2611645e66e5fa46bf22294ca68fe1948adf45cec8cb47b8792afcdb248bd9adec7c6e6c27108" + + assertEquals(expectedSignature, output.signature) + assertEquals("""{"nonce":1,"value":"1","receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r","sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa","gasPrice":1000000000,"gasLimit":12000000,"data":"ZGVsZWdhdGU=","chainID":"1","version":1,"signature":"$expectedSignature"}""", output.encoded) + } + @Test fun signEGLDTransfer() { val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) diff --git a/swift/Tests/Blockchains/ElrondTests.swift b/swift/Tests/Blockchains/ElrondTests.swift index 06718ed42a3..beee15a7a26 100644 --- a/swift/Tests/Blockchains/ElrondTests.swift +++ b/swift/Tests/Blockchains/ElrondTests.swift @@ -51,6 +51,64 @@ class ElrondTests: XCTestCase { XCTAssertEqual(output.signature, expectedSignature) XCTAssertEqual(output.encoded, expectedEncoded) } + + func testSignGenericActionUndelegate() { + // Successfully broadcasted https://explorer.elrond.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 + let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)! + + let input = ElrondSigningInput.with { + $0.genericAction = ElrondGenericAction.with { + $0.accounts = ElrondAccounts.with { + $0.senderNonce = 6 + $0.sender = "erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa" + $0.receiver = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r" + } + $0.value = "0" + $0.data = "unDelegate@0de0b6b3a7640000" + $0.version = 1 + } + $0.gasPrice = 1000000000 + $0.gasLimit = 12000000 + $0.chainID = "1" + $0.privateKey = privateKey.data + } + + let output: ElrondSigningOutput = AnySigner.sign(input: input, coin: .elrond) + let expectedSignature = "89f9683af92f7b835bff4e1d0dbfcff5245b3367df4d23538eb799e0ad0a90be29ac3bd3598ce55b35b35ebef68bfa5738eed39fd01adc33476f65bd1b966e0b" + let expectedEncoded = #"{"nonce":6,"value":"0","receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r","sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa","gasPrice":1000000000,"gasLimit":12000000,"data":"dW5EZWxlZ2F0ZUAwZGUwYjZiM2E3NjQwMDAw","chainID":"1","version":1,"signature":"\#(expectedSignature)"}"# + + XCTAssertEqual(output.signature, expectedSignature) + XCTAssertEqual(output.encoded, expectedEncoded) + } + + func testSignGenericActionDelegate() { + // Successfully broadcasted https://explorer.elrond.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 + let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)! + + let input = ElrondSigningInput.with { + $0.genericAction = ElrondGenericAction.with { + $0.accounts = ElrondAccounts.with { + $0.senderNonce = 1 + $0.sender = "erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa" + $0.receiver = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r" + } + $0.value = "1" + $0.data = "delegate" + $0.version = 1 + } + $0.gasPrice = 1000000000 + $0.gasLimit = 12000000 + $0.chainID = "1" + $0.privateKey = privateKey.data + } + + let output: ElrondSigningOutput = AnySigner.sign(input: input, coin: .elrond) + let expectedSignature = "3b9164d47a4e3c0330ae387cd29ba6391f9295acf5e43a16a4a2611645e66e5fa46bf22294ca68fe1948adf45cec8cb47b8792afcdb248bd9adec7c6e6c27108" + let expectedEncoded = #"{"nonce":1,"value":"1","receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r","sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa","gasPrice":1000000000,"gasLimit":12000000,"data":"ZGVsZWdhdGU=","chainID":"1","version":1,"signature":"\#(expectedSignature)"}"# + + XCTAssertEqual(output.signature, expectedSignature) + XCTAssertEqual(output.encoded, expectedEncoded) + } func testSignEGLDTransfer() { let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)! diff --git a/tests/chains/Elrond/SignerTests.cpp b/tests/chains/Elrond/SignerTests.cpp index aeaa8455a69..f2348dbe155 100644 --- a/tests/chains/Elrond/SignerTests.cpp +++ b/tests/chains/Elrond/SignerTests.cpp @@ -6,13 +6,16 @@ #include "boost/format.hpp" #include +#include #include "Elrond/Address.h" #include "Elrond/Signer.h" +#include "Elrond/Codec.h" #include "HexCoding.h" #include "PrivateKey.h" #include "PublicKey.h" #include "TestAccounts.h" +#include "TestUtilities.h" using namespace TW; @@ -43,6 +46,189 @@ TEST(ElrondSigner, SignGenericAction) { ASSERT_EQ(expectedSignature, signature); } +TEST(ElrondSigner, SignGenericActionUnDelegate) { + auto input = Proto::SigningInput(); + auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + + input.mutable_generic_action()->mutable_accounts()->set_sender_nonce(6); + input.mutable_generic_action()->mutable_accounts()->set_sender("erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa"); + input.mutable_generic_action()->mutable_accounts()->set_receiver("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r"); + input.mutable_generic_action()->set_value("0"); + input.mutable_generic_action()->set_data("unDelegate@" + TW::Elrond::Codec::encodeBigInt("1000000000000000000")); + input.mutable_generic_action()->set_version(1); + input.set_gas_price(1000000000); + input.set_gas_limit(12000000); + input.set_chain_id("1"); + + auto output = Signer::sign(input); + auto signature = output.signature(); + auto encoded = output.encoded(); + auto expectedSignature = "89f9683af92f7b835bff4e1d0dbfcff5245b3367df4d23538eb799e0ad0a90be29ac3bd3598ce55b35b35ebef68bfa5738eed39fd01adc33476f65bd1b966e0b"; + nlohmann::json expected = R"( + { + "chainID":"1", + "data":"dW5EZWxlZ2F0ZUAwZGUwYjZiM2E3NjQwMDAw", + "gasLimit":12000000, + "gasPrice":1000000000, + "nonce":6, + "receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r", + "sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa", + "signature":"89f9683af92f7b835bff4e1d0dbfcff5245b3367df4d23538eb799e0ad0a90be29ac3bd3598ce55b35b35ebef68bfa5738eed39fd01adc33476f65bd1b966e0b", + "value":"0", + "version":1 + })"_json; + assertJSONEqual(expected, nlohmann::json::parse(encoded)); + ASSERT_EQ(expectedSignature, signature); + // Successfully broadcasted https://explorer.elrond.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 +} + +TEST(ElrondSigner, SignGenericActionRedelegateRewards) { + auto input = Proto::SigningInput(); + auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + + input.mutable_generic_action()->mutable_accounts()->set_sender_nonce(7); + input.mutable_generic_action()->mutable_accounts()->set_sender("erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa"); + input.mutable_generic_action()->mutable_accounts()->set_receiver("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r"); + input.mutable_generic_action()->set_value("0"); + input.mutable_generic_action()->set_data("reDelegateRewards"); + input.mutable_generic_action()->set_version(1); + input.set_gas_price(1000000000); + input.set_gas_limit(12000000); + input.set_chain_id("1"); + + auto output = Signer::sign(input); + auto signature = output.signature(); + auto encoded = output.encoded(); + auto expectedSignature = "fc0238d41e4d02a24ac8a502cc3d59e406258b5c186c883e2e9aeffa859a818f5317bf22c9bc6d3838c64529953a46c1d4aabc485f96675a4c4dd642f5f50402"; + nlohmann::json expected = R"( + { + "chainID":"1", + "data":"cmVEZWxlZ2F0ZVJld2FyZHM=", + "gasLimit":12000000, + "gasPrice":1000000000, + "nonce":7, + "receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r", + "sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa", + "signature":"fc0238d41e4d02a24ac8a502cc3d59e406258b5c186c883e2e9aeffa859a818f5317bf22c9bc6d3838c64529953a46c1d4aabc485f96675a4c4dd642f5f50402", + "value":"0", + "version":1 + })"_json; + assertJSONEqual(expected, nlohmann::json::parse(encoded)); + ASSERT_EQ(expectedSignature, signature); +} + +TEST(ElrondSigner, SignGenericActionClaimRewards) { + auto input = Proto::SigningInput(); + auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + + input.mutable_generic_action()->mutable_accounts()->set_sender_nonce(7); + input.mutable_generic_action()->mutable_accounts()->set_sender("erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa"); + input.mutable_generic_action()->mutable_accounts()->set_receiver("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r"); + input.mutable_generic_action()->set_value("0"); + input.mutable_generic_action()->set_data("claimRewards"); + input.mutable_generic_action()->set_version(1); + input.set_gas_price(1000000000); + input.set_gas_limit(6000000); + input.set_chain_id("1"); + + auto output = Signer::sign(input); + auto signature = output.signature(); + auto encoded = output.encoded(); + auto expectedSignature = "c453652214d428045721ad5560194a699ce4194ba7edcbdc1c4f5d1e9a605b82bb0a0fd7dba708322b62518d5d5af3e7380efab0804ac00cdafe7598e7498900"; + nlohmann::json expected = R"( + { + "chainID":"1", + "data":"Y2xhaW1SZXdhcmRz", + "gasLimit":6000000, + "gasPrice":1000000000, + "nonce":7, + "receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r", + "sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa", + "signature":"c453652214d428045721ad5560194a699ce4194ba7edcbdc1c4f5d1e9a605b82bb0a0fd7dba708322b62518d5d5af3e7380efab0804ac00cdafe7598e7498900", + "value":"0", + "version":1 + })"_json; + assertJSONEqual(expected, nlohmann::json::parse(encoded)); + ASSERT_EQ(expectedSignature, signature); +} + +TEST(ElrondSigner, SignGenericActionWithdrawStake) { + auto input = Proto::SigningInput(); + auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + + input.mutable_generic_action()->mutable_accounts()->set_sender_nonce(7); + input.mutable_generic_action()->mutable_accounts()->set_sender("erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa"); + input.mutable_generic_action()->mutable_accounts()->set_receiver("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r"); + input.mutable_generic_action()->set_value("0"); + input.mutable_generic_action()->set_data("withdraw"); + input.mutable_generic_action()->set_version(1); + input.set_gas_price(1000000000); + input.set_gas_limit(12000000); + input.set_chain_id("1"); + + auto output = Signer::sign(input); + auto signature = output.signature(); + auto encoded = output.encoded(); + auto expectedSignature = "a2a17498e78e29082c433c009895bd949fc68b2222620d8f5350f821350cde390c15ffe00df4f0e84a074abd892331b79503bf458a35cb90333d1350553d9302"; + nlohmann::json expected = R"( + { + "chainID":"1", + "data":"d2l0aGRyYXc=", + "gasLimit":12000000, + "gasPrice":1000000000, + "nonce":7, + "receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r", + "sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa", + "signature":"a2a17498e78e29082c433c009895bd949fc68b2222620d8f5350f821350cde390c15ffe00df4f0e84a074abd892331b79503bf458a35cb90333d1350553d9302", + "value":"0", + "version":1 + })"_json; + assertJSONEqual(expected, nlohmann::json::parse(encoded)); + ASSERT_EQ(expectedSignature, signature); + // Need to wait 9 days for broadcasting +} + +TEST(ElrondSigner, SignGenericActionDelegate) { + auto input = Proto::SigningInput(); + auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + + input.mutable_generic_action()->mutable_accounts()->set_sender_nonce(1); + input.mutable_generic_action()->mutable_accounts()->set_sender("erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa"); + input.mutable_generic_action()->mutable_accounts()->set_receiver("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r"); + input.mutable_generic_action()->set_value("1"); + input.mutable_generic_action()->set_data("delegate"); + input.mutable_generic_action()->set_version(1); + input.set_gas_price(1000000000); + input.set_gas_limit(12000000); + input.set_chain_id("1"); + + auto output = Signer::sign(input); + auto signature = output.signature(); + auto encoded = output.encoded(); + auto expectedSignature = "3b9164d47a4e3c0330ae387cd29ba6391f9295acf5e43a16a4a2611645e66e5fa46bf22294ca68fe1948adf45cec8cb47b8792afcdb248bd9adec7c6e6c27108"; + nlohmann::json expected = R"( + { + "chainID":"1", + "data":"ZGVsZWdhdGU=", + "gasLimit":12000000, + "gasPrice":1000000000, + "nonce":1, + "receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r", + "sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa", + "signature":"3b9164d47a4e3c0330ae387cd29ba6391f9295acf5e43a16a4a2611645e66e5fa46bf22294ca68fe1948adf45cec8cb47b8792afcdb248bd9adec7c6e6c27108", + "value":"1", + "version":1 + })"_json; + assertJSONEqual(expected, nlohmann::json::parse(encoded)); + ASSERT_EQ(expectedSignature, signature); + // Successfully broadcasted https://explorer.elrond.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 +} + TEST(ElrondSigner, SignGenericActionJSON) { // Shuffle some fields, assume arbitrary order in the input auto input = (boost::format(R"({"genericAction" : {"accounts": {"senderNonce": 7, "receiver": "%1%", "sender": "%2%"}, "data": "foo", "value": "0", "version": 1}, "gasPrice": 1000000000, "gasLimit": 50000, "chainId": "1"})") % BOB_BECH32 % ALICE_BECH32).str(); From f7217bd0c9ccdba7d6699cfc67887ece4465e1a8 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Wed, 26 Oct 2022 07:00:50 +0200 Subject: [PATCH 121/497] Rust sample app (#2660) --- .github/workflows/linux-sampleapp-ci.yml | 8 +- samples/rust/.gitignore | 6 + samples/rust/Cargo.lock | 333 +++++++++++++++++++++++ samples/rust/Cargo.toml | 16 ++ samples/rust/README.md | 32 +++ samples/rust/src/build.rs | 46 ++++ samples/rust/src/main.rs | 76 ++++++ samples/rust/src/walletcore_extra.rs | 68 +++++ samples/rust/src/walletcore_iface.rs | 169 ++++++++++++ 9 files changed, 753 insertions(+), 1 deletion(-) create mode 100644 samples/rust/.gitignore create mode 100644 samples/rust/Cargo.lock create mode 100644 samples/rust/Cargo.toml create mode 100644 samples/rust/README.md create mode 100644 samples/rust/src/build.rs create mode 100644 samples/rust/src/main.rs create mode 100644 samples/rust/src/walletcore_extra.rs create mode 100644 samples/rust/src/walletcore_iface.rs diff --git a/.github/workflows/linux-sampleapp-ci.yml b/.github/workflows/linux-sampleapp-ci.yml index 3d16471abbd..67bbec223ee 100644 --- a/.github/workflows/linux-sampleapp-ci.yml +++ b/.github/workflows/linux-sampleapp-ci.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v2 - name: Install system dependencies run: | - sudo apt-get update && sudo apt-get install ninja-build llvm-11 libboost-all-dev clang-11 --fix-missing + sudo apt-get update && sudo apt-get install ninja-build llvm-11 libboost-all-dev clang-11 rustc --fix-missing - name: Cache internal dependencies id: internal_cache uses: actions/cache@v1.1.2 @@ -88,3 +88,9 @@ jobs: env: CC: /usr/bin/clang CXX: /usr/bin/clang++ + - name: Build and run Rust sample app + run: | + cd samples/rust + rustc --version + cargo build + cargo run diff --git a/samples/rust/.gitignore b/samples/rust/.gitignore new file mode 100644 index 00000000000..4ff40df7737 --- /dev/null +++ b/samples/rust/.gitignore @@ -0,0 +1,6 @@ +# build directory +target + +# Generated proto files +src/wc_proto/*.rs + diff --git a/samples/rust/Cargo.lock b/samples/rust/Cargo.lock new file mode 100644 index 00000000000..029c2e3f6e7 --- /dev/null +++ b/samples/rust/Cargo.lock @@ -0,0 +1,333 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.135" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "protobuf" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e" +dependencies = [ + "once_cell", + "protobuf-support", + "thiserror", +] + +[[package]] +name = "protobuf-codegen" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd418ac3c91caa4032d37cb80ff0d44e2ebe637b2fb243b6234bf89cdac4901" +dependencies = [ + "anyhow", + "once_cell", + "protobuf", + "protobuf-parse", + "regex", + "tempfile", + "thiserror", +] + +[[package]] +name = "protobuf-parse" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d39b14605eaa1f6a340aec7f320b34064feb26c93aec35d6a9a2272a8ddfa49" +dependencies = [ + "anyhow", + "indexmap", + "log", + "protobuf", + "protobuf-support", + "tempfile", + "thiserror", + "which", +] + +[[package]] +name = "protobuf-support" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372" +dependencies = [ + "thiserror", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rustsample" +version = "1.0.0" +dependencies = [ + "cc", + "hex", + "libc", + "pkg-config", + "protobuf", + "protobuf-codegen", +] + +[[package]] +name = "syn" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "which" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +dependencies = [ + "either", + "libc", + "once_cell", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/samples/rust/Cargo.toml b/samples/rust/Cargo.toml new file mode 100644 index 00000000000..4f27795f435 --- /dev/null +++ b/samples/rust/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "rustsample" +version = "1.0.0" +edition = "2021" +build = "src/build.rs" + +[dependencies] +hex = "0.4.3" +libc = "0.2" +protobuf = "3.2.0" + +[build-dependencies] +cc = { version = "1.0", features = ["parallel"] } +pkg-config = "0.3" +protobuf = "3.2.0" +protobuf-codegen = "3.2.0" diff --git a/samples/rust/README.md b/samples/rust/README.md new file mode 100644 index 00000000000..535990b95c1 --- /dev/null +++ b/samples/rust/README.md @@ -0,0 +1,32 @@ +# Rust Sample Application + +A simple Rust application to how to link and use wallet-core from Rust. + +## Prerequisites + +- Compiled `wallet-core` library +- Rust (`rustc`, `cargo`) + +## Building and Running + +- In the `build.rs` file set the path to the wallet-core folder (by default simply `../..`). + +``` +cargo build +cargo run +``` + +## Some Details + +- The app links with the wallet-core library (C/C++). +- The `walletcore_iface.rs` file contains the interface definitions in Rust. +- Links with `TrustWalletCore`, `TrezorCrypto`, `protobuf`, and the platform libc (`c++` or `stdc++`). Build/link paramaters are in `build.rs`. +- Rust proto files are created during the build process, from the `.proto` files in wallet-core, +into subfolder `src/wc_proto` +(see `build.rs`). +- Notable dependecies: + -- `protobuf` + -- `lib` for C linking + -- `hex` + -- `protobuf-codegen` for generating protobuf source files + diff --git a/samples/rust/src/build.rs b/samples/rust/src/build.rs new file mode 100644 index 00000000000..cb96ab2c9c9 --- /dev/null +++ b/samples/rust/src/build.rs @@ -0,0 +1,46 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +use std::fs; +use std::path::Path; + +// Wallet-core project folder, with sources (proto) and build library binaries +static WALLET_CORE_PROJECT_DIR: &str = "../.."; + +// libs to link with, in reverse dependency order +static LIBS: [&str; 3] = ["TrustWalletCore", "TrezorCrypto", "protobuf"]; + +fn main() { + // Generate protobuf interface files + let proto_src: String = WALLET_CORE_PROJECT_DIR.to_string() + "/src/proto"; + let out_dir: &str = "src/wc_proto"; + + let _create_folder_res = fs::create_dir_all(out_dir); + protobuf_codegen::Codegen::new() + //.protoc() // use `protoc` parser, optional. + .protoc_path(Path::new(&(WALLET_CORE_PROJECT_DIR.to_string() + "/build/local/bin/protoc"))) + .out_dir(out_dir) + .input(proto_src.to_string() + "/Common.proto") + .input(proto_src.to_string() + "/Bitcoin.proto") + .input(proto_src.to_string() + "/Ethereum.proto") + .include(proto_src) + .run() + .expect("Codegen failed."); + println!("Protobuf codegen to {} ready", out_dir); + + println!("cargo:rustc-link-search=native={}/build", WALLET_CORE_PROJECT_DIR); + println!("cargo:rustc-link-search=native={}/build/trezor-crypto", WALLET_CORE_PROJECT_DIR); + + // Libraries; order matters + for i in 0..LIBS.len() { + println!("cargo:rustc-link-lib={}", LIBS[i]); + } + if cfg!(target_os = "macos") { + println!("cargo:rustc-link-lib=c++"); + } else { // "linux", etc + println!("cargo:rustc-link-lib=stdc++"); + } +} diff --git a/samples/rust/src/main.rs b/samples/rust/src/main.rs new file mode 100644 index 00000000000..a2228f5fcb8 --- /dev/null +++ b/samples/rust/src/main.rs @@ -0,0 +1,76 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +pub mod walletcore_iface; +pub mod walletcore_extra; +pub mod wc_proto; + +use crate::walletcore_iface::*; +use crate::walletcore_extra::*; +use crate::wc_proto::Ethereum; +use protobuf::Message; +use hex::ToHex; + +// returns private key +fn get_wallet_info(coin: u32, coin_name: &str, wallet: &HDWallet) -> TWData { + println!("coin {}:", coin_name); + let address = hd_wallet_get_address_for_coin(wallet, coin); + println!(" address: {}", address.to_string()); + + let priv_key = hd_wallet_get_key_for_coin(wallet, coin); + let priv_key_data = private_key_data(&priv_key); + println!(" privkey: {}", priv_key_data.to_hex()); + + let pub_key = private_key_get_public_key_secp256k1(&priv_key, true); + let pub_key_data = public_key_data(&pub_key); + println!(" pubkey: {}", pub_key_data.to_hex()); + + return priv_key_data; +} + +fn main() { + println!("=== Calling wallet-core from Rust"); + + let mnemonic = "confirm bleak useless tail chalk destroy horn step bulb genuine attract split"; + println!("mnemonic is valid: {}", mnemonic_is_valid(&TWString::from_str(mnemonic))); + + let mnemonic_tw = TWString::from_str(mnemonic); + if !mnemonic_is_valid(&mnemonic_tw) { + println!("Mnemonic is invalid! {}", mnemonic); + return; + } + println!("wallet created, mnemonic {}", mnemonic); + let wallet = hd_wallet_create_with_mnemonic(&mnemonic_tw, &TWString::from_str("")); + + get_wallet_info(0, "bitcoin", &wallet); + + let eth_pk = get_wallet_info(60, "ethereum", &wallet); + + // Ethereum transaction + println!("Signing Ethereum transaction"); + let mut signing_input = Ethereum::SigningInput::new(); + signing_input.chain_id = vec!(4); + signing_input.nonce = vec!(0); + signing_input.tx_mode = ::protobuf::EnumOrUnknown::new(Ethereum::TransactionMode::Legacy); + signing_input.gas_price = hex::decode("00174876E800").unwrap(); // 100000000000 100 gwei + signing_input.gas_limit = hex::decode("005208").unwrap(); // 21000 + signing_input.to_address = "0xE9B511C0753649E5F3E78Ed8AdBEE92d0d2Db384".to_string(); + signing_input.private_key = eth_pk.to_vec(); + let mut transfer = Ethereum::transaction::Transfer::new(); + transfer.amount = hex::decode("002386F26FC10000").unwrap(); // 10000000000000000 0.01 + let mut transaction = Ethereum::Transaction::new(); + transaction.transaction_oneof = Some(Ethereum::transaction::Transaction_oneof::Transfer(transfer)); + signing_input.transaction = ::protobuf::MessageField::some(transaction); + + let input_ser = signing_input.write_to_bytes().unwrap(); + let input_ser_data = TWData::from_vec(&input_ser); + + let output_ser_data = any_signer_sign(&input_ser_data, 60); + + let outputp: Ethereum::SigningOutput = protobuf::Message::parse_from_bytes(&output_ser_data.to_vec()).unwrap(); + let x: Vec = outputp.encoded; + println!(" signed tx: {}", x.encode_hex::()); +} diff --git a/samples/rust/src/walletcore_extra.rs b/samples/rust/src/walletcore_extra.rs new file mode 100644 index 00000000000..6f3b1c49e98 --- /dev/null +++ b/samples/rust/src/walletcore_extra.rs @@ -0,0 +1,68 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +// Extra type helpers, traits for wallet-core interfaces + +use crate::walletcore_iface::*; +use hex::ToHex; +use std::ffi::CString; +use std::ffi::CStr; + + +// Some traits +pub trait FromString { + fn from_str(s: &str) -> Self; +} + +pub trait ToVec { + fn to_vec(self: &Self) -> Vec; +} + +pub trait FromVec { + fn from_vec(vec: &Vec) -> Self; +} + +pub trait ToHexString { + fn to_hex(self: &Self) -> String; +} + + +// TWString trait implementations +impl FromString for TWString { + fn from_str(s: &str) -> Self { + let cstring = CString::new(s).unwrap(); + tw_string_create_with_utf8_bytes(cstring.as_ptr()) + } +} + +impl ToString for TWString { + fn to_string(&self) -> String { + let s1 = tw_string_utf8_bytes(&self); + let c_str: &CStr = unsafe { CStr::from_ptr(s1) }; + let str_slice: &str = c_str.to_str().unwrap(); + str_slice.to_owned() + } +} + + +// TWData trait implementations +impl ToVec for TWData { + fn to_vec(&self) -> Vec { + tw_data_bytes(&self) + } +} + +impl FromVec for TWData { + fn from_vec(v: &Vec) -> Self { + tw_data_create_with_bytes(v) + } +} + +impl ToHexString for TWData { + fn to_hex(&self) -> String { + self.to_vec().encode_hex::() + } +} diff --git a/samples/rust/src/walletcore_iface.rs b/samples/rust/src/walletcore_iface.rs new file mode 100644 index 00000000000..5e3a71f8f15 --- /dev/null +++ b/samples/rust/src/walletcore_iface.rs @@ -0,0 +1,169 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +// Rust interfaces to wallet-core +// Could be auto-generated + +use libc::c_char; + +extern "C" { + fn TWStringCreateWithUTF8Bytes(bytes: *const c_char) -> *const u8; + fn TWStringDelete(twstring: *const u8); + fn TWStringUTF8Bytes(twstring: *const u8) -> *const c_char; +} + +pub struct TWString { + wrapped: *const u8 +} + +pub fn tw_string_create_with_utf8_bytes(bytes: *const c_char) -> TWString { + let ptr = unsafe { TWStringCreateWithUTF8Bytes(bytes) }; + TWString { wrapped: ptr } +} + +pub fn tw_string_utf8_bytes(twstring: &TWString) -> *const c_char { + unsafe { TWStringUTF8Bytes(twstring.wrapped) } +} + +impl Drop for TWString { + fn drop(&mut self) { + unsafe { TWStringDelete(self.wrapped) }; + } +} + + +extern "C" { + fn TWDataCreateWithBytes(bytes: *const u8, size: usize) -> *const u8; + fn TWDataDelete(data: *const u8); + fn TWDataSize(data: *const u8) -> usize; + fn TWDataBytes(data: *const u8) -> *const u8; +} + +pub struct TWData { + wrapped: *const u8 +} + +pub fn tw_data_create_with_bytes(bytes: &Vec) -> TWData { + let ptr = unsafe { TWDataCreateWithBytes(bytes.as_ptr(), bytes.len()) }; + TWData { wrapped: ptr } +} + +pub fn tw_data_size(data: &TWData) -> usize { + unsafe { TWDataSize(data.wrapped) } +} + +pub fn tw_data_bytes(data: &TWData) -> Vec { + let size = tw_data_size(data); + let ptr = unsafe { TWDataBytes(data.wrapped) }; + let slice: &[u8] = unsafe { std::slice::from_raw_parts(ptr, size) }; + slice.to_vec() +} + +impl Drop for TWData { + fn drop(&mut self) { + unsafe { TWDataDelete(self.wrapped) }; + } +} + + +extern "C" { + fn TWPrivateKeyData(private_key: *const u8) -> *const u8; + fn TWPrivateKeyGetPublicKeySecp256k1(private_key: *const u8, compressed: bool) -> *const u8; + fn TWPrivateKeyDelete(private_key: *const u8); +} + +pub struct PrivateKey { + wrapped: *const u8 +} + +pub fn private_key_data(private_key: &PrivateKey) -> TWData { + let ptr = unsafe { TWPrivateKeyData(private_key.wrapped) }; + TWData { wrapped: ptr } +} + +pub fn private_key_get_public_key_secp256k1(private_key: &PrivateKey, compressed: bool) -> PublicKey { + let ptr = unsafe { TWPrivateKeyGetPublicKeySecp256k1(private_key.wrapped, compressed) }; + PublicKey { wrapped: ptr } +} + +impl Drop for PrivateKey { + fn drop(&mut self) { + unsafe { TWPrivateKeyDelete(self.wrapped) }; + } +} + + +extern "C" { + fn TWPublicKeyData(public_key: *const u8) -> *const u8; + fn TWPublicKeyDelete(public_key: *const u8); +} + +pub struct PublicKey { + wrapped: *const u8 +} + +pub fn public_key_data(public_key: &PublicKey) -> TWData { + let ptr = unsafe { TWPublicKeyData(public_key.wrapped) }; + TWData { wrapped: ptr } +} + +impl Drop for PublicKey { + fn drop(&mut self) { + unsafe { TWPublicKeyDelete(self.wrapped) }; + } +} + + +extern "C" { + fn TWHDWalletCreateWithMnemonic(mnemonic: *const u8, passphrase: *const u8) -> *const u8; + fn TWHDWalletDelete(wallet: *const u8); + fn TWHDWalletGetAddressForCoin(wallet: *const u8, coin: u32) -> *const u8; + fn TWHDWalletGetKeyForCoin(wallet: *const u8, coin: u32) -> *const u8; +} + +pub struct HDWallet { + wrapped: *const u8 +} + +pub fn hd_wallet_create_with_mnemonic(mnemonic: &TWString, passphrase: &TWString) -> HDWallet { + let ptr = unsafe { TWHDWalletCreateWithMnemonic(mnemonic.wrapped, passphrase.wrapped) }; + HDWallet { wrapped: ptr } +} + +pub fn hd_wallet_get_address_for_coin(wallet: &HDWallet, coin: u32) -> TWString { + let ptr = unsafe { TWHDWalletGetAddressForCoin(wallet.wrapped, coin) }; + TWString { wrapped: ptr } +} + +pub fn hd_wallet_get_key_for_coin(wallet: &HDWallet, coin: u32) -> PrivateKey { + let ptr = unsafe { TWHDWalletGetKeyForCoin(wallet.wrapped, coin) }; + PrivateKey { wrapped: ptr } +} + +impl Drop for HDWallet { + fn drop(&mut self) { + unsafe { TWHDWalletDelete(self.wrapped) }; + } +} + + +extern "C" { + fn TWAnySignerSign(input: *const u8, coin: u32) -> *const u8; +} + +pub fn any_signer_sign(input: &TWData, coin: u32) -> TWData { + let ptr = unsafe { TWAnySignerSign(input.wrapped, coin) }; + TWData { wrapped: ptr } +} + + +extern "C" { + fn TWMnemonicIsValid(mnemonic: *const u8) -> bool; +} + +pub fn mnemonic_is_valid(mnemonic: &TWString) -> bool { + unsafe { TWMnemonicIsValid(mnemonic.wrapped) } +} From d9c02ce4678a92179e7b38d3d8c933b71916d06b Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 26 Oct 2022 18:35:36 +0200 Subject: [PATCH 122/497] [CodeQuality]: Enable sonarcloud on CI run (#2676) --- .github/workflows/linux-ci-sonarcloud.yml | 49 +++++++++++++++++++++++ sonar-project.properties | 7 ++++ src/HDWallet.cpp | 2 +- src/Mnemonic.cpp | 2 +- src/Result.h | 6 +-- src/interface/TWTransactionCompiler.cpp | 12 +++--- tools/sonar-scanner.properties | 9 +++++ tools/sonarcloud-analysis | 9 +++++ 8 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/linux-ci-sonarcloud.yml create mode 100644 sonar-project.properties create mode 100644 tools/sonar-scanner.properties create mode 100755 tools/sonarcloud-analysis diff --git a/.github/workflows/linux-ci-sonarcloud.yml b/.github/workflows/linux-ci-sonarcloud.yml new file mode 100644 index 00000000000..fc69a791607 --- /dev/null +++ b/.github/workflows/linux-ci-sonarcloud.yml @@ -0,0 +1,49 @@ +name: Linux CI SonarCloud + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v2 + - name: Install system dependencies + run: | + # build-essential clang-14 libc++-dev libc++abi-dev ruby-full cmake + sudo apt-get update && sudo apt-get install ninja-build lcov llvm-14 clang-tidy-14 libboost-all-dev --fix-missing + - name: Cache internal dependencies + id: internal_cache + uses: actions/cache@v1.1.2 + with: + path: build/local + key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} + - name: Install internal dependencies + run: | + tools/install-dependencies + env: + CC: /usr/bin/clang + CXX: /usr/bin/clang++ + if: steps.internal_cache.outputs.cache-hit != 'true' + - name: Code generation + run: | + tools/generate-files + env: + CC: /usr/bin/clang + CXX: /usr/bin/clang++ + - name: CMake (coverage/clang-tidy/clang-asan) + run: | + cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DTW_CODE_COVERAGE=ON -DTW_ENABLE_CLANG_TIDY=ON -DTW_CLANG_ASAN=ON -GNinja + cat build/compile_commands.json + env: + CC: /usr/bin/clang + CXX: /usr/bin/clang++ + - name: SonarCloud Scan + run: | + ./tools/sonarcloud-analysis + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 00000000000..ec607dbae00 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,7 @@ +sonar.organization=trustwallet +sonar.projectKey=TrustWallet_wallet-core +sonar.cfamily.compile-commands=build/compile_commands.json +sonar.cfamily.reportingCppStandardOverride=c++20 +sonar.cfamily.cache.enabled=false +sonar.lang.patterns.cpp=**/*.cc,**/*.cpp,**/*.cxx,**/*.c++,**/*.hh,**/*.hpp,**/*.hxx,**/*.h++,**/*.ipp,**/*.h +sonar.lang.patterns.c=**/*.c diff --git a/src/HDWallet.cpp b/src/HDWallet.cpp index 47e84bdec75..db73dc18f9b 100644 --- a/src/HDWallet.cpp +++ b/src/HDWallet.cpp @@ -283,7 +283,7 @@ std::string serialize(const HDNode* node, uint32_t fingerprint, uint32_t version bool deserialize(const std::string& extended, TWCurve curve, Hash::Hasher hasher, HDNode* node) { TW::memzero(node); const char* curveNameStr = curveName(curve); - if (curveNameStr == nullptr || ::strlen(curveNameStr) == 0) { + if (curveNameStr == nullptr || std::string(curveNameStr).empty()) { return false; } node->curve = get_curve_by_name(curveNameStr); diff --git a/src/Mnemonic.cpp b/src/Mnemonic.cpp index 1bff4d76ea7..1ed92d61361 100644 --- a/src/Mnemonic.cpp +++ b/src/Mnemonic.cpp @@ -32,7 +32,7 @@ bool Mnemonic::isValidWord(const std::string& word) { // (i.e., no early exit on match) auto found = false; for (const char* const* w = mnemonicWordlist(); *w != nullptr; ++w) { - if (strlen(*w) == len && strncmp(*w, wordC, len) == 0) { + if (std::string(*w).size() == len && strncmp(*w, wordC, len) == 0) { found = true; } } diff --git a/src/Result.h b/src/Result.h index 1ce611525a1..1f4991c3cc4 100644 --- a/src/Result.h +++ b/src/Result.h @@ -122,10 +122,10 @@ struct Result { E error() const { return get(); } /// Returns a new success result with the given payloadd. - static Result success(T&& val) { return Result(Types::Success(std::forward(val))); } + static Result success(T&& val) { return Result(Types::Success(std::move(val))); } /// Returns a new failure result with the given error. - static Result failure(E&& val) { return Result(Types::Failure(std::forward(val))); } + static Result failure(E&& val) { return Result(Types::Failure(std::move(val))); } static Result failure(E& val) { return Result(Types::Failure(val)); } @@ -171,7 +171,7 @@ struct Result { /// Returns a new failure result with the given error. static Result failure(E&& val) { - return Result(Types::Failure(std::forward(val))); + return Result(Types::Failure(std::move(val))); } operator bool() const { return success_; } diff --git a/src/interface/TWTransactionCompiler.cpp b/src/interface/TWTransactionCompiler.cpp index bd8b6bcf051..0b5b45e52a1 100644 --- a/src/interface/TWTransactionCompiler.cpp +++ b/src/interface/TWTransactionCompiler.cpp @@ -31,13 +31,15 @@ TWData *_Nonnull TWTransactionCompilerBuildInput(enum TWCoinType coinType, TWStr return TWDataCreateWithBytes(result.data(), result.size()); } -std::vector createFromTWDataVector(const struct TWDataVector* _Nonnull dataVector) { +static std::vector createFromTWDataVector(const struct TWDataVector* _Nonnull dataVector) { std::vector ret; const auto n = TWDataVectorSize(dataVector); - for (auto i = 0ul; i < n; ++i) { - auto elem = TWDataVectorGet(dataVector, i); - ret.push_back(*(static_cast(elem))); - TWDataDelete(elem); + for (auto i = 0uL; i < n; ++i) { + const auto* const elem = TWDataVectorGet(dataVector, i); + if (const auto* const data = reinterpret_cast(elem); data) { + ret.emplace_back(*data); + TWDataDelete(elem); + } } return ret; } diff --git a/tools/sonar-scanner.properties b/tools/sonar-scanner.properties new file mode 100644 index 00000000000..08eb8f97091 --- /dev/null +++ b/tools/sonar-scanner.properties @@ -0,0 +1,9 @@ +#Configure here general information about the environment, such as SonarQube server connection details for example +#No information about specific project should appear here + +#----- Default SonarQube server +sonar.host.url=https://sonarcloud.io/ + +#----- Default source code encoding +#sonar.sourceEncoding=UTF-8 + diff --git a/tools/sonarcloud-analysis b/tools/sonarcloud-analysis new file mode 100755 index 00000000000..9ff3a8440e4 --- /dev/null +++ b/tools/sonarcloud-analysis @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +TARGET=sonar-scanner-cli-4.7.0.2747-linux.zip +TARGET_DIR=sonar-scanner-4.7.0.2747-linux +curl https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/${TARGET} --output ${TARGET} +unzip ${TARGET} +cp tools/sonar-scanner.properties ${TARGET_DIR}/conf +chmod +x ${TARGET_DIR}/bin/sonar-scanner +./${TARGET_DIR}/bin/sonar-scanner From d86ccd594de12b01174667fe66c091ad897ff206 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 31 Oct 2022 07:30:21 +0100 Subject: [PATCH 123/497] feat(aptos): fix aptos global variable initialization for wasm (#2689) --- src/Aptos/Address.h | 16 ++++++-- src/Aptos/MoveTypes.h | 12 +++--- tests/chains/Aptos/AddressTests.cpp | 8 ++-- tests/chains/Aptos/MoveTypesTests.cpp | 12 +++--- .../chains/Aptos/TransactionPayloadTests.cpp | 2 +- wasm/tests/Blockchain/Aptos.test.ts | 40 +++++++++++++++++++ 6 files changed, 69 insertions(+), 21 deletions(-) create mode 100644 wasm/tests/Blockchain/Aptos.test.ts diff --git a/src/Aptos/Address.h b/src/Aptos/Address.h index 45fe27aa011..328c387edf4 100644 --- a/src/Aptos/Address.h +++ b/src/Aptos/Address.h @@ -27,6 +27,18 @@ class Address { /// Determines whether a string makes a valid address. static bool isValid(const std::string& string); + static Address zero() { + return Address("0x0"); + } + + static Address one() { + return Address("0x1"); + } + + static Address three() { + return Address("0x3"); + } + /// Initializes an Aptos address with a string representation. explicit Address(const std::string& string); @@ -50,10 +62,6 @@ constexpr inline bool operator==(const Address& lhs, const Address& rhs) noexcep return lhs.bytes == rhs.bytes; } -inline const Address gAddressZero = Address("0x0"); -inline const Address gAddressOne = Address("0x1"); -inline const Address gAddressThree = Address("0x3"); - BCS::Serializer& operator<<(BCS::Serializer& stream, Address) noexcept; } // namespace TW::Aptos diff --git a/src/Aptos/MoveTypes.h b/src/Aptos/MoveTypes.h index c4360afcd83..f9662825921 100644 --- a/src/Aptos/MoveTypes.h +++ b/src/Aptos/MoveTypes.h @@ -33,10 +33,10 @@ class ModuleId { Identifier mName; }; -inline ModuleId gAptosAccountModule{gAddressOne, "aptos_account"}; -inline ModuleId gAptosCoinModule{gAddressOne, "coin"}; -inline ModuleId gAptosManagedCoinsModule{gAddressOne, "managed_coin"}; -inline ModuleId gAptosTokenTransfersModule{gAddressThree, "token_transfers"}; +inline ModuleId gAptosAccountModule{Address::one(), "aptos_account"}; +inline ModuleId gAptosCoinModule{Address::one(), "coin"}; +inline ModuleId gAptosManagedCoinsModule{Address::one(), "managed_coin"}; +inline ModuleId gAptosTokenTransfersModule{Address::three(), "token_transfers"}; BCS::Serializer& operator<<(BCS::Serializer& stream, const ModuleId& module) noexcept; @@ -101,7 +101,7 @@ BCS::Serializer& operator<<(BCS::Serializer& stream, TSigner) noexcept; BCS::Serializer& operator<<(BCS::Serializer& stream, const Vector& t) noexcept; BCS::Serializer& operator<<(BCS::Serializer& stream, const TStructTag& t) noexcept; BCS::Serializer& operator<<(BCS::Serializer& stream, const TypeTag& t) noexcept; -static const TypeTag gTransferTag = {TypeTag::TypeTagVariant(TStructTag{.st = StructTag(gAddressOne, "aptos_coin", "AptosCoin", {})})}; -static const TypeTag gOfferNftTag = {TypeTag::TypeTagVariant(TStructTag{.st = StructTag(gAddressThree, "token_transfers", "offer_script", {})})}; +static const TypeTag gTransferTag = {TypeTag::TypeTagVariant(TStructTag{.st = StructTag(Address::one(), "aptos_coin", "AptosCoin", {})})}; +static const TypeTag gOfferNftTag = {TypeTag::TypeTagVariant(TStructTag{.st = StructTag(Address::three(), "token_transfers", "offer_script", {})})}; } // namespace TW::Aptos diff --git a/tests/chains/Aptos/AddressTests.cpp b/tests/chains/Aptos/AddressTests.cpp index 92f156d077e..1267ea72cdd 100644 --- a/tests/chains/Aptos/AddressTests.cpp +++ b/tests/chains/Aptos/AddressTests.cpp @@ -16,8 +16,8 @@ namespace TW::Aptos::tests { TEST(AptosAddress, Valid) { ASSERT_TRUE(Address::isValid("0x1")); - ASSERT_TRUE(Address::isValid(gAddressOne.string())); - ASSERT_TRUE(Address::isValid(gAddressZero.string())); + ASSERT_TRUE(Address::isValid(Address::one().string())); + ASSERT_TRUE(Address::isValid(Address::zero().string())); ASSERT_TRUE(Address::isValid("0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b")); ASSERT_TRUE(Address::isValid("eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b")); ASSERT_TRUE(Address::isValid("19aadeca9388e009d136245b9a67423f3eee242b03142849eb4f81a4a409e59c")); @@ -47,8 +47,8 @@ TEST(AptosAddress, FromString) { } TEST(AptosAddress, ShortString) { - ASSERT_EQ(gAddressOne.string(), "0x0000000000000000000000000000000000000000000000000000000000000001"); - ASSERT_EQ(gAddressOne.shortString(), "1"); + ASSERT_EQ(Address::one().string(), "0x0000000000000000000000000000000000000000000000000000000000000001"); + ASSERT_EQ(Address::one().shortString(), "1"); } } // namespace TW::Aptos::tests diff --git a/tests/chains/Aptos/MoveTypesTests.cpp b/tests/chains/Aptos/MoveTypesTests.cpp index c2cffeafa9a..3c7fded5d17 100644 --- a/tests/chains/Aptos/MoveTypesTests.cpp +++ b/tests/chains/Aptos/MoveTypesTests.cpp @@ -11,8 +11,8 @@ namespace TW::Aptos::tests { TEST(AptosMoveTypes, ModuleId) { - ModuleId module(gAddressOne, "coin"); - ASSERT_EQ(module.address(), gAddressOne); + ModuleId module(Address::one(), "coin"); + ASSERT_EQ(module.address(), Address::one()); ASSERT_EQ(module.name(), "coin"); ASSERT_EQ(hex(module.accessVector()), "00000000000000000000000000000000000000000000000000000000000000000104636f696e"); ASSERT_EQ(module.string(), "0x0000000000000000000000000000000000000000000000000000000000000001::coin"); @@ -22,9 +22,9 @@ TEST(AptosMoveTypes, ModuleId) { TEST(AptosMoveTypes, StructTag) { auto functorTest = [](T value, const std::string expectedHex) { TypeTag t{.tags = value}; - StructTag st(gAddressOne, "abc", "abc", std::vector{{t}}); + StructTag st(Address::one(), "abc", "abc", std::vector{{t}}); ASSERT_EQ(st.moduleID().name(), "abc"); - ASSERT_EQ(st.moduleID().address(), gAddressOne); + ASSERT_EQ(st.moduleID().address(), Address::one()); ASSERT_EQ(hex(st.serialize()), expectedHex); }; functorTest(Bool{}, "01000000000000000000000000000000000000000000000000000000000000000103616263036162630100"); @@ -34,7 +34,7 @@ TEST(AptosMoveTypes, StructTag) { functorTest(TAddress{}, "01000000000000000000000000000000000000000000000000000000000000000103616263036162630104"); functorTest(TSigner{}, "01000000000000000000000000000000000000000000000000000000000000000103616263036162630105"); functorTest(Vector{.tags = std::vector{{TypeTag{.tags = U8{}}}}}, "0100000000000000000000000000000000000000000000000000000000000000010361626303616263010601"); - StructTag stInner(gAddressOne, "foo", "bar", std::vector{{U8{}}}); + StructTag stInner(Address::one(), "foo", "bar", std::vector{{U8{}}}); functorTest(TStructTag{stInner}, "01000000000000000000000000000000000000000000000000000000000000000103616263036162630107000000000000000000000000000000000000000000000000000000000000000103666f6f036261720101"); } @@ -50,7 +50,7 @@ TEST(AptosMoveTypes, TypeTagDisplay) { functorTest(TypeTag{.tags = TSigner{}}, "signer"); TypeTag t{.tags = TypeTag::TypeTagVariant(Vector{.tags = {{U8{}}}})}; functorTest(t, "vector"); - StructTag st(gAddressOne, "foo", "bar", std::vector{{U8{}}}); + StructTag st(Address::one(), "foo", "bar", std::vector{{U8{}}}); TypeTag anotherT{.tags = TypeTag::TypeTagVariant(st)}; functorTest(anotherT, "0x1::foo::bar"); functorTest(gTransferTag, "0x1::aptos_coin::AptosCoin"); diff --git a/tests/chains/Aptos/TransactionPayloadTests.cpp b/tests/chains/Aptos/TransactionPayloadTests.cpp index 29fd5e3712a..ed393963a06 100644 --- a/tests/chains/Aptos/TransactionPayloadTests.cpp +++ b/tests/chains/Aptos/TransactionPayloadTests.cpp @@ -11,7 +11,7 @@ namespace TW::Aptos::tests { TEST(AptosTransactionPayload, PayLoadBasis) { - ModuleId module(gAddressOne, "coin"); + ModuleId module(Address::one(), "coin"); std::uint64_t amount{1000}; Address to("0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b"); BCS::Serializer serializer; diff --git a/wasm/tests/Blockchain/Aptos.test.ts b/wasm/tests/Blockchain/Aptos.test.ts new file mode 100644 index 00000000000..78486eab2bd --- /dev/null +++ b/wasm/tests/Blockchain/Aptos.test.ts @@ -0,0 +1,40 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import "mocha"; +import { assert } from "chai"; +import { Buffer } from "buffer"; +import { TW } from "../../dist"; +import Long = require("long"); + +describe("Aptos", () => { + it("test sign aptos", () => { + const { PrivateKey, HexCoding, AnySigner, AnyAddress, CoinType } = globalThis.core; + const txDataInput = TW.Aptos.Proto.SigningInput.create({ + chainId: 33, + sender: "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + transfer: TW.Aptos.Proto.TransferMessage.create({ + amount: new Long(1000), + to: "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + }), + sequenceNumber: new Long(99), + expirationTimestampSecs: new Long(3664390082), + gasUnitPrice: new Long(100), + maxGasAmount: new Long(3296766), + privateKey: PrivateKey.createWithData( + HexCoding.decode( + "0x5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec", + ), + ).data(), + }); + const input = TW.Aptos.Proto.SigningInput.encode(txDataInput).finish(); + const outputData = AnySigner.sign(input, CoinType.aptos); + const output = TW.Aptos.Proto.SigningOutput.decode(outputData); + assert.equal(HexCoding.encode(output.encoded), "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada00000000210020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c405707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01") + assert.equal(HexCoding.encode(output.authenticator!.signature), "0x5707246db31e2335edc4316a7a656a11691d1d1647f6e864d1ab12f43428aaaf806cf02120d0b608cdd89c5c904af7b137432aacdd60cc53f9fad7bd33578e01") + assert.equal(HexCoding.encode(output.rawTxn), "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3063000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e7366657200022007968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f3008e803000000000000fe4d3200000000006400000000000000c2276ada0000000021") + }); +}); From 83465cf7a8b669cbccc1f2af63819c3f606bd2d1 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 1 Nov 2022 08:06:17 +0900 Subject: [PATCH 124/497] [Swift] Fix some warnings (#2691) * Fix some warnings in test * set basedOnDependencyAnalysis false --- swift/Tests/TransactionCompilerTests.swift | 8 ++++---- swift/project.yml | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/swift/Tests/TransactionCompilerTests.swift b/swift/Tests/TransactionCompilerTests.swift index b5e147a65f5..05ff08f7457 100644 --- a/swift/Tests/TransactionCompilerTests.swift +++ b/swift/Tests/TransactionCompilerTests.swift @@ -143,8 +143,8 @@ class TransactionCompilerTests: XCTestCase { XCTAssertEqual(preSigningOutput.hashPublicKeys[2].publicKeyHash.hexString, inPubKeyHash0.hexString) // Simulate signatures, normally they are obtained from external source, e.g. a signature server. - var signatureVec = DataVector() - var pubkeyVec = DataVector() + let signatureVec = DataVector() + let pubkeyVec = DataVector() for h in preSigningOutput.hashPublicKeys { let preImageHash = h.dataHash let pubkeyHash = h.publicKeyHash @@ -153,14 +153,14 @@ class TransactionCompilerTests: XCTestCase { XCTAssertTrue(signatureInfos.contains { $0.key == key }) let sigInfo: SignatureInfo = signatureInfos[key]! let publicKeyData = sigInfo.publicKey - let publicKey = PublicKey(data: publicKeyData, type: PublicKeyType.secp256k1) + let publicKey = PublicKey(data: publicKeyData, type: PublicKeyType.secp256k1)! let signature = sigInfo.signature signatureVec.add(data: signature) pubkeyVec.add(data: publicKeyData) // Verify signature (pubkey & hash & signature) - publicKey?.verifyAsDER(signature: signature, message: preImageHash) + XCTAssertTrue(publicKey.verifyAsDER(signature: signature, message: preImageHash)) } /// Step 3: Compile transaction info diff --git a/swift/project.yml b/swift/project.yml index 3d17eb60784..274533d6a6b 100644 --- a/swift/project.yml +++ b/swift/project.yml @@ -60,6 +60,7 @@ targets: fi name: SwiftLint shell: /bin/bash + basedOnDependencyAnalysis: false WalletCoreTests: type: bundle.unit-test From 93465c4f33338f36b3aab93129796269cd3582d2 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Tue, 1 Nov 2022 00:06:38 +0100 Subject: [PATCH 125/497] Update in SmartBCH swift test (#2692) --- .../smartbitcoincash/TestSmartBitcoinCashAddress.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/smartbitcoincash/TestSmartBitcoinCashAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/smartbitcoincash/TestSmartBitcoinCashAddress.kt index 852245d5a05..95acfd23453 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/smartbitcoincash/TestSmartBitcoinCashAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/smartbitcoincash/TestSmartBitcoinCashAddress.kt @@ -20,12 +20,12 @@ class TestSmartBitcoinCashAddress { @Test fun testAddress() { - val key = PrivateKey("ab4accc9310d90a61fc354d8f353bca4a2b3c0590685d3eb82d0216af3badddc".toHexByteArray()) + val key = PrivateKey("155cbd57319f3d938977b4c18000473eb3c432c4e31b667b63e88559c497d82d".toHexByteArray()) val pubkey = key.getPublicKeySecp256k1(false) val address = AnyAddress(pubkey, CoinType.SMARTBITCOINCASH) - val expected = AnyAddress("0xA3Dcd899C0f3832DFDFed9479a9d828c6A4EB2A7", CoinType.SMARTBITCOINCASH) + val expected = AnyAddress("0x8bFC9477684987dcAf0970b9bce5E3D9267C99C0", CoinType.SMARTBITCOINCASH) - assertEquals(pubkey.data().toHex(), "0x0448a9ffac8022f1c7eb5253746e24d11d9b6b2737c0aecd48335feabb95a179916b1f3a97bed6740a85a2d11c663d38566acfb08af48a47ce0c835c65c9b23d0d") + assertEquals(pubkey.data().toHex(), "0x046439f94100c802691c53ef18523be2c24d301f0e2bd3b425e832378a5405eff4331d5e57303785969073321fc76a8504a3854bdb21e6ab7b268a1737882a29c0") assertEquals(address.description(), expected.description()) } } From 469b324177da1cc31e6ec07a4b155c3cbee39127 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 3 Nov 2022 13:08:27 +0100 Subject: [PATCH 126/497] feat(wasm): upgrade mocha version to 10.1.0 and 10.0.0 (#2698) --- wasm/package-lock.json | 189 +++++++++++++++-------------------------- wasm/package.json | 4 +- 2 files changed, 72 insertions(+), 121 deletions(-) diff --git a/wasm/package-lock.json b/wasm/package-lock.json index 8697fe149e1..7647bbb08c3 100644 --- a/wasm/package-lock.json +++ b/wasm/package-lock.json @@ -13,12 +13,12 @@ }, "devDependencies": { "@types/chai": "^4.3.0", - "@types/mocha": "^9.1.0", + "@types/mocha": "^10.0.0", "@types/node": "^18.7.18", "@types/webextension-polyfill": "^0.9.0", "buffer": "^6.0.3", "chai": "^4.3.6", - "mocha": "^9.2.2", + "mocha": "^10.1.0", "ts-node": "^10.7.0", "typescript": "^4.6.3" } @@ -134,9 +134,9 @@ "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, "node_modules/@types/mocha": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", - "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.0.tgz", + "integrity": "sha512-rADY+HtTOA52l9VZWtgQfn4p+UDVM2eDVkMZT1I6syp0YKxW2F9v+0pbRZLsvskhQv/vMb6ZfCay81GHbz5SHg==", "dev": true }, "node_modules/@types/node": { @@ -150,12 +150,6 @@ "integrity": "sha512-HG1y1o2hK8ag6Y7dfkrAbfKmMIP+B0E6SwAzUfmQ1dDxEIdLTtMyrStY26suHBPrAL7Xw/chlDW02ugc3uXWtQ==", "dev": true }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, "node_modules/acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -467,9 +461,9 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -668,15 +662,6 @@ "node": "*" } }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -803,12 +788,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -873,54 +852,60 @@ "dev": true }, "node_modules/minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { "node": ">=10" } }, + "node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/mocha": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", - "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", + "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==", "dev": true, "dependencies": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", - "debug": "4.3.3", + "debug": "4.3.4", "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", "glob": "7.2.0", - "growl": "1.10.5", "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", - "minimatch": "4.2.1", + "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.3.1", + "nanoid": "3.3.3", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", + "workerpool": "6.2.1", "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" }, "bin": { "_mocha": "bin/_mocha", - "mocha": "bin/mocha" + "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 12.0.0" + "node": ">= 14.0.0" }, "funding": { "type": "opencollective", @@ -943,9 +928,9 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" @@ -1261,25 +1246,10 @@ "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", "dev": true }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", "dev": true }, "node_modules/wrap-ansi": { @@ -1484,9 +1454,9 @@ "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, "@types/mocha": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", - "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.0.tgz", + "integrity": "sha512-rADY+HtTOA52l9VZWtgQfn4p+UDVM2eDVkMZT1I6syp0YKxW2F9v+0pbRZLsvskhQv/vMb6ZfCay81GHbz5SHg==", "dev": true }, "@types/node": { @@ -1500,12 +1470,6 @@ "integrity": "sha512-HG1y1o2hK8ag6Y7dfkrAbfKmMIP+B0E6SwAzUfmQ1dDxEIdLTtMyrStY26suHBPrAL7Xw/chlDW02ugc3uXWtQ==", "dev": true }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, "acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -1723,9 +1687,9 @@ "dev": true }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -1862,12 +1826,6 @@ "is-glob": "^4.0.1" } }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1950,12 +1908,6 @@ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2005,41 +1957,49 @@ "dev": true }, "minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + } } }, "mocha": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", - "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", + "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==", "dev": true, "requires": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", - "debug": "4.3.3", + "debug": "4.3.4", "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", "glob": "7.2.0", - "growl": "1.10.5", "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", - "minimatch": "4.2.1", + "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.3.1", + "nanoid": "3.3.3", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", + "workerpool": "6.2.1", "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" @@ -2060,9 +2020,9 @@ "dev": true }, "nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", "dev": true }, "normalize-path": { @@ -2264,19 +2224,10 @@ "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", "dev": true }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, "workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", "dev": true }, "wrap-ansi": { diff --git a/wasm/package.json b/wasm/package.json index 8ae7e3f0b3b..eafc3845ed4 100644 --- a/wasm/package.json +++ b/wasm/package.json @@ -34,12 +34,12 @@ }, "devDependencies": { "@types/chai": "^4.3.0", - "@types/mocha": "^9.1.0", + "@types/mocha": "^10.0.0", "@types/node": "^18.7.18", "@types/webextension-polyfill": "^0.9.0", "buffer": "^6.0.3", "chai": "^4.3.6", - "mocha": "^9.2.2", + "mocha": "^10.1.0", "ts-node": "^10.7.0", "typescript": "^4.6.3" } From 748d5a745b61e48665ae4ca122f26269363080db Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 3 Nov 2022 17:29:35 +0100 Subject: [PATCH 127/497] [Solana]: add unsigned_tx support (#2699) * feat(solana): add unsigned_tx base58 to SigningOutput --- src/Solana/Signer.cpp | 3 +++ src/proto/Solana.proto | 3 +++ tests/chains/Solana/TWAnySignerTests.cpp | 1 + 3 files changed, 7 insertions(+) diff --git a/src/Solana/Signer.cpp b/src/Solana/Signer.cpp index f5839bc0e8f..e14351939fd 100644 --- a/src/Solana/Signer.cpp +++ b/src/Solana/Signer.cpp @@ -173,6 +173,9 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto encoded = transaction.serialize(); protoOutput.set_encoded(encoded); + auto unsignedTx = Base58::bitcoin.encode(transaction.messageData()); + protoOutput.set_unsigned_tx(unsignedTx.data(), unsignedTx.size()); + return protoOutput; } diff --git a/src/proto/Solana.proto b/src/proto/Solana.proto index 0f7280b5da3..07fb6a00f58 100644 --- a/src/proto/Solana.proto +++ b/src/proto/Solana.proto @@ -156,4 +156,7 @@ message SigningInput { message SigningOutput { // The encoded transaction string encoded = 1; + + // The unsigned transaction + string unsigned_tx = 2; } diff --git a/tests/chains/Solana/TWAnySignerTests.cpp b/tests/chains/Solana/TWAnySignerTests.cpp index 8246f8f48ce..5fd474bbf0e 100644 --- a/tests/chains/Solana/TWAnySignerTests.cpp +++ b/tests/chains/Solana/TWAnySignerTests.cpp @@ -38,6 +38,7 @@ TEST(TWAnySignerSolana, SignTransfer) { ANY_SIGN(input, TWCoinTypeSolana); ASSERT_EQ(output.encoded(), expectedString1); + ASSERT_EQ(output.unsigned_tx(), "87PYsiS4MUU1UqXrsDoCBmD5FcKsXhwEBD8hc4zbq78yePu7bLENmbnmjmVbsj4VvaxnZhy4bERndPFzjSRH5WpwKwMLSCKvn9eSDmPESNcdkqne2UdMfWiFoq8ZeQBnF9h98dP8GM9kfzWPjvLmhjwuwA1E2k5WCtfii7LKQ34v6AtmFQGZqgdKiNqygP7ZKusHWGT8ZkTZ"); } TEST(TWAnySignerSolana, SignTransferToSelf) { From 6d452504d9ca4403a3923cd7879ccc4a871b0c0d Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Fri, 4 Nov 2022 14:12:48 +0100 Subject: [PATCH 128/497] Expose derivation option in AnyAddress, HDWallet (#2683) * Expose derivation option on TWAnyAddressCreateWithPublicKey * Expose derivation option on TWHDWalletGetKey * HDWalletGetAddressDerivation: expose derivation in wallet.getAddress * Devconsole: update wc lib to latest * New sample script for devConsole * Use \see in comments * Swift test for AnyAddress * Swift test for new HDWallet methods * Kotlin test for new HDWallet methods * PublicKeyType fix * Review: assertStringsEqual(), const rename. --- .../core/app/utils/TestAnyAddress.kt | 92 +++++++++++++++++++ .../core/app/utils/TestHDWallet.kt | 54 +++++++++++ include/TrustWalletCore/TWAnyAddress.h | 9 ++ include/TrustWalletCore/TWHDWallet.h | 33 ++++++- .../devconsole.ts/package-lock.json | 14 +-- samples/typescript/devconsole.ts/package.json | 2 +- .../bitcoin.addresses.sampleinput.txt | 19 ++++ src/AnyAddress.cpp | 8 +- src/AnyAddress.h | 4 +- src/interface/TWAnyAddress.cpp | 5 + src/interface/TWHDWallet.cpp | 18 +++- swift/Tests/AnyAddressTests.swift | 69 ++++++++++++++ swift/Tests/HDWalletTests.swift | 44 ++++++++- tests/common/AnyAddressTests.cpp | 13 +++ tests/interface/TWAnyAddressTests.cpp | 38 +++++++- tests/interface/TWHDWalletTests.cpp | 32 ++++++- 16 files changed, 427 insertions(+), 27 deletions(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestAnyAddress.kt create mode 100644 samples/typescript/devconsole.ts/samplescripts/bitcoin.addresses.sampleinput.txt create mode 100644 swift/Tests/AnyAddressTests.swift diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestAnyAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestAnyAddress.kt new file mode 100644 index 00000000000..64b3bb82987 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestAnyAddress.kt @@ -0,0 +1,92 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.utils + +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import wallet.core.jni.* +import java.security.InvalidParameterException +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Assert.fail +import org.junit.Test + +class TestAnyAddress { + init { + System.loadLibrary("TrustWalletCore"); + } + + val any_address_test_address = "bc1qcj2vfjec3c3luf9fx9vddnglhh9gawmncmgxhz" + val any_address_test_pubkey = "02753f5c275e1847ba4d2fd3df36ad00af2e165650b35fe3991e9c9c46f68b12bc" + + @Test + fun testCreateWithString() { + val coin = CoinType.BITCOIN + val address = AnyAddress(any_address_test_address, coin) + assertEquals(address.coin(), coin) + assertEquals(address.description(), any_address_test_address) + } + + @Test + fun testCreateWithStringBech32() { + val coin = CoinType.BITCOIN + val address1 = AnyAddress(any_address_test_address, coin, "bc") + assertEquals(address1.description(), any_address_test_address) + + val address2 = AnyAddress("tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3", coin, "tb") + assertEquals(address2.description(), "tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3") + } + + @Test + fun testCreateWithPublicKey() { + val coin = CoinType.BITCOIN + val pubkey = PublicKey(any_address_test_pubkey.toHexByteArray(), PublicKeyType.SECP256K1) + val address = AnyAddress(pubkey, coin) + assertEquals(address.description(), any_address_test_address) + } + + @Test + fun testCreateWithPublicKeyDerivation() { + val coin = CoinType.BITCOIN + val pubkey = PublicKey(any_address_test_pubkey.toHexByteArray(), PublicKeyType.SECP256K1) + val address1 = AnyAddress(pubkey, coin, Derivation.BITCOINSEGWIT) + assertEquals(address1.description(), any_address_test_address) + + val address2 = AnyAddress(pubkey, coin, Derivation.BITCOINLEGACY) + assertEquals(address2.description(), "1JvRfEQFv5q5qy9uTSAezH7kVQf4hqnHXx") + } + + @Test + fun testCreateBech32WithPublicKey() { + val coin = CoinType.BITCOIN + val pubkey = PublicKey(any_address_test_pubkey.toHexByteArray(), PublicKeyType.SECP256K1) + val address1 = AnyAddress(pubkey, coin, "bc") + assertEquals(address1.description(), any_address_test_address) + + val address2 = AnyAddress(pubkey, coin, "tb") + assertEquals(address2.description(), "tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3") + } + + @Test + fun testIsValid() { + val coin = CoinType.BITCOIN + assertTrue(AnyAddress.isValid(any_address_test_address, coin)); + assertFalse(AnyAddress.isValid(any_address_test_address, CoinType.ETHEREUM)); + assertFalse(AnyAddress.isValid("__INVALID_ADDRESS__", CoinType.ETHEREUM)); + } + + @Test + fun testIsValidBech32() { + val coin = CoinType.BITCOIN + assertTrue(AnyAddress.isValidBech32(any_address_test_address, coin, "bc")); + assertFalse(AnyAddress.isValidBech32(any_address_test_address, coin, "tb")); + assertTrue(AnyAddress.isValidBech32("tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3", coin, "tb")); + assertFalse(AnyAddress.isValidBech32("tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3", coin, "bc")); + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt index 0d85be821d8..ed1c171aa6b 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt @@ -1,8 +1,16 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + package com.trustwallet.core.app.utils import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHex import wallet.core.jni.CoinType import wallet.core.jni.Curve +import wallet.core.jni.Derivation import wallet.core.jni.HDVersion import wallet.core.jni.HDWallet import wallet.core.jni.Mnemonic @@ -65,6 +73,52 @@ class TestHDWallet { assertEquals(Numeric.toHexString(hd.entropy()), "0xba5821e8c356c05ba5f025d9532fe0f21f65d594") } + @Test + fun testGetKeyForCoin() { + val coin = CoinType.BITCOIN + val wallet = HDWallet(words, password) + val key = wallet.getKeyForCoin(coin) + + val address = coin.deriveAddress(key) + assertEquals(address, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85") + } + + @Test + fun testGetKeyDerivation() { + val coin = CoinType.BITCOIN + val wallet = HDWallet(words, password) + + val key1 = wallet.getKeyDerivation(coin, Derivation.BITCOINSEGWIT) + assertEquals(key1.data().toHex(), "0x1901b5994f075af71397f65bd68a9fff8d3025d65f5a2c731cf90f5e259d6aac") + + val key2 = wallet.getKeyDerivation(coin, Derivation.BITCOINLEGACY) + assertEquals(key2.data().toHex(), "0x28071bf4e2b0340db41b807ed8a5514139e5d6427ff9d58dbd22b7ed187103a4") + + val key3 = wallet.getKeyDerivation(coin, Derivation.BITCOINTESTNET) + assertEquals(key3.data().toHex(), "0xca5845e1b43e3adf577b7f110b60596479425695005a594c88f9901c3afe864f") + } + + @Test + fun testGetAddressForCoin() { + val coin = CoinType.BITCOIN + val wallet = HDWallet(words, password) + + val address = wallet.getAddressForCoin(coin) + assertEquals(address, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85") + } + + @Test + fun testGetAddressDerivation() { + val coin = CoinType.BITCOIN + val wallet = HDWallet(words, password) + + val address1 = wallet.getAddressDerivation(coin, Derivation.BITCOINSEGWIT) + assertEquals(address1, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85") + + val address2 = wallet.getAddressDerivation(coin, Derivation.BITCOINLEGACY) + assertEquals(address2, "1PeUvjuxyf31aJKX6kCXuaqxhmG78ZUdL1") + } + @Test fun testDerive() { val wallet = HDWallet(words, password) diff --git a/include/TrustWalletCore/TWAnyAddress.h b/include/TrustWalletCore/TWAnyAddress.h index 86dcdc51bd9..652d4994529 100644 --- a/include/TrustWalletCore/TWAnyAddress.h +++ b/include/TrustWalletCore/TWAnyAddress.h @@ -88,6 +88,15 @@ struct TWAnyAddress* _Nullable TWAnyAddressCreateSS58(TWString* _Nonnull string, TW_EXPORT_STATIC_METHOD struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKey(struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin); +/// Creates an address from a public key and derivation option. +/// +/// \param publicKey derivates the address from the public key. +/// \param coin coin type of the address. +/// \param derivation the custom derivation to use. +/// \return TWAnyAddress pointer or nullptr if public key is invalid. +TW_EXPORT_STATIC_METHOD +struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKeyDerivation(struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin, enum TWDerivation derivation); + /// Creates an bech32 address from a public key and a given hrp. /// /// \param publicKey derivates the address from the public key. diff --git a/include/TrustWalletCore/TWHDWallet.h b/include/TrustWalletCore/TWHDWallet.h index 55ab3e13b4a..a6261f57a7b 100644 --- a/include/TrustWalletCore/TWHDWallet.h +++ b/include/TrustWalletCore/TWHDWallet.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -100,8 +100,10 @@ TWData* _Nonnull TWHDWalletEntropy(struct TWHDWallet* _Nonnull wallet); TW_EXPORT_METHOD struct TWPrivateKey* _Nonnull TWHDWalletGetMasterKey(struct TWHDWallet* _Nonnull wallet, enum TWCurve curve); -/// Generates the default private key for the specified coin. +/// Generates the default private key for the specified coin, using default derivation. /// +/// \see TWHDWalletGetKey +/// \see TWHDWalletGetKeyDerivation /// \param wallet non-null TWHDWallet /// \param coin a coin type /// \note Returned object needs to be deleted with \TWPrivateKeyDelete @@ -109,16 +111,29 @@ struct TWPrivateKey* _Nonnull TWHDWalletGetMasterKey(struct TWHDWallet* _Nonnull TW_EXPORT_METHOD struct TWPrivateKey* _Nonnull TWHDWalletGetKeyForCoin(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin); -/// Generates the default address for the specified coin (without exposing intermediary private key). +/// Generates the default address for the specified coin (without exposing intermediary private key), default derivation. /// +/// \see TWHDWalletGetAddressDerivation /// \param wallet non-null TWHDWallet /// \param coin a coin type /// \return return the default address for the specified coin as a non-null TWString TW_EXPORT_METHOD TWString* _Nonnull TWHDWalletGetAddressForCoin(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin); +/// Generates the default address for the specified coin and derivation (without exposing intermediary private key). +/// +/// \see TWHDWalletGetAddressForCoin +/// \param wallet non-null TWHDWallet +/// \param coin a coin type +/// \param derivation a (custom) derivation to use +/// \return return the default address for the specified coin as a non-null TWString +TW_EXPORT_METHOD +TWString* _Nonnull TWHDWalletGetAddressDerivation(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin, enum TWDerivation derivation); + /// Generates the private key for the specified derivation path. /// +/// \see TWHDWalletGetKeyForCoin +/// \see TWHDWalletGetKeyDerivation /// \param wallet non-null TWHDWallet /// \param coin a coin type /// \param derivationPath a non-null derivation path @@ -127,6 +142,18 @@ TWString* _Nonnull TWHDWalletGetAddressForCoin(struct TWHDWallet* _Nonnull walle TW_EXPORT_METHOD struct TWPrivateKey* _Nonnull TWHDWalletGetKey(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin, TWString* _Nonnull derivationPath); +/// Generates the private key for the specified derivation. +/// +/// \see TWHDWalletGetKey +/// \see TWHDWalletGetKeyForCoin +/// \param wallet non-null TWHDWallet +/// \param coin a coin type +/// \param derivation a (custom) derivation to use +/// \note Returned object needs to be deleted with \TWPrivateKeyDelete +/// \return The private key for the specified derivation path/coin +TW_EXPORT_METHOD +struct TWPrivateKey* _Nonnull TWHDWalletGetKeyDerivation(struct TWHDWallet* _Nonnull wallet, enum TWCoinType coin, enum TWDerivation derivation); + /// Generates the private key for the specified derivation path and curve. /// /// \param wallet non-null TWHDWallet diff --git a/samples/typescript/devconsole.ts/package-lock.json b/samples/typescript/devconsole.ts/package-lock.json index 50046ba9ab4..ce8a4ecf0ee 100644 --- a/samples/typescript/devconsole.ts/package-lock.json +++ b/samples/typescript/devconsole.ts/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "license": "MIT", "dependencies": { - "@trustwallet/wallet-core": "3.0.4", + "@trustwallet/wallet-core": "3.0.8", "chalk": "^4.1.2", "clear": "^0.1.0", "figlet": "^1.5.2", @@ -116,9 +116,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@trustwallet/wallet-core": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.4.tgz", - "integrity": "sha512-FrIVEwRmUYFuwU9IoXg0J8fngeW7nlJZZAsrnOWba2g/yGWZl4FQ4z87MEQ5ROOGW9jJzsdWG4PRZffvYzhqsg==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.8.tgz", + "integrity": "sha512-u0ST2xZL6oWCAMmZRKQVxBLhNtOu/tYByVl9OEfd8SbAGHVjW/6V+oVmHAqBL/z3fwfZfYg2LY08AW831ZNwoQ==", "dependencies": { "protobufjs": ">=6.11.3" } @@ -964,9 +964,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "@trustwallet/wallet-core": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.4.tgz", - "integrity": "sha512-FrIVEwRmUYFuwU9IoXg0J8fngeW7nlJZZAsrnOWba2g/yGWZl4FQ4z87MEQ5ROOGW9jJzsdWG4PRZffvYzhqsg==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@trustwallet/wallet-core/-/wallet-core-3.0.8.tgz", + "integrity": "sha512-u0ST2xZL6oWCAMmZRKQVxBLhNtOu/tYByVl9OEfd8SbAGHVjW/6V+oVmHAqBL/z3fwfZfYg2LY08AW831ZNwoQ==", "requires": { "protobufjs": ">=6.11.3" } diff --git a/samples/typescript/devconsole.ts/package.json b/samples/typescript/devconsole.ts/package.json index 7ca581061d5..64e52dc3f10 100644 --- a/samples/typescript/devconsole.ts/package.json +++ b/samples/typescript/devconsole.ts/package.json @@ -14,7 +14,7 @@ "author": "Trust Wallet", "license": "MIT", "dependencies": { - "@trustwallet/wallet-core": "3.0.4", + "@trustwallet/wallet-core": "3.0.8", "chalk": "^4.1.2", "clear": "^0.1.0", "figlet": "^1.5.2", diff --git a/samples/typescript/devconsole.ts/samplescripts/bitcoin.addresses.sampleinput.txt b/samples/typescript/devconsole.ts/samplescripts/bitcoin.addresses.sampleinput.txt new file mode 100644 index 00000000000..9c7201110a7 --- /dev/null +++ b/samples/typescript/devconsole.ts/samplescripts/bitcoin.addresses.sampleinput.txt @@ -0,0 +1,19 @@ +// Derive Bitcoin addresses of different flavor + +coin = CoinType.bitcoin + +privKeyData = '0xafeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5'; +privKey = PrivateKey.createWithData(HexCoding.decode(privKeyData)); +pubKey = privKey.getPublicKeySecp256k1(true); +address11 = SegwitAddress.createWithPublicKey(HRP.bitcoin, pubKey).description(); + +// This is not yet possible yet through AnyAddress +// TWAnyAddressCreateWithPublicKeyDerivation +address21 = AnyAddress.createWithPublicKey(pubKey, coin); +address21.description() + +// This is not yet possible yet through HDWallet +// TWHDWalletGetKeyDerivation +// TWHDWalletGetAddressDerivation +wallet = HDWallet.createWithMnemonic('ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal', ''); +address = wallet.getAddressForCoin(coin); diff --git a/src/AnyAddress.cpp b/src/AnyAddress.cpp index be44ccb2e95..bf0fb994b98 100644 --- a/src/AnyAddress.cpp +++ b/src/AnyAddress.cpp @@ -25,15 +25,15 @@ AnyAddress* AnyAddress::createAddress(const std::string& address, enum TWCoinTyp return new AnyAddress{.address = std::move(normalized), .coin = coin}; } -AnyAddress* AnyAddress::createAddress(const PublicKey& publicKey, enum TWCoinType coin, const std::string& hrp) { +AnyAddress* AnyAddress::createAddress(const PublicKey& publicKey, enum TWCoinType coin, const std::string& hrp, TWDerivation derivation) { - auto derivedAddress = TW::deriveAddress(coin, publicKey, TWDerivationDefault, hrp); + auto derivedAddress = TW::deriveAddress(coin, publicKey, derivation, hrp); return new AnyAddress{.address = std::move(derivedAddress), .coin = coin}; } -AnyAddress* AnyAddress::createAddress(const PublicKey& publicKey, enum TWCoinType coin, const PrefixVariant& addressPrefix) { +AnyAddress* AnyAddress::createAddress(const PublicKey& publicKey, enum TWCoinType coin, const PrefixVariant& addressPrefix, TWDerivation derivation) { - auto derivedAddress = TW::deriveAddress(coin, publicKey, addressPrefix); + auto derivedAddress = TW::deriveAddress(coin, publicKey, addressPrefix, derivation); return new AnyAddress{.address = std::move(derivedAddress), .coin = coin}; } diff --git a/src/AnyAddress.h b/src/AnyAddress.h index a40be466a8e..e78f3d67a7c 100644 --- a/src/AnyAddress.h +++ b/src/AnyAddress.h @@ -24,8 +24,8 @@ class AnyAddress { enum TWCoinType coin; static AnyAddress* createAddress(const std::string& address, enum TWCoinType coin, const PrefixVariant& prefix = std::monostate()); - static AnyAddress* createAddress(const PublicKey& publicKey, enum TWCoinType coin, const std::string& hrp = ""); - static AnyAddress* createAddress(const PublicKey& publicKey, enum TWCoinType coin, const PrefixVariant& prefix); + static AnyAddress* createAddress(const PublicKey& publicKey, enum TWCoinType coin, const std::string& hrp = "", TWDerivation derivation = TWDerivationDefault); + static AnyAddress* createAddress(const PublicKey& publicKey, enum TWCoinType coin, const PrefixVariant& prefix, TWDerivation derivation = TWDerivationDefault); Data getData() const; }; diff --git a/src/interface/TWAnyAddress.cpp b/src/interface/TWAnyAddress.cpp index d67496008d4..4f4713679ed 100644 --- a/src/interface/TWAnyAddress.cpp +++ b/src/interface/TWAnyAddress.cpp @@ -68,6 +68,11 @@ struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKey( return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin)}; } +struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKeyDerivation( + struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin, enum TWDerivation derivation) { + return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin, std::string(""), derivation)}; +} + struct TWAnyAddress* _Nonnull TWAnyAddressCreateBech32WithPublicKey( struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin, TWString* _Nonnull hrp) { const auto& hrpStr = *reinterpret_cast(hrp); diff --git a/src/interface/TWHDWallet.cpp b/src/interface/TWHDWallet.cpp index 18447aa54bd..630b0613110 100644 --- a/src/interface/TWHDWallet.cpp +++ b/src/interface/TWHDWallet.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -67,14 +67,17 @@ struct TWPrivateKey *_Nonnull TWHDWalletGetMasterKey(struct TWHDWallet *_Nonnull } struct TWPrivateKey *_Nonnull TWHDWalletGetKeyForCoin(struct TWHDWallet *wallet, TWCoinType coin) { - auto derivationPath = TW::derivationPath(coin); - return new TWPrivateKey{ wallet->impl.getKey(coin, derivationPath) }; + return TWHDWalletGetKeyDerivation(wallet, coin, TWDerivationDefault); } TWString *_Nonnull TWHDWalletGetAddressForCoin(struct TWHDWallet *wallet, TWCoinType coin) { - auto derivationPath = TW::derivationPath(coin); + return TWHDWalletGetAddressDerivation(wallet, coin, TWDerivationDefault); +} + +TWString *_Nonnull TWHDWalletGetAddressDerivation(struct TWHDWallet *wallet, TWCoinType coin, enum TWDerivation derivation) { + auto derivationPath = TW::derivationPath(coin, derivation); PrivateKey privateKey = wallet->impl.getKey(coin, derivationPath); - std::string address = deriveAddress(coin, privateKey); + std::string address = deriveAddress(coin, privateKey, derivation); return TWStringCreateWithUTF8Bytes(address.c_str()); } @@ -84,6 +87,11 @@ struct TWPrivateKey *_Nonnull TWHDWalletGetKey(struct TWHDWallet *_Nonnull walle return new TWPrivateKey{ wallet->impl.getKey(coin, path) }; } +struct TWPrivateKey *_Nonnull TWHDWalletGetKeyDerivation(struct TWHDWallet *_Nonnull wallet, enum TWCoinType coin, enum TWDerivation derivation) { + auto derivationPath = TW::derivationPath(coin, derivation); + return new TWPrivateKey{ wallet->impl.getKey(coin, derivationPath) }; +} + struct TWPrivateKey *_Nonnull TWHDWalletGetDerivedKey(struct TWHDWallet *_Nonnull wallet, enum TWCoinType coin, uint32_t account, uint32_t change, uint32_t address) { const auto derivationPath = DerivationPath(TW::purpose(coin), TW::slip44Id(coin), account, change, address); return new TWPrivateKey{ wallet->impl.getKey(coin, derivationPath) }; diff --git a/swift/Tests/AnyAddressTests.swift b/swift/Tests/AnyAddressTests.swift new file mode 100644 index 00000000000..dc4f16da527 --- /dev/null +++ b/swift/Tests/AnyAddressTests.swift @@ -0,0 +1,69 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import WalletCore +import XCTest + +class AnyAddressTests: XCTestCase { + let any_address_test_address = "bc1qcj2vfjec3c3luf9fx9vddnglhh9gawmncmgxhz" + let any_address_test_pubkey = "02753f5c275e1847ba4d2fd3df36ad00af2e165650b35fe3991e9c9c46f68b12bc" + + func testCreateWithString() { + let coin = CoinType.bitcoin + let address = AnyAddress(string: any_address_test_address, coin: coin)! + XCTAssertEqual(address.coin, coin) + XCTAssertEqual(address.description, any_address_test_address) + } + + func testCreateWithStringBech32() { + let coin = CoinType.bitcoin + let address1 = AnyAddress(string: any_address_test_address, coin: coin, hrp: "bc")! + XCTAssertEqual(address1.description, any_address_test_address) + + let address2 = AnyAddress(string: "tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3", coin: coin, hrp: "tb")! + XCTAssertEqual(address2.description, "tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3") + } + + func testCreateWithPublicKey() { + let coin = CoinType.bitcoin + let pubkey = PublicKey(data: Data(hexString: any_address_test_pubkey)!, type: .secp256k1)! + let address = AnyAddress(publicKey: pubkey, coin: coin) + XCTAssertEqual(address.description, any_address_test_address) + } + + func testCreateWithPublicKeyDerivation() { + let coin = CoinType.bitcoin + let pubkey = PublicKey(data: Data(hexString: any_address_test_pubkey)!, type: .secp256k1)! + let address1 = AnyAddress(publicKey: pubkey, coin: coin, derivation: .bitcoinSegwit) + XCTAssertEqual(address1.description, any_address_test_address) + + let address2 = AnyAddress(publicKey: pubkey, coin: coin, derivation: .bitcoinLegacy) + XCTAssertEqual(address2.description, "1JvRfEQFv5q5qy9uTSAezH7kVQf4hqnHXx") + } + + func testCreateBech32WithPublicKey() { + let coin = CoinType.bitcoin + let pubkey = PublicKey(data: Data(hexString: any_address_test_pubkey)!, type: .secp256k1)! + let address1 = AnyAddress(publicKey: pubkey, coin: coin, hrp: "bc") + XCTAssertEqual(address1.description, any_address_test_address) + + let address2 = AnyAddress(publicKey: pubkey, coin: coin, hrp: "tb") + XCTAssertEqual(address2.description, "tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3") + } + + func testIsValid() { + let coin = CoinType.bitcoin + XCTAssertTrue(AnyAddress.isValid(string: any_address_test_address, coin: coin)); + XCTAssertFalse(AnyAddress.isValid(string: any_address_test_address, coin: .ethereum)); + XCTAssertFalse(AnyAddress.isValid(string: "__INVALID_ADDRESS__", coin: .ethereum)); + } + + func testIsValidBech32() { + let coin = CoinType.bitcoin + XCTAssertTrue(AnyAddress.isValidBech32(string: any_address_test_address, coin: coin, hrp: "bc")); + XCTAssertFalse(AnyAddress.isValidBech32(string: any_address_test_address, coin: coin, hrp: "tb")); + } +} diff --git a/swift/Tests/HDWalletTests.swift b/swift/Tests/HDWalletTests.swift index e6e5b8b6b46..cc832c55a7e 100644 --- a/swift/Tests/HDWalletTests.swift +++ b/swift/Tests/HDWalletTests.swift @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -49,6 +49,48 @@ class HDWalletTests: XCTestCase { XCTAssertEqual(masterKey.data.hexString, "e120fc1ef9d193a851926ebd937c3985dc2c4e642fb3d0832317884d5f18f3b3") } + func testGetKeyForCoin() { + let coin = CoinType.bitcoin + let wallet = HDWallet.test + let key = wallet.getKeyForCoin(coin: coin) + + let address = coin.deriveAddress(privateKey: key) + XCTAssertEqual(address, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85") + } + + func testGetKeyDerivation() { + let coin = CoinType.bitcoin + let wallet = HDWallet.test + + let key1 = wallet.getKeyDerivation(coin: coin, derivation: .bitcoinSegwit) + XCTAssertEqual(key1.data.hexString, "1901b5994f075af71397f65bd68a9fff8d3025d65f5a2c731cf90f5e259d6aac") + + let key2 = wallet.getKeyDerivation(coin: coin, derivation: .bitcoinLegacy) + XCTAssertEqual(key2.data.hexString, "28071bf4e2b0340db41b807ed8a5514139e5d6427ff9d58dbd22b7ed187103a4") + + let key3 = wallet.getKeyDerivation(coin: coin, derivation: .bitcoinTestnet) + XCTAssertEqual(key3.data.hexString, "ca5845e1b43e3adf577b7f110b60596479425695005a594c88f9901c3afe864f") + } + + func testGetAddressForCoin() { + let coin = CoinType.bitcoin + let wallet = HDWallet.test + + let address = wallet.getAddressForCoin(coin: coin) + XCTAssertEqual(address, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85") + } + + func testGetAddressDerivation() { + let coin = CoinType.bitcoin + let wallet = HDWallet.test + + let address1 = wallet.getAddressDerivation(coin: coin, derivation: .bitcoinSegwit) + XCTAssertEqual(address1, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85") + + let address2 = wallet.getAddressDerivation(coin: coin, derivation: .bitcoinLegacy) + XCTAssertEqual(address2, "1PeUvjuxyf31aJKX6kCXuaqxhmG78ZUdL1") + } + func testDerive() { let wallet = HDWallet.test diff --git a/tests/common/AnyAddressTests.cpp b/tests/common/AnyAddressTests.cpp index bc7dc5af2b2..917bd0ca07d 100644 --- a/tests/common/AnyAddressTests.cpp +++ b/tests/common/AnyAddressTests.cpp @@ -26,6 +26,19 @@ TEST(AnyAddress, createFromPubKey) { EXPECT_EQ(ANY_ADDRESS_TEST_ADDRESS, addr->address); } +TEST(AnyAddress, createFromPubKeyDerivation) { + const Data key = parse_hex(ANY_ADDRESS_TEST_PUBKEY); + PublicKey publicKey(key, TWPublicKeyTypeSECP256k1); + { + std::unique_ptr addr(AnyAddress::createAddress(publicKey, TWCoinTypeBitcoin, std::string(""), TWDerivationDefault)); + EXPECT_EQ(addr->address, ANY_ADDRESS_TEST_ADDRESS); + } + { + std::unique_ptr addr(AnyAddress::createAddress(publicKey, TWCoinTypeBitcoin, std::string(""), TWDerivationBitcoinLegacy)); + EXPECT_EQ(addr->address, "1JvRfEQFv5q5qy9uTSAezH7kVQf4hqnHXx"); + } +} + TEST(AnyAddress, createFromWrongString) { std::unique_ptr addr(AnyAddress::createAddress("1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaax", TWCoinTypeBitcoin)); EXPECT_EQ(nullptr, addr); diff --git a/tests/interface/TWAnyAddressTests.cpp b/tests/interface/TWAnyAddressTests.cpp index c0bef30ab93..f0384bd4c09 100644 --- a/tests/interface/TWAnyAddressTests.cpp +++ b/tests/interface/TWAnyAddressTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,12 +9,13 @@ #include "HexCoding.h" #include #include +#include #include using namespace TW; -TEST(AnyAddress, InvalidString) { +TEST(TWAnyAddress, InvalidString) { auto string = STRING("0x4E5B2e1dc63F6b91cb6Cd759936495434C7e972F"); auto btcAddress = TWAnyAddressCreateWithString(string.get(), TWCoinTypeBitcoin); auto ethAaddress = WRAP(TWAnyAddress, TWAnyAddressCreateWithString(string.get(), TWCoinTypeEthereum)); @@ -24,7 +25,7 @@ TEST(AnyAddress, InvalidString) { ASSERT_EQ(TWAnyAddressCoin(ethAaddress.get()), TWCoinTypeEthereum); } -TEST(AnyAddress, Data) { +TEST(TWAnyAddress, Data) { // ethereum { auto string = STRING("0x4E5B2e1dc63F6b91cb6Cd759936495434C7e972F"); @@ -169,3 +170,34 @@ TEST(AnyAddress, Data) { assertHexEqual(keyHash, "18f9d8d877393bbbe8d697a8a2e52879cc7e84f467656d1cce6bab5a8d2637ec"); } } + +TEST(TWAnyAddress, createFromPubKey) { + constexpr auto pubkey = "02753f5c275e1847ba4d2fd3df36ad00af2e165650b35fe3991e9c9c46f68b12bc"; + const auto pubkey_twstring = STRING(pubkey); + const auto pubkey_data = WRAPD(TWDataCreateWithHexString(pubkey_twstring.get())); + const auto pubkey_obj = WRAP(TWPublicKey, TWPublicKeyCreateWithData(pubkey_data.get(), TWPublicKeyTypeSECP256k1)); + + const auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKey(pubkey_obj.get(), TWCoinTypeBitcoin)); + + assertStringsEqual(WRAPS(TWAnyAddressDescription(addr.get())), "bc1qcj2vfjec3c3luf9fx9vddnglhh9gawmncmgxhz"); +} + +TEST(TWAnyAddress, createFromPubKeyDerivation) { + constexpr auto pubkey = "02753f5c275e1847ba4d2fd3df36ad00af2e165650b35fe3991e9c9c46f68b12bc"; + const auto pubkey_twstring = STRING(pubkey); + const auto pubkey_data = WRAPD(TWDataCreateWithHexString(pubkey_twstring.get())); + const auto pubkey_obj = WRAP(TWPublicKey, TWPublicKeyCreateWithData(pubkey_data.get(), TWPublicKeyTypeSECP256k1)); + + { + const auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKeyDerivation(pubkey_obj.get(), TWCoinTypeBitcoin, TWDerivationDefault)); + assertStringsEqual(WRAPS(TWAnyAddressDescription(addr.get())), "bc1qcj2vfjec3c3luf9fx9vddnglhh9gawmncmgxhz"); + } + { + const auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKeyDerivation(pubkey_obj.get(), TWCoinTypeBitcoin, TWDerivationBitcoinLegacy)); + assertStringsEqual(WRAPS(TWAnyAddressDescription(addr.get())), "1JvRfEQFv5q5qy9uTSAezH7kVQf4hqnHXx"); + } + { + const auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKeyDerivation(pubkey_obj.get(), TWCoinTypeBitcoin, TWDerivationBitcoinTestnet)); + assertStringsEqual(WRAPS(TWAnyAddressDescription(addr.get())), "tb1qcj2vfjec3c3luf9fx9vddnglhh9gawmnjan4v3"); + } +} diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp index 63fc42fec3c..d34edd03468 100644 --- a/tests/interface/TWHDWalletTests.cpp +++ b/tests/interface/TWHDWalletTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -133,12 +133,42 @@ TEST(HDWallet, DeriveBitcoinExtended) { assertStringsEqual(address, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85"); } +TEST(HDWallet, GetKeyDerivation) { + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); + { + auto key = WRAP(TWPrivateKey, TWHDWalletGetKeyDerivation(wallet.get(), TWCoinTypeBitcoin, TWDerivationBitcoinSegwit)); + assertHexEqual(WRAPD(TWPrivateKeyData(key.get())), "1901b5994f075af71397f65bd68a9fff8d3025d65f5a2c731cf90f5e259d6aac"); + auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(key.get(), true)); + auto publicKeyData = WRAPD(TWPublicKeyData(publicKey.get())); + assertHexEqual(publicKeyData, "037ea5dff03f677502c4a1d73c5ac897200e56b155e876774c8fba0cc22f80b941"); + } + { + auto key = WRAP(TWPrivateKey, TWHDWalletGetKeyDerivation(wallet.get(), TWCoinTypeBitcoin, TWDerivationBitcoinLegacy)); + assertHexEqual(WRAPD(TWPrivateKeyData(key.get())), "28071bf4e2b0340db41b807ed8a5514139e5d6427ff9d58dbd22b7ed187103a4"); + auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeySecp256k1(key.get(), true)); + auto publicKeyData = WRAPD(TWPublicKeyData(publicKey.get())); + assertHexEqual(publicKeyData, "0240ebf906b948281289405317a5eb9a98045af8a8ab5311b2e3060cfb66c507a1"); + } +} + TEST(HDWallet, DeriveAddressBitcoin) { auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto address = WRAP(TWString, TWHDWalletGetAddressForCoin(wallet.get(), TWCoinTypeBitcoin)); assertStringsEqual(address, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85"); } +TEST(HDWallet, DeriveAddressBitcoinDerivation) { + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); + { + auto address = WRAP(TWString, TWHDWalletGetAddressDerivation(wallet.get(), TWCoinTypeBitcoin, TWDerivationBitcoinSegwit)); + assertStringsEqual(address, "bc1qumwjg8danv2vm29lp5swdux4r60ezptzz7ce85"); + } + { + auto address = WRAP(TWString, TWHDWalletGetAddressDerivation(wallet.get(), TWCoinTypeBitcoin, TWDerivationBitcoinLegacy)); + assertStringsEqual(address, "1PeUvjuxyf31aJKX6kCXuaqxhmG78ZUdL1"); + } +} + TEST(HDWallet, DeriveEthereum) { auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); auto key = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeEthereum)); From c58d9b0ef7719ef0d351032099be011313207e75 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Fri, 4 Nov 2022 16:12:34 +0100 Subject: [PATCH 129/497] Update in SmartBCH swift test (#2700) --- swift/Tests/Blockchains/SmartBitcoinCashTests.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/swift/Tests/Blockchains/SmartBitcoinCashTests.swift b/swift/Tests/Blockchains/SmartBitcoinCashTests.swift index 131f13d14b6..48d5a6aca65 100644 --- a/swift/Tests/Blockchains/SmartBitcoinCashTests.swift +++ b/swift/Tests/Blockchains/SmartBitcoinCashTests.swift @@ -10,12 +10,12 @@ import XCTest class SmartBitcoinCashTests: XCTestCase { func testAddress() { - let key = PrivateKey(data: Data(hexString: "ab4accc9310d90a61fc354d8f353bca4a2b3c0590685d3eb82d0216af3badddc")!)! + let key = PrivateKey(data: Data(hexString: "155cbd57319f3d938977b4c18000473eb3c432c4e31b667b63e88559c497d82d")!)! let pubkey = key.getPublicKeySecp256k1(compressed: false) let address = AnyAddress(publicKey: pubkey, coin: .smartBitcoinCash) - let addressFromString = AnyAddress(string: "0xA3Dcd899C0f3832DFDFed9479a9d828c6A4EB2A7", coin: .smartBitcoinCash)! + let addressFromString = AnyAddress(string: "0x8bFC9477684987dcAf0970b9bce5E3D9267C99C0", coin: .smartBitcoinCash)! - XCTAssertEqual(pubkey.data.hexString, "0448a9ffac8022f1c7eb5253746e24d11d9b6b2737c0aecd48335feabb95a179916b1f3a97bed6740a85a2d11c663d38566acfb08af48a47ce0c835c65c9b23d0d") + XCTAssertEqual(pubkey.data.hexString, "046439f94100c802691c53ef18523be2c24d301f0e2bd3b425e832378a5405eff4331d5e57303785969073321fc76a8504a3854bdb21e6ab7b268a1737882a29c0") XCTAssertEqual(address.description, addressFromString.description) } From 29e193926a02e073a15669f6b3618416b31a2b70 Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Sat, 5 Nov 2022 10:04:57 +0300 Subject: [PATCH 130/497] [Tools] Kotlin API codegen (#2678) --- tools/android-build | 5 +++++ tools/android-release | 12 ++++++++++++ tools/doxygen_convert_comments | 28 ++++++++++++++++++++++++++++ tools/install-android-dependencies | 29 +++++++++++++++++++++++++++++ tools/kotlin-doc | 27 +++++++++++++++++++++++++++ 5 files changed, 101 insertions(+) create mode 100755 tools/kotlin-doc diff --git a/tools/android-build b/tools/android-build index f63af0c09af..8f87cb4f827 100755 --- a/tools/android-build +++ b/tools/android-build @@ -13,3 +13,8 @@ cp trustwalletcore/build/outputs/aar/trustwalletcore-release.aar ../build/trustw popd echo "Now upload build/trustwalletcore.aar to https://github.com/TrustWallet/trust-wallet-core/releases/tag/$version" + +echo "Building docs..." +tools/kotlin-doc + +echo "Now upload Kotlin docs from build/kdoc.zip to whatever place it needs to be" diff --git a/tools/android-release b/tools/android-release index 60199fb10e5..4856fa5a5ec 100755 --- a/tools/android-release +++ b/tools/android-release @@ -1,6 +1,7 @@ #!/bin/bash # # This script uploads android build to repositories defined in maven-push.gradle +# It also builds and uploads Kotlin docs set -e @@ -14,3 +15,14 @@ pushd android ./gradlew clean build assembleRelease publish -Pversion="$version" echo "Android build uploaded" +popd # android + +echo "Building docs..." +tools/kotlin-doc + +release_url=$(wc_release_url ${version}) +echo "release_url url for docs is $release_url" + +filename=build/dokka/kdoc.zip +download_url=$(wc_upload_asset ${release_url} ${filename}) +echo "download_url is $download_url" diff --git a/tools/doxygen_convert_comments b/tools/doxygen_convert_comments index 91870ffb466..3a81e3baeae 100755 --- a/tools/doxygen_convert_comments +++ b/tools/doxygen_convert_comments @@ -7,6 +7,13 @@ SWIFT_SEE_PATTERN='s/\\see/\- SeeAlso:/g' SWIFT_FOLDER_PATH="swift/Sources/Generated/*.swift" SWIFT_FOLDER_PATH_BAK="swift/Sources/Generated/*.bak" +KOTLIN_PARAMETER_PATTERN='s/\\param/\@param/g' +KOTLIN_RETURN_PATTERN='s/\\return/\@return/g' +KOTLIN_NOTE_PATTERN='s/\\note/\@note/g' +KOTLIN_SEE_PATTERN='s/\\see/\@see/g' +KOTLIN_FOLDER_PATH="jni/java/wallet/core/jni/*.java" +KOTLIN_FOLDER_PATH_BAK="jni/java/wallet/core/jni/*.bak" + function process_swift_comments() { perl -pi.bak -e "$SWIFT_PARAMETER_PATTERN" "$1" perl -pi.bak -e "$SWIFT_RETURN_PATTERN" "$1" @@ -14,6 +21,16 @@ function process_swift_comments() { perl -pi.bak -e "$SWIFT_SEE_PATTERN" "$1" } +function process_kotlin_comments() { + # Process multiline /// comments into javadoc /** ... */ format + perl -0777 -pi.bak -e 's/\/\/\/([^\n]*\n)((?:\ *\/\/\/[^\n]*\n)*)/\/**\n *$1$2*\/\n/g' $1 + perl -pi.bak -e 's/\/\/\//\ \*/g' $1 + + perl -pi.bak -e "$KOTLIN_PARAMETER_PATTERN" "$1" + perl -pi.bak -e "$KOTLIN_RETURN_PATTERN" "$1" + perl -pi.bak -e "$KOTLIN_NOTE_PATTERN" "$1" + perl -pi.bak -e "$KOTLIN_SEE_PATTERN" "$1" +} function swift_convert() { echo "Processing swift conversion" @@ -25,4 +42,15 @@ function swift_convert() { rm -rf $SWIFT_FOLDER_PATH_BAK } +function kotlin_convert() { + echo "Processing kotlin conversion" + + for d in $KOTLIN_FOLDER_PATH ; do + process_kotlin_comments $d + done + + rm -rf $KOTLIN_FOLDER_PATH_BAK +} + swift_convert +kotlin_convert diff --git a/tools/install-android-dependencies b/tools/install-android-dependencies index 7f3d5c64b88..b91ad4d6520 100755 --- a/tools/install-android-dependencies +++ b/tools/install-android-dependencies @@ -2,7 +2,36 @@ set -e +# Dokka stuff +ROOT="$PWD" +DOKKA_CLI_JAR=https://repo1.maven.org/maven2/org/jetbrains/dokka/dokka-cli/1.7.20/dokka-cli-1.7.20.jar + +declare -a DOKKA_DEPS=( +https://repo1.maven.org/maven2/org/jetbrains/dokka/dokka-base/1.7.20/dokka-base-1.7.20.jar +https://repo1.maven.org/maven2/org/jetbrains/dokka/dokka-analysis/1.7.20/dokka-analysis-1.7.20.jar +https://repo1.maven.org/maven2/org/jetbrains/dokka/kotlin-analysis-intellij/1.7.20/kotlin-analysis-intellij-1.7.20.jar +https://repo1.maven.org/maven2/org/jetbrains/dokka/kotlin-analysis-compiler/1.7.20/kotlin-analysis-compiler-1.7.20.jar +https://repo1.maven.org/maven2/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.6.4/kotlinx-coroutines-core-1.6.4.jar +https://repo1.maven.org/maven2/org/jetbrains/kotlinx/kotlinx-html-jvm/0.8.0/kotlinx-html-jvm-0.8.0.jar +https://repo1.maven.org/maven2/org/freemarker/freemarker/2.3.31/freemarker-2.3.31.jar +) + $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --verbose "cmake;3.18.1" "ndk;23.1.7779620" $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "system-images;android-26;google_apis;x86" echo -e "y\ny\ny\ny\ny\n" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses + +echo "Downloading Dokka..." +DOKKA_DIR="$ROOT/build/dokka" +mkdir -p "$DOKKA_DIR" +cd "$DOKKA_DIR" + +if [ ! -f dokka-cli-1.7.20.jar ]; then + curl -fSsOL $DOKKA_CLI_JAR +fi + +for dep in "${DOKKA_DEPS[@]}" ; do + if [ ! -f ${dep##*/} ]; then + curl -fSsOL $dep + fi +done diff --git a/tools/kotlin-doc b/tools/kotlin-doc new file mode 100755 index 00000000000..09105cb56a6 --- /dev/null +++ b/tools/kotlin-doc @@ -0,0 +1,27 @@ +#!/bin/bash + +pushd jni + +DOKKA_CLI_JAR=../build/dokka/dokka-cli-1.7.20.jar + +declare -a DOKKA_DEPS=( +dokka-base-1.7.20.jar +dokka-analysis-1.7.20.jar +kotlin-analysis-intellij-1.7.20.jar +kotlin-analysis-compiler-1.7.20.jar +kotlinx-coroutines-core-1.6.4.jar +kotlinx-html-jvm-0.8.0.jar +freemarker-2.3.31.jar +) + +pluginClassPath="" +for dep in "${DOKKA_DEPS[@]}" ; do + pluginClassPath="$pluginClassPath;../build/dokka/$dep" +done + +java -jar ${DOKKA_CLI_JAR} -outputDir dokka-out -pluginsClasspath $pluginClassPath -sourceSet "-sourceSetName TrustWallet -src java/wallet/core/jni" + +popd #jni + +zip -rq kdoc.zip jni/dokka-out +mv kdoc.zip build/dokka From cc07e5f30bae8e78914211f5f2b56d502ad124ad Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sun, 6 Nov 2022 17:43:32 +0900 Subject: [PATCH 131/497] [CI] Test Kotlin doc (#2705) * Fix dokka-out missing, run kotlin-doc on CI * Fix default root module name and extra jni path in zip --- .github/workflows/android-ci.yml | 25 ++++++++++++++++--------- .gitignore | 1 + tools/kotlin-doc | 9 +++++---- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/.github/workflows/android-ci.yml b/.github/workflows/android-ci.yml index 0bb3ed90964..3dfe3e5b9f0 100644 --- a/.github/workflows/android-ci.yml +++ b/.github/workflows/android-ci.yml @@ -17,28 +17,35 @@ jobs: uses: actions/setup-java@v1 with: java-version: 11 + - name: Install system dependencies run: brew install boost ninja + - name: Install Android Dependencies - run: | - tools/install-android-dependencies + run: tools/install-android-dependencies + - name: Cache internal dependencies id: internal_cache uses: actions/cache@v1.1.2 with: path: build/local key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} + - name: Install internal dependencies - run: | - tools/install-dependencies + run: tools/install-dependencies if: steps.internal_cache.outputs.cache-hit != 'true' + + - name: Generate files + run: tools/generate-files + + - name: Build Kotlin doc + run: tools/kotlin-doc + - name: Run test - run: | - tools/generate-files - tools/android-test + run: tools/android-test + - name: Build sample app - run: | - tools/samples-build android + run: tools/samples-build android env: GITHUB_USER: ${{ github.actor }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 707a2517dee..4c0f5e373aa 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ lib/protobuf jni/cpp/generated jni/java/wallet/core/jni jni/java/wallet/core/proto +jni/dokka-out swift/Sources/Generated swift/wallet-core/ src/Generated/*.cpp diff --git a/tools/kotlin-doc b/tools/kotlin-doc index 09105cb56a6..d1ea9e5de3b 100755 --- a/tools/kotlin-doc +++ b/tools/kotlin-doc @@ -19,9 +19,10 @@ for dep in "${DOKKA_DEPS[@]}" ; do pluginClassPath="$pluginClassPath;../build/dokka/$dep" done -java -jar ${DOKKA_CLI_JAR} -outputDir dokka-out -pluginsClasspath $pluginClassPath -sourceSet "-sourceSetName TrustWallet -src java/wallet/core/jni" +mkdir -p dokka-out -popd #jni +java -jar ${DOKKA_CLI_JAR} -moduleName WalletCore -outputDir dokka-out -pluginsClasspath $pluginClassPath -sourceSet "-sourceSetName TrustWallet -src java/wallet/core/jni" + +zip -rq kdoc.zip dokka-out && mv kdoc.zip ../build/dokka -zip -rq kdoc.zip jni/dokka-out -mv kdoc.zip build/dokka +popd #jni From b59b97c7684d77e8709e82934a0ea2a8a26db41b Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 8 Nov 2022 08:57:46 +0100 Subject: [PATCH 132/497] Add Hedera support (#2680) --- CMakeLists.txt | 2 +- .../blockchains/CoinAddressDerivationTests.kt | 1 + .../blockchains/hedera/TestHederaAddress.kt | 35 + .../blockchains/hedera/TestHederaSigner.kt | 72 + codegen/lib/templates/newcoin/Address.h.erb | 2 +- codegen/lib/templates/newcoin/Entry.h.erb | 2 +- docs/registry.md | 1 + include/TrustWalletCore/TWBlockchain.h | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 41 +- src/Coin.cpp | 3 + src/Data.h | 6 + src/Hedera/Address.cpp | 90 + src/Hedera/Address.h | 52 + src/Hedera/DER.cpp | 20 + src/Hedera/DER.h | 18 + src/Hedera/Entry.cpp | 26 + src/Hedera/Entry.h | 22 + src/Hedera/Protobuf/.gitignore | 3 + src/Hedera/Protobuf/basic_types.proto | 1596 +++++++++++++++++ src/Hedera/Protobuf/crypto_transfer.proto | 55 + src/Hedera/Protobuf/duration.proto | 38 + src/Hedera/Protobuf/timestamp.proto | 54 + src/Hedera/Protobuf/transaction_body.proto | 76 + .../Protobuf/transaction_contents.proto | 42 + src/Hedera/Signer.cpp | 107 ++ src/Hedera/Signer.h | 25 + src/algorithm/string.hpp | 27 + src/proto/Hedera.proto | 98 + swift/Tests/Blockchains/HederaTests.swift | 59 + swift/Tests/CoinAddressDerivationTests.swift | 4 + tests/chains/Hedera/AddressTests.cpp | 58 + tests/chains/Hedera/SignerTests.cpp | 238 +++ tests/chains/Hedera/TWAnySignerTests.cpp | 42 + tests/chains/Hedera/TWCoinTypeTests.cpp | 33 + tests/common/CoinAddressDerivationTests.cpp | 3 + tests/common/HDWallet/HDWalletTests.cpp | 23 + tests/common/algorithm/string.cpp | 19 + tools/generate-files | 1 + wasm/CMakeLists.txt | 4 +- wasm/tests/Blockchain/Hedera.test.ts | 62 + 41 files changed, 3050 insertions(+), 12 deletions(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaAddress.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaSigner.kt create mode 100644 src/Hedera/Address.cpp create mode 100644 src/Hedera/Address.h create mode 100644 src/Hedera/DER.cpp create mode 100644 src/Hedera/DER.h create mode 100644 src/Hedera/Entry.cpp create mode 100644 src/Hedera/Entry.h create mode 100644 src/Hedera/Protobuf/.gitignore create mode 100644 src/Hedera/Protobuf/basic_types.proto create mode 100644 src/Hedera/Protobuf/crypto_transfer.proto create mode 100644 src/Hedera/Protobuf/duration.proto create mode 100644 src/Hedera/Protobuf/timestamp.proto create mode 100644 src/Hedera/Protobuf/transaction_body.proto create mode 100644 src/Hedera/Protobuf/transaction_contents.proto create mode 100644 src/Hedera/Signer.cpp create mode 100644 src/Hedera/Signer.h create mode 100644 src/algorithm/string.hpp create mode 100644 src/proto/Hedera.proto create mode 100644 swift/Tests/Blockchains/HederaTests.swift create mode 100644 tests/chains/Hedera/AddressTests.cpp create mode 100644 tests/chains/Hedera/SignerTests.cpp create mode 100644 tests/chains/Hedera/TWAnySignerTests.cpp create mode 100644 tests/chains/Hedera/TWCoinTypeTests.cpp create mode 100644 tests/common/algorithm/string.cpp create mode 100644 wasm/tests/Blockchain/Hedera.test.ts diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b061e1c15b..ed02ed918ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,7 @@ endif () if (NOT ANDROID AND TW_UNITY_BUILD) set_target_properties(TrustWalletCore PROPERTIES UNITY_BUILD ON) - file(GLOB_RECURSE PROTOBUF_SOURCE_FILES CONFIGURE_DEPENDS src/Cosmos/Protobuf/*.pb.cc src/proto/*.pb.cc) + file(GLOB_RECURSE PROTOBUF_SOURCE_FILES CONFIGURE_DEPENDS src/Cosmos/Protobuf/*.pb.cc src/Hedera/Protobuf/*.pb.cc src/proto/*.pb.cc) foreach(file ${PROTOBUF_SOURCE_FILES}) set_property(SOURCE ${file} PROPERTY SKIP_UNITY_BUILD_INCLUSION ON) endforeach() diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 98f69f55d1b..ddd2c1dd86c 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -106,5 +106,6 @@ class CoinAddressDerivationTests { NERVOS -> assertEquals("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02wectaumxn0664yw2jd53lqk4mxg3", address) EVERSCALE -> assertEquals("0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04", address) APTOS -> assertEquals("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", address) + HEDERA -> assertEquals("0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5", address) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaAddress.kt new file mode 100644 index 00000000000..be92015f825 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaAddress.kt @@ -0,0 +1,35 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.hedera + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestHederaAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val any = AnyAddress("0.0.1377988", CoinType.HEDERA) + assertEquals(any.coin(), CoinType.HEDERA) + assertEquals(any.description(), "0.0.1377988") + + Assert.assertFalse( + AnyAddress.isValid( + "0.0.a", + CoinType.HEDERA + ) + ) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaSigner.kt new file mode 100644 index 00000000000..dec11a37bcb --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/hedera/TestHederaSigner.kt @@ -0,0 +1,72 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.hedera + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.* +import wallet.core.jni.proto.Hedera + +class TestHederaSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun HederaTransactionSimpleTransferSigning() { + // Successfully broadcasted: https://hashscan.io/testnet/transaction/0.0.48694347-1667222879-749068449?t=1667222891.440398729&p=1 + val key = + "e87a5584c0173263e138db689fdb2a7389025aaae7cb1a18a1017d76012130e8".toHexBytesInByteString() + + val transfer = Hedera.TransferMessage + .newBuilder() + .setAmount(100000000) + .setFrom("0.0.48694347") + .setTo("0.0.48462050") + .build() + + val timestamp = Hedera.Timestamp + .newBuilder() + .setSeconds(1667222879) + .setNanos(749068449) + .build() + + val transactionID = Hedera.TransactionID + .newBuilder() + .setTransactionValidStart(timestamp) + .setAccountID("0.0.48694347") + .build() + + val body = Hedera.TransactionBody + .newBuilder() + .setMemo("") + .setTransfer(transfer) + .setTransactionID(transactionID) + .setNodeAccountID("0.0.9") + .setTransactionFee(100000000) + .setTransactionValidDuration(120) + .build() + + val signingInput = Hedera.SigningInput + .newBuilder() + .setPrivateKey(key) + .setBody(body).build() + + val result = AnySigner.sign(signingInput, CoinType.HEDERA, Hedera.SigningOutput.parser()) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.encoded.toByteArray())), + "0a440a150a0c08df9aff9a0610a1c197e502120518cb889c17120218091880c2d72f22020878721e0a1c0a0c0a0518e2f18d17108084af5f0a0c0a0518cb889c1710ff83af5f12660a640a205d3a70d08b2beafb72c7a68986b3ff819a306078b8c359d739e4966e82e6d40e1a40612589c3b15f1e3ed6084b5a3a5b1b81751578cac8d6c922f31731b3982a5bac80a22558b2197276f5bae49b62503a4d39448ceddbc5ef3ba9bee4c0f302f70c" + ) + } +} diff --git a/codegen/lib/templates/newcoin/Address.h.erb b/codegen/lib/templates/newcoin/Address.h.erb index 74997f6330c..d39dad53723 100644 --- a/codegen/lib/templates/newcoin/Address.h.erb +++ b/codegen/lib/templates/newcoin/Address.h.erb @@ -7,7 +7,7 @@ #pragma once #include "Data.h" -#include "../PublicKey.h" +#include "PublicKey.h" #include diff --git a/codegen/lib/templates/newcoin/Entry.h.erb b/codegen/lib/templates/newcoin/Entry.h.erb index fa115a9a30b..090d5d06445 100644 --- a/codegen/lib/templates/newcoin/Entry.h.erb +++ b/codegen/lib/templates/newcoin/Entry.h.erb @@ -14,7 +14,7 @@ namespace TW::<%= format_name(coin) %> { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const; + virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, const PrefixVariant& addressPrefix) const; virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; // normalizeAddress(): implement this if needed, e.g. Ethereum address is EIP55 checksummed diff --git a/docs/registry.md b/docs/registry.md index 5d89f556a91..3db48715d95 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -67,6 +67,7 @@ This list is generated from [./registry.json](../registry.json) | 1815 | Cardano | ADA | | | | 2301 | Qtum | QTUM | | | | 2718 | Nebulas | NAS | | | +| 3030 | Hedera | HBAR | | | | 6060 | GoChain | GO | | | | 8964 | NULS | NULS | | | | 18000 | Meter | MTR | | | diff --git a/include/TrustWalletCore/TWBlockchain.h b/include/TrustWalletCore/TWBlockchain.h index 80fe59660ce..44724e534f6 100644 --- a/include/TrustWalletCore/TWBlockchain.h +++ b/include/TrustWalletCore/TWBlockchain.h @@ -55,6 +55,7 @@ enum TWBlockchain { TWBlockchainNervos = 41, TWBlockchainEverscale = 42, TWBlockchainAptos = 43, // Aptos + TWBlockchainHedera = 44, // Hedera }; TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 4c009702001..d740aa310f5 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -121,6 +121,7 @@ enum TWCoinType { TWCoinTypeNervos = 309, TWCoinTypeEverscale = 396, TWCoinTypeAptos = 637, + TWCoinTypeHedera = 3030, }; /// Returns the blockchain for a coin type. diff --git a/registry.json b/registry.json index 96dedfb41e8..fe76a261485 100644 --- a/registry.json +++ b/registry.json @@ -1944,7 +1944,7 @@ "documentation": "https://eth.wiki/json-rpc/API" }, "deprecated": true, - "testFolderName" : "Binance" + "testFolderName": "Binance" }, { "id": "smartchain", @@ -1977,7 +1977,7 @@ "rpc": "https://bsc-dataseed1.binance.org", "documentation": "https://eth.wiki/json-rpc/API" }, - "testFolderName" : "Binance" + "testFolderName": "Binance" }, { "id": "polygon", @@ -2157,7 +2157,7 @@ "rpc": "https://http-mainnet-node.huobichain.com", "documentation": "https://eth.wiki/json-rpc/API" }, - "testFolderName" : "ECO" + "testFolderName": "ECO" }, { "id": "avalanchec", @@ -2188,7 +2188,7 @@ "clientPublic": "https://api.avax.network/ext/bc/C/rpc", "clientDocs": "https://docs.avax.network/" }, - "testFolderName" : "Avalanche" + "testFolderName": "Avalanche" }, { "id": "xdai", @@ -2436,7 +2436,7 @@ "clientPublic": "https://evm-cronos.crypto.org", "clientDocs": "https://eth.wiki/json-rpc/API" }, - "testFolderName" : "Cronos" + "testFolderName": "Cronos" }, { "id": "kavaevm", @@ -2495,7 +2495,7 @@ "rpc": "https://smartbch.fountainhead.cash/mainnet", "documentation": "https://github.com/smartbch/docs/blob/main/developers-guide/jsonrpc.md" }, - "testFolderName" : "Bitcoin" + "testFolderName": "Bitcoin" }, { "id": "kcc", @@ -2526,7 +2526,7 @@ "rpc": "https://rpc-mainnet.kcc.network", "documentation": "https://docs.kcc.io/#/en-us/" }, - "testFolderName" : "KuCoinCommunityChain" + "testFolderName": "KuCoinCommunityChain" }, { "id": "boba", @@ -2821,5 +2821,32 @@ "rpc": "https://exchainrpc.okex.org", "documentation": "https://okc-docs.readthedocs.io/en/latest" } + }, + { + "id": "hedera", + "name": "Hedera", + "coinId": 3030, + "symbol": "HBAR", + "decimals": 8, + "blockchain": "Hedera", + "derivation": [ + { + "path": "m/44'/3030'/0'/0'/0" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://hashscan.io/mainnet", + "txPath": "/transaction/", + "accountPath": "/account/", + "sampleTx": "0.0.19790-1666769504-858851231", + "sampleAccount": "0.0.19790" + }, + "info": { + "url": "https://hedera.com/", + "source": "https://github.com/hashgraph", + "documentation": "https://docs.hedera.com" + } } ] diff --git a/src/Coin.cpp b/src/Coin.cpp index 9b88d7eb252..c99c086c8bc 100644 --- a/src/Coin.cpp +++ b/src/Coin.cpp @@ -55,6 +55,7 @@ #include "XRP/Entry.h" #include "Zcash/Entry.h" #include "Zilliqa/Entry.h" +#include "Hedera/Entry.h" // end_of_coin_includes_marker_do_not_modify using namespace TW; @@ -103,6 +104,7 @@ Zcash::Entry zcashDP; Zilliqa::Entry zilliqaDP; Nervos::Entry NervosDP; Everscale::Entry EverscaleDP; +Hedera::Entry HederaDP; // end_of_coin_dipatcher_declarations_marker_do_not_modify CoinEntry* coinDispatcher(TWCoinType coinType) { @@ -153,6 +155,7 @@ CoinEntry* coinDispatcher(TWCoinType coinType) { case TWBlockchainNervos: entry = &NervosDP; break; case TWBlockchainEverscale: entry = &EverscaleDP; break; case TWBlockchainAptos: entry = &AptosDP; break; + case TWBlockchainHedera: entry = &HederaDP; break; // end_of_coin_dipatcher_switch_marker_do_not_modify default: entry = nullptr; break; diff --git a/src/Data.h b/src/Data.h index 1c43fdc68b0..6ab74ccaba9 100644 --- a/src/Data.h +++ b/src/Data.h @@ -32,6 +32,12 @@ inline void append(Data& data, const Data& suffix) { data.insert(data.end(), suffix.begin(), suffix.end()); } +inline Data concat(const Data& data, const Data& suffix) { + Data out = data; + append(out, suffix); + return out; +} + inline void append(Data& data, const byte suffix) { data.push_back(suffix); } diff --git a/src/Hedera/Address.cpp b/src/Hedera/Address.cpp new file mode 100644 index 00000000000..c3129a286cb --- /dev/null +++ b/src/Hedera/Address.cpp @@ -0,0 +1,90 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Address.h" +#include "HexCoding.h" +#include "DER.h" +#include "algorithm/string.hpp" + +#include +#include + +namespace TW::Hedera::internal { + static const std::regex gEntityIDRegex{"(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-([a-z]{5}))?$"}; +} + +namespace TW::Hedera { + + +Alias::Alias(std::optional alias) noexcept : mPubKey(std::move(alias)) { + +} + +std::string Alias::string() const noexcept { + std::string pubkeyBytes = ""; + if (mPubKey.has_value()) { + pubkeyBytes = hex(mPubKey.value().bytes); + } + return gHederaDerPrefixPublic + pubkeyBytes; +} + +bool Address::isValid(const std::string& string) { + using namespace internal; + std::smatch match; + auto isValid = std::regex_match(string, match, gEntityIDRegex); + if (!isValid) { + auto parts = TW::ssplit(string, '.'); + if (parts.size() != 3) { + return false; + } + auto isNumberFunctor = [](std::string_view input) { + return input.find_first_not_of("0123456789") == std::string::npos; + }; + if (!isNumberFunctor(parts[0]) || !isNumberFunctor(parts[1])) { + return false; + } + isValid = hasDerPrefix(parts[2]); + } + return isValid; +} + +Address::Address(const std::string& string) { + if (!isValid(string)) { + throw std::invalid_argument("Invalid address string"); + } + + auto toInt = [](std::string_view s) -> std::optional { + if (std::size_t value = 0; std::from_chars(s.begin(), s.end(), value).ec == std::errc{}) { + return value; + } else { + return std::nullopt; + } + }; + + // When creating an Address by string - we assume to only sent to 0.0.1 format, alias is internal. + auto parts = TW::ssplit(string, '.'); + mShard = *toInt(parts[0]); + mRealm = *toInt(parts[1]); + mNum = *toInt(parts[2]); +} + +Address::Address(const PublicKey& publicKey) + : Address(0, 0, 0, publicKey) { +} + +std::string Address::string() const { + std::string out = std::to_string(mShard) + "." + std::to_string(mRealm) + "."; + if (mAlias.mPubKey.has_value()) { + return out + mAlias.string(); + } + return out + std::to_string(mNum); +} + +Address::Address(std::size_t shard, std::size_t realm, std::size_t num, std::optional alias) + : mShard(shard), mRealm(realm), mNum(num), mAlias(std::move(alias)) { +} + +} // namespace TW::Hedera diff --git a/src/Hedera/Address.h b/src/Hedera/Address.h new file mode 100644 index 00000000000..ab29025aea1 --- /dev/null +++ b/src/Hedera/Address.h @@ -0,0 +1,52 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" +#include "PublicKey.h" + +#include +#include + +namespace TW::Hedera { + +struct Alias { + explicit Alias(std::optional alias = std::nullopt) noexcept; + std::string string() const noexcept; + std::optional mPubKey{std::nullopt}; +}; + +class Address { +public: + /// Determines whether a string makes a valid address. + static bool isValid(const std::string& string); + + /// Initializes a Hedera address with a string representation. + explicit Address(const std::string& string); + + /// Initializes a Hedera address with a public key. + explicit Address(const PublicKey& publicKey); + + /// Initializes a Hedera address with a shard, realm, num and optional alias + explicit Address(std::size_t shard, std::size_t realm, std::size_t num, std::optional alias = std::nullopt); + + /// Returns a string representation of the address. + std::string string() const; + + std::size_t shard() const { return mShard; } + std::size_t realm() const { return mRealm; } + std::size_t num() const { return mNum; } + const Alias& alias() const {return mAlias;} + +private: + std::size_t mShard{0}; + std::size_t mRealm{0}; + std::size_t mNum; + Alias mAlias; +}; + +} // namespace TW::Hedera diff --git a/src/Hedera/DER.cpp b/src/Hedera/DER.cpp new file mode 100644 index 00000000000..5da801ee061 --- /dev/null +++ b/src/Hedera/DER.cpp @@ -0,0 +1,20 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "DER.h" +#include "PublicKey.h" +#include "HexCoding.h" + +namespace TW::Hedera { + +bool hasDerPrefix(const std::string& input) noexcept { + if (std::size_t pos = input.find(gHederaDerPrefixPublic); pos != std::string::npos) { + return PublicKey::isValid(parse_hex(input.substr(pos + std::string(gHederaDerPrefixPublic).size())), TWPublicKeyTypeED25519); + } + return false; +} + +} // namespace TW::Hedera diff --git a/src/Hedera/DER.h b/src/Hedera/DER.h new file mode 100644 index 00000000000..67bf784d71e --- /dev/null +++ b/src/Hedera/DER.h @@ -0,0 +1,18 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include + +namespace TW::Hedera { + // Hedera DER prefix: https://github.com/hashgraph/hedera-sdk-js/blob/e0cd39c84ab189d59a6bcedcf16e4102d7bb8beb/packages/cryptography/src/Ed25519PrivateKey.js#L8 + inline constexpr const char* const gHederaDerPrefixPrivate = "302e020100300506032b657004220420"; + // Hedera DER prefix: https://github.com/hashgraph/hedera-sdk-js/blob/e0cd39c84ab189d59a6bcedcf16e4102d7bb8beb/packages/cryptography/src/Ed25519PublicKey.js#L7 + inline constexpr const char* const gHederaDerPrefixPublic = "302a300506032b6570032100"; + + bool hasDerPrefix(const std::string& input) noexcept; +} diff --git a/src/Hedera/Entry.cpp b/src/Hedera/Entry.cpp new file mode 100644 index 00000000000..60dfc7e124a --- /dev/null +++ b/src/Hedera/Entry.cpp @@ -0,0 +1,26 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Entry.h" + +#include "Address.h" +#include "Signer.h" + +namespace TW::Hedera { + +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { + return Address::isValid(address); +} + +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { + return Address(publicKey).string(); +} + +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { + signTemplate(dataIn, dataOut); +} + +} // namespace TW::Hedera diff --git a/src/Hedera/Entry.h b/src/Hedera/Entry.h new file mode 100644 index 00000000000..5cf496ef185 --- /dev/null +++ b/src/Hedera/Entry.h @@ -0,0 +1,22 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "../CoinEntry.h" + +namespace TW::Hedera { + +/// Entry point for implementation of Hedera coin. +/// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file +class Entry final : public CoinEntry { +public: + virtual bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; + virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; +}; + +} // namespace TW::Hedera diff --git a/src/Hedera/Protobuf/.gitignore b/src/Hedera/Protobuf/.gitignore new file mode 100644 index 00000000000..c96d61208c0 --- /dev/null +++ b/src/Hedera/Protobuf/.gitignore @@ -0,0 +1,3 @@ +*.cc +*.h + diff --git a/src/Hedera/Protobuf/basic_types.proto b/src/Hedera/Protobuf/basic_types.proto new file mode 100644 index 00000000000..40bb309ce34 --- /dev/null +++ b/src/Hedera/Protobuf/basic_types.proto @@ -0,0 +1,1596 @@ +// Taken from https://github.com/hashgraph/hedera-protobufs/tree/main/services + +syntax = "proto3"; + +package proto; + +/*- + * ‌ + * Hedera Network Services Protobuf + * ​ + * Copyright (C) 2018 - 2022 Hedera Hashgraph, LLC + * ​ + * 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. + * ‍ + */ + +import "timestamp.proto"; +import "google/protobuf/wrappers.proto"; + +option java_package = "com.hederahashgraph.api.proto.java"; +option java_multiple_files = true; + +/** + * Each shard has a nonnegative shard number. Each realm within a given shard has a nonnegative + * realm number (that number might be reused in other shards). And each account, file, and smart + * contract instance within a given realm has a nonnegative number (which might be reused in other + * realms). Every account, file, and smart contract instance is within exactly one realm. So a + * FileID is a triplet of numbers, like 0.1.2 for entity number 2 within realm 1 within shard 0. + * Each realm maintains a single counter for assigning numbers, so if there is a file with ID + * 0.1.2, then there won't be an account or smart contract instance with ID 0.1.2. + * + * Everything is partitioned into realms so that each Solidity smart contract can access everything + * in just a single realm, locking all those entities while it's running, but other smart contracts + * could potentially run in other realms in parallel. So realms allow Solidity to be parallelized + * somewhat, even though the language itself assumes everything is serial. + */ +message ShardID { + /** + * the shard number (nonnegative) + */ + int64 shardNum = 1; +} + +/** + * The ID for a realm. Within a given shard, every realm has a unique ID. Each account, file, and + * contract instance belongs to exactly one realm. + */ +message RealmID { + /** + * The shard number (nonnegative) + */ + int64 shardNum = 1; + + /** + * The realm number (nonnegative) + */ + int64 realmNum = 2; +} + +/** + * The ID for an a cryptocurrency account + */ +message AccountID { + /** + * The shard number (nonnegative) + */ + int64 shardNum = 1; + + /** + * The realm number (nonnegative) + */ + int64 realmNum = 2; + + /** + * The account number unique within its realm which can be either a non-negative integer or an alias public key. + * For any AccountID fields in the query response, transaction record or transaction receipt only accountNum will + * be populated. + */ + oneof account { + /** + * A non-negative account number unique within its realm + */ + int64 accountNum = 3; + + /** + * The public key bytes to be used as the account's alias. The public key bytes are the result of serializing + * a protobuf Key message for any primitive key type. Currently only primitive key bytes are supported as an alias + * (ThresholdKey, KeyList, ContractID, and delegatable_contract_id are not supported) + * + * May also be the ethereum account 20-byte EVM address to be used initially in place of the public key bytes. This EVM + * address may be either the encoded form of the shard.realm.num or the keccak-256 hash of a ECDSA_SECP256K1 primitive key. + * + * At most one account can ever have a given alias and it is used for account creation if it + * was automatically created using a crypto transfer. It will be null if an account is created normally. + * It is immutable once it is set for an account. + * + * If a transaction auto-creates the account, any further transfers to that alias will simply be deposited + * in that account, without creating anything, and with no creation fee being charged. + * + * If a transaction lazily-creates this account, a subsequent transaction will be required containing the public key bytes + * that map to the EVM address bytes. The provided public key bytes will then serve as the final alias bytes. + */ + bytes alias = 4; + + } +} + +/** + * The ID for a file + */ +message FileID { + /** + * The shard number (nonnegative) + */ + int64 shardNum = 1; + + /** + * The realm number (nonnegative) + */ + int64 realmNum = 2; + + /** + * A nonnegative File number unique within its realm + */ + int64 fileNum = 3; +} + +/** + * The ID for a smart contract instance + */ +message ContractID { + /** + * The shard number (nonnegative) + */ + int64 shardNum = 1; + + /** + * The realm number (nonnegative) + */ + int64 realmNum = 2; + + oneof contract { + /** + * A nonnegative number unique within a given shard and realm + */ + int64 contractNum = 3; + + /** + * The 20-byte EVM address of the contract to call. + * + * Every contract has an EVM address determined by its shard.realm.num id. + * This address is as follows: + *
    + *
  1. The first 4 bytes are the big-endian representation of the shard.
  2. + *
  3. The next 8 bytes are the big-endian representation of the realm.
  4. + *
  5. The final 8 bytes are the big-endian representation of the number.
  6. + *
+ * + * Contracts created via CREATE2 have an additional, primary address that is + * derived from the EIP-1014 + * specification, and does not have a simple relation to a shard.realm.num id. + * + * (Please do note that CREATE2 contracts can also be referenced by the three-part + * EVM address described above.) + */ + bytes evm_address = 4; + } +} + +/** + * The ID for a transaction. This is used for retrieving receipts and records for a transaction, for + * appending to a file right after creating it, for instantiating a smart contract with bytecode in + * a file just created, and internally by the network for detecting when duplicate transactions are + * submitted. A user might get a transaction processed faster by submitting it to N nodes, each with + * a different node account, but all with the same TransactionID. Then, the transaction will take + * effect when the first of all those nodes submits the transaction and it reaches consensus. The + * other transactions will not take effect. So this could make the transaction take effect faster, + * if any given node might be slow. However, the full transaction fee is charged for each + * transaction, so the total fee is N times as much if the transaction is sent to N nodes. + * + * Applicable to Scheduled Transactions: + * - The ID of a Scheduled Transaction has transactionValidStart and accountIDs inherited from the + * ScheduleCreate transaction that created it. That is to say that they are equal + * - The scheduled property is true for Scheduled Transactions + * - transactionValidStart, accountID and scheduled properties should be omitted + */ +message TransactionID { + /** + * The transaction is invalid if consensusTimestamp < transactionID.transactionStartValid + */ + Timestamp transactionValidStart = 1; + + /** + * The Account ID that paid for this transaction + */ + AccountID accountID = 2; + + /** + * Whether the Transaction is of type Scheduled or no + */ + bool scheduled = 3; + + /** + * The identifier for an internal transaction that was spawned as part + * of handling a user transaction. (These internal transactions share the + * transactionValidStart and accountID of the user transaction, so a + * nonce is necessary to give them a unique TransactionID.) + * + * An example is when a "parent" ContractCreate or ContractCall transaction + * calls one or more HTS precompiled contracts; each of the "child" + * transactions spawned for a precompile has a id with a different nonce. + */ + int32 nonce = 4; +} + +/** + * An account, and the amount that it sends or receives during a cryptocurrency or token transfer. + */ +message AccountAmount { + /** + * The Account ID that sends/receives cryptocurrency or tokens + */ + AccountID accountID = 1; + + /** + * The amount of tinybars (for Crypto transfers) or in the lowest + * denomination (for Token transfers) that the account sends(negative) or + * receives(positive) + */ + sint64 amount = 2; + + /** + * If true then the transfer is expected to be an approved allowance and the + * accountID is expected to be the owner. The default is false (omitted). + */ + bool is_approval = 3; +} + +/** + * A list of accounts and amounts to transfer out of each account (negative) or into it (positive). + */ +message TransferList { + /** + * Multiple list of AccountAmount pairs, each of which has an account and + * an amount to transfer into it (positive) or out of it (negative) + */ + repeated AccountAmount accountAmounts = 1; +} + +/** + * A sender account, a receiver account, and the serial number of an NFT of a Token with + * NON_FUNGIBLE_UNIQUE type. When minting NFTs the sender will be the default AccountID instance + * (0.0.0) and when burning NFTs, the receiver will be the default AccountID instance. + */ +message NftTransfer { + /** + * The accountID of the sender + */ + AccountID senderAccountID = 1; + + /** + * The accountID of the receiver + */ + AccountID receiverAccountID = 2; + + /** + * The serial number of the NFT + */ + int64 serialNumber = 3; + + /** + * If true then the transfer is expected to be an approved allowance and the + * senderAccountID is expected to be the owner. The default is false (omitted). + */ + bool is_approval = 4; +} + +/** + * A list of token IDs and amounts representing the transferred out (negative) or into (positive) + * amounts, represented in the lowest denomination of the token + */ +message TokenTransferList { + /** + * The ID of the token + */ + TokenID token = 1; + + /** + * Applicable to tokens of type FUNGIBLE_COMMON. Multiple list of AccountAmounts, each of which + * has an account and amount + */ + repeated AccountAmount transfers = 2; + + /** + * Applicable to tokens of type NON_FUNGIBLE_UNIQUE. Multiple list of NftTransfers, each of + * which has a sender and receiver account, including the serial number of the NFT + */ + repeated NftTransfer nftTransfers = 3; + + /** + * If present, the number of decimals this fungible token type is expected to have. The transfer + * will fail with UNEXPECTED_TOKEN_DECIMALS if the actual decimals differ. + */ + google.protobuf.UInt32Value expected_decimals = 4; +} + +/** + * A rational number, used to set the amount of a value transfer to collect as a custom fee + */ +message Fraction { + /** + * The rational's numerator + */ + int64 numerator = 1; + + /** + * The rational's denominator; a zero value will result in FRACTION_DIVIDES_BY_ZERO + */ + int64 denominator = 2; +} + +/** + * Unique identifier for a topic (used by the consensus service) + */ +message TopicID { + /** + * The shard number (nonnegative) + */ + int64 shardNum = 1; + + /** + * The realm number (nonnegative) + */ + int64 realmNum = 2; + + /** + * Unique topic identifier within a realm (nonnegative). + */ + int64 topicNum = 3; +} + +/** + * Unique identifier for a token + */ +message TokenID { + /** + * A nonnegative shard number + */ + int64 shardNum = 1; + + /** + * A nonnegative realm number + */ + int64 realmNum = 2; + + /** + * A nonnegative token number + */ + int64 tokenNum = 3; +} + +/** + * Unique identifier for a Schedule + */ +message ScheduleID { + /** + * A nonnegative shard number + */ + int64 shardNum = 1; + + /** + * A nonnegative realm number + */ + int64 realmNum = 2; + + /** + * A nonnegative schedule number + */ + int64 scheduleNum = 3; +} + +/** + * Possible Token Types (IWA Compatibility). + * Apart from fungible and non-fungible, Tokens can have either a common or unique representation. + * This distinction might seem subtle, but it is important when considering how tokens can be traced + * and if they can have isolated and unique properties. + */ +enum TokenType { + /** + * Interchangeable value with one another, where any quantity of them has the same value as + * another equal quantity if they are in the same class. Share a single set of properties, not + * distinct from one another. Simply represented as a balance or quantity to a given Hedera + * account. + */ + FUNGIBLE_COMMON = 0; + + /** + * Unique, not interchangeable with other tokens of the same type as they typically have + * different values. Individually traced and can carry unique properties (e.g. serial number). + */ + NON_FUNGIBLE_UNIQUE = 1; +} + +/** + * Allows a set of resource prices to be scoped to a certain type of a HAPI operation. + * + * For example, the resource prices for a TokenMint operation are different between minting fungible + * and non-fungible tokens. This enum allows us to "mark" a set of prices as applying to one or the + * other. + * + * Similarly, the resource prices for a basic TokenCreate without a custom fee schedule yield a + * total price of $1. The resource prices for a TokenCreate with a custom fee schedule are different + * and yield a total base price of $2. + */ +enum SubType { + /** + * The resource prices have no special scope + */ + DEFAULT = 0; + + /** + * The resource prices are scoped to an operation on a fungible common token + */ + TOKEN_FUNGIBLE_COMMON = 1; + + /** + * The resource prices are scoped to an operation on a non-fungible unique token + */ + TOKEN_NON_FUNGIBLE_UNIQUE = 2; + + /** + * The resource prices are scoped to an operation on a fungible common + * token with a custom fee schedule + */ + TOKEN_FUNGIBLE_COMMON_WITH_CUSTOM_FEES = 3; + + /** + * The resource prices are scoped to an operation on a non-fungible unique + * token with a custom fee schedule + */ + TOKEN_NON_FUNGIBLE_UNIQUE_WITH_CUSTOM_FEES = 4; + + /** + * The resource prices are scoped to a ScheduleCreate containing a ContractCall. + */ + SCHEDULE_CREATE_CONTRACT_CALL = 5; +} + +/** + * Possible Token Supply Types (IWA Compatibility). + * Indicates how many tokens can have during its lifetime. + */ +enum TokenSupplyType { + /** + * Indicates that tokens of that type have an upper bound of Long.MAX_VALUE. + */ + INFINITE = 0; + + /** + * Indicates that tokens of that type have an upper bound of maxSupply, + * provided on token creation. + */ + FINITE = 1; +} + +/** + * Possible Freeze statuses returned on TokenGetInfoQuery or CryptoGetInfoResponse in + * TokenRelationship + */ +enum TokenFreezeStatus { + /** + * UNDOCUMENTED + */ + FreezeNotApplicable = 0; + + /** + * UNDOCUMENTED + */ + Frozen = 1; + + /** + * UNDOCUMENTED + */ + Unfrozen = 2; +} + +/** + * Possible KYC statuses returned on TokenGetInfoQuery or CryptoGetInfoResponse in TokenRelationship + */ +enum TokenKycStatus { + /** + * UNDOCUMENTED + */ + KycNotApplicable = 0; + + /** + * UNDOCUMENTED + */ + Granted = 1; + + /** + * UNDOCUMENTED + */ + Revoked = 2; +} + +/** + * Possible Pause statuses returned on TokenGetInfoQuery + */ +enum TokenPauseStatus { + /** + * Indicates that a Token has no pauseKey + */ + PauseNotApplicable = 0; + + /** + * Indicates that a Token is Paused + */ + Paused = 1; + + /** + * Indicates that a Token is Unpaused. + */ + Unpaused = 2; +} + +/** + * A Key can be a public key from either the Ed25519 or ECDSA(secp256k1) signature schemes, where + * in the ECDSA(secp256k1) case we require the 33-byte compressed form of the public key. We call + * these public keys primitive keys. + * + * If an account has primitive key associated to it, then the corresponding private key must sign + * any transaction to transfer cryptocurrency out of it. + * + * A Key can also be the ID of a smart contract instance, which is then authorized to perform any + * precompiled contract action that requires this key to sign. + * + * Note that when a Key is a smart contract ID, it doesn't mean the contract with that ID + * will actually create a cryptographic signature. It only means that when the contract calls a + * precompiled contract, the resulting "child transaction" will be authorized to perform any action + * controlled by the Key. + * + * A Key can be a "threshold key", which means a list of M keys, any N of which must sign in order + * for the threshold signature to be considered valid. The keys within a threshold signature may + * themselves be threshold signatures, to allow complex signature requirements. + * + * A Key can be a "key list" where all keys in the list must sign unless specified otherwise in the + * documentation for a specific transaction type (e.g. FileDeleteTransactionBody). Their use is + * dependent on context. For example, a Hedera file is created with a list of keys, where all of + * them must sign a transaction to create or modify the file, but only one of them is needed to sign + * a transaction to delete the file. So it's a single list that sometimes acts as a 1-of-M threshold + * key, and sometimes acts as an M-of-M threshold key. A key list is always an M-of-M, unless + * specified otherwise in documentation. A key list can have nested key lists or threshold keys. + * Nested key lists are always M-of-M. A key list can have repeated primitive public keys, but all + * repeated keys are only required to sign once. + * + * A Key can contain a ThresholdKey or KeyList, which in turn contain a Key, so this mutual + * recursion would allow nesting arbitrarily deep. A ThresholdKey which contains a list of primitive + * keys has 3 levels: ThresholdKey -> KeyList -> Key. A KeyList which contains several primitive + * keys has 2 levels: KeyList -> Key. A Key with 2 levels of nested ThresholdKeys has 7 levels: + * Key -> ThresholdKey -> KeyList -> Key -> ThresholdKey -> KeyList -> Key. + * + * Each Key should not have more than 46 levels, which implies 15 levels of nested ThresholdKeys. + */ +message Key { + oneof key { + /** + * smart contract instance that is authorized as if it had signed with a key + */ + ContractID contractID = 1; + + /** + * Ed25519 public key bytes + */ + bytes ed25519 = 2; + + /** + * (NOT SUPPORTED) RSA-3072 public key bytes + */ + bytes RSA_3072 = 3; + + /** + * (NOT SUPPORTED) ECDSA with the p-384 curve public key bytes + */ + bytes ECDSA_384 = 4; + + /** + * a threshold N followed by a list of M keys, any N of which are required to form a valid + * signature + */ + ThresholdKey thresholdKey = 5; + + /** + * A list of Keys of the Key type. + */ + KeyList keyList = 6; + + /** + * Compressed ECDSA(secp256k1) public key bytes + */ + bytes ECDSA_secp256k1 = 7; + + /** + * A smart contract that, if the recipient of the active message frame, should be treated + * as having signed. (Note this does not mean the code being executed in the frame + * will belong to the given contract, since it could be running another contract's code via + * delegatecall. So setting this key is a more permissive version of setting the + * contractID key, which also requires the code in the active message frame belong to the + * the contract with the given id.) + */ + ContractID delegatable_contract_id = 8; + } +} + +/** + * A set of public keys that are used together to form a threshold signature. If the threshold is N + * and there are M keys, then this is an N of M threshold signature. If an account is associated + * with ThresholdKeys, then a transaction to move cryptocurrency out of it must be signed by a list + * of M signatures, where at most M-N of them are blank, and the other at least N of them are valid + * signatures corresponding to at least N of the public keys listed here. + */ +message ThresholdKey { + /** + * A valid signature set must have at least this many signatures + */ + uint32 threshold = 1; + + /** + * List of all the keys that can sign + */ + KeyList keys = 2; +} + +/** + * A list of keys that requires all keys (M-of-M) to sign unless otherwise specified in + * documentation. A KeyList may contain repeated keys, but all repeated keys are only required to + * sign once. + */ +message KeyList { + /** + * list of keys + */ + repeated Key keys = 1; +} + +/** + * This message is DEPRECATED and UNUSABLE with network nodes. It is retained + * here only for historical reasons. + * + * Please use the SignaturePair and SignatureMap messages. + */ +message Signature { + option deprecated = true; + + oneof signature { + /** + * smart contract virtual signature (always length zero) + */ + bytes contract = 1; + + /** + * ed25519 signature bytes + */ + bytes ed25519 = 2; + + /** + * RSA-3072 signature bytes + */ + bytes RSA_3072 = 3; + + /** + * ECDSA p-384 signature bytes + */ + bytes ECDSA_384 = 4; + + /** + * A list of signatures for a single N-of-M threshold Key. This must be a list of exactly M + * signatures, at least N of which are non-null. + */ + ThresholdSignature thresholdSignature = 5; + + /** + * A list of M signatures, each corresponding to a Key in a KeyList of the same length. + */ + SignatureList signatureList = 6; + } +} + +/** + * This message is DEPRECATED and UNUSABLE with network nodes. It is retained + * here only for historical reasons. + * + * Please use the SignaturePair and SignatureMap messages. + */ +message ThresholdSignature { + option deprecated = true; + + /** + * for an N-of-M threshold key, this is a list of M signatures, at least N of which must be + * non-null + */ + SignatureList sigs = 2; +} + +/** + * This message is DEPRECATED and UNUSABLE with network nodes. It is retained + * here only for historical reasons. + * + * Please use the SignaturePair and SignatureMap messages. + */ +message SignatureList { + option deprecated = true; + + /** + * each signature corresponds to a Key in the KeyList + */ + repeated Signature sigs = 2; +} + +/** + * The client may use any number of bytes from zero to the whole length of the public key for + * pubKeyPrefix. If zero bytes are used, then it must be that only one primitive key is required + * to sign the linked transaction; it will surely resolve to INVALID_SIGNATURE otherwise. + * + * IMPORTANT: In the special case that a signature is being provided for a key used to + * authorize a precompiled contract, the pubKeyPrefix must contain the entire public + * key! That is, if the key is a Ed25519 key, the pubKeyPrefix should be 32 bytes + * long. If the key is a ECDSA(secp256k1) key, the pubKeyPrefix should be 33 bytes long, + * since we require the compressed form of the public key. + * + * Only Ed25519 and ECDSA(secp256k1) keys and hence signatures are currently supported. + */ +message SignaturePair { + /** + * First few bytes of the public key + */ + bytes pubKeyPrefix = 1; + + oneof signature { + /** + * smart contract virtual signature (always length zero) + */ + bytes contract = 2; + + /** + * ed25519 signature + */ + bytes ed25519 = 3; + + /** + * RSA-3072 signature + */ + bytes RSA_3072 = 4; + + /** + * ECDSA p-384 signature + */ + bytes ECDSA_384 = 5; + + /** + * ECDSA(secp256k1) signature + */ + bytes ECDSA_secp256k1 = 6; + } +} + +/** + * A set of signatures corresponding to every unique public key used to sign a given transaction. If + * one public key matches more than one prefixes on the signature map, the transaction containing + * the map will fail immediately with the response code KEY_PREFIX_MISMATCH. + */ +message SignatureMap { + /** + * Each signature pair corresponds to a unique Key required to sign the transaction. + */ + repeated SignaturePair sigPair = 1; +} + +/** + * The transactions and queries supported by Hedera Hashgraph. + */ +enum HederaFunctionality { + /** + * UNSPECIFIED - Need to keep first value as unspecified because first element is ignored and + * not parsed (0 is ignored by parser) + */ + NONE = 0; + + /** + * crypto transfer + */ + CryptoTransfer = 1; + + /** + * crypto update account + */ + CryptoUpdate = 2; + + /** + * crypto delete account + */ + CryptoDelete = 3; + + /** + * Add a livehash to a crypto account + */ + CryptoAddLiveHash = 4; + + /** + * Delete a livehash from a crypto account + */ + CryptoDeleteLiveHash = 5; + + /** + * Smart Contract Call + */ + ContractCall = 6; + + /** + * Smart Contract Create Contract + */ + ContractCreate = 7; + + /** + * Smart Contract update contract + */ + ContractUpdate = 8; + + /** + * File Operation create file + */ + FileCreate = 9; + + /** + * File Operation append file + */ + FileAppend = 10; + + /** + * File Operation update file + */ + FileUpdate = 11; + + /** + * File Operation delete file + */ + FileDelete = 12; + + /** + * crypto get account balance + */ + CryptoGetAccountBalance = 13; + + /** + * crypto get account record + */ + CryptoGetAccountRecords = 14; + + /** + * Crypto get info + */ + CryptoGetInfo = 15; + + /** + * Smart Contract Call + */ + ContractCallLocal = 16; + + /** + * Smart Contract get info + */ + ContractGetInfo = 17; + + /** + * Smart Contract, get the runtime code + */ + ContractGetBytecode = 18; + + /** + * Smart Contract, get by solidity ID + */ + GetBySolidityID = 19; + + /** + * Smart Contract, get by key + */ + GetByKey = 20; + + /** + * Get a live hash from a crypto account + */ + CryptoGetLiveHash = 21; + + /** + * Crypto, get the stakers for the node + */ + CryptoGetStakers = 22; + + /** + * File Operations get file contents + */ + FileGetContents = 23; + + /** + * File Operations get the info of the file + */ + FileGetInfo = 24; + + /** + * Crypto get the transaction records + */ + TransactionGetRecord = 25; + + /** + * Contract get the transaction records + */ + ContractGetRecords = 26; + + /** + * crypto create account + */ + CryptoCreate = 27; + + /** + * system delete file + */ + SystemDelete = 28; + + /** + * system undelete file + */ + SystemUndelete = 29; + + /** + * delete contract + */ + ContractDelete = 30; + + /** + * freeze + */ + Freeze = 31; + + /** + * Create Tx Record + */ + CreateTransactionRecord = 32; + + /** + * Crypto Auto Renew + */ + CryptoAccountAutoRenew = 33; + + /** + * Contract Auto Renew + */ + ContractAutoRenew = 34; + + /** + * Get Version + */ + GetVersionInfo = 35; + + /** + * Transaction Get Receipt + */ + TransactionGetReceipt = 36; + + /** + * Create Topic + */ + ConsensusCreateTopic = 50; + + /** + * Update Topic + */ + ConsensusUpdateTopic = 51; + + /** + * Delete Topic + */ + ConsensusDeleteTopic = 52; + + /** + * Get Topic information + */ + ConsensusGetTopicInfo = 53; + + /** + * Submit message to topic + */ + ConsensusSubmitMessage = 54; + + UncheckedSubmit = 55; + /** + * Create Token + */ + TokenCreate = 56; + + /** + * Get Token information + */ + TokenGetInfo = 58; + + /** + * Freeze Account + */ + TokenFreezeAccount = 59; + + /** + * Unfreeze Account + */ + TokenUnfreezeAccount = 60; + + /** + * Grant KYC to Account + */ + TokenGrantKycToAccount = 61; + + /** + * Revoke KYC from Account + */ + TokenRevokeKycFromAccount = 62; + + /** + * Delete Token + */ + TokenDelete = 63; + + /** + * Update Token + */ + TokenUpdate = 64; + + /** + * Mint tokens to treasury + */ + TokenMint = 65; + + /** + * Burn tokens from treasury + */ + TokenBurn = 66; + + /** + * Wipe token amount from Account holder + */ + TokenAccountWipe = 67; + + /** + * Associate tokens to an account + */ + TokenAssociateToAccount = 68; + + /** + * Dissociate tokens from an account + */ + TokenDissociateFromAccount = 69; + + /** + * Create Scheduled Transaction + */ + ScheduleCreate = 70; + + /** + * Delete Scheduled Transaction + */ + ScheduleDelete = 71; + + /** + * Sign Scheduled Transaction + */ + ScheduleSign = 72; + + /** + * Get Scheduled Transaction Information + */ + ScheduleGetInfo = 73; + + /** + * Get Token Account Nft Information + */ + TokenGetAccountNftInfos = 74; + + /** + * Get Token Nft Information + */ + TokenGetNftInfo = 75; + + /** + * Get Token Nft List Information + */ + TokenGetNftInfos = 76; + + /** + * Update a token's custom fee schedule, if permissible + */ + TokenFeeScheduleUpdate = 77; + + /** + * Get execution time(s) by TransactionID, if available + */ + NetworkGetExecutionTime = 78; + + /** + * Pause the Token + */ + TokenPause = 79; + + /** + * Unpause the Token + */ + TokenUnpause = 80; + + /** + * Approve allowance for a spender relative to the owner account + */ + CryptoApproveAllowance = 81; + + /** + * Deletes granted allowances on owner account + */ + CryptoDeleteAllowance = 82; + + /** + * Gets all the information about an account, including balance and allowances. This does not get the list of + * account records. + */ + GetAccountDetails = 83; + + /** + * Ethereum Transaction + */ + EthereumTransaction = 84; + + /** + * Updates the staking info at the end of staking period to indicate new staking period has started. + */ + NodeStakeUpdate = 85; + + /** + * Generates a pseudorandom number. + */ + UtilPrng = 86; +} + +/** + * A set of prices the nodes use in determining transaction and query fees, and constants involved + * in fee calculations. Nodes multiply the amount of resources consumed by a transaction or query + * by the corresponding price to calculate the appropriate fee. Units are one-thousandth of a + * tinyCent. + */ +message FeeComponents { + /** + * A minimum, the calculated fee must be greater than this value + */ + int64 min = 1; + + /** + * A maximum, the calculated fee must be less than this value + */ + int64 max = 2; + + /** + * A constant contribution to the fee + */ + int64 constant = 3; + + /** + * The price of bandwidth consumed by a transaction, measured in bytes + */ + int64 bpt = 4; + + /** + * The price per signature verification for a transaction + */ + int64 vpt = 5; + + /** + * The price of RAM consumed by a transaction, measured in byte-hours + */ + int64 rbh = 6; + + /** + * The price of storage consumed by a transaction, measured in byte-hours + */ + int64 sbh = 7; + + /** + * The price of computation for a smart contract transaction, measured in gas + */ + int64 gas = 8; + + /** + * The price per hbar transferred for a transfer + */ + int64 tv = 9; + + /** + * The price of bandwidth for data retrieved from memory for a response, measured in bytes + */ + int64 bpr = 10; + + /** + * The price of bandwidth for data retrieved from disk for a response, measured in bytes + */ + int64 sbpr = 11; +} + +/** + * The fees for a specific transaction or query based on the fee data. + */ +message TransactionFeeSchedule { + /** + * A particular transaction or query + */ + HederaFunctionality hederaFunctionality = 1; + + /** + * Resource price coefficients + */ + FeeData feeData = 2 [deprecated=true]; + + /** + * Resource price coefficients. Supports subtype price definition. + */ + repeated FeeData fees = 3; +} + +/** + * The total fee charged for a transaction. It is composed of three components – a node fee that + * compensates the specific node that submitted the transaction, a network fee that compensates the + * network for assigning the transaction a consensus timestamp, and a service fee that compensates + * the network for the ongoing maintenance of the consequences of the transaction. + */ +message FeeData { + /** + * Fee paid to the submitting node + */ + FeeComponents nodedata = 1; + + /** + * Fee paid to the network for processing a transaction into consensus + */ + FeeComponents networkdata = 2; + + /** + * Fee paid to the network for providing the service associated with the + * transaction; for instance, storing a file + */ + FeeComponents servicedata = 3; + + /** + * SubType distinguishing between different types of FeeData, correlating + * to the same HederaFunctionality + */ + SubType subType = 4; +} + +/** + * A list of resource prices fee for different transactions and queries and the time period at which + * this fee schedule will expire. Nodes use the prices to determine the fees for all transactions + * based on how much of those resources each transaction uses. + */ +message FeeSchedule { + /** + * List of price coefficients for network resources + */ + repeated TransactionFeeSchedule transactionFeeSchedule = 1; + + /** + * FeeSchedule expiry time + */ + TimestampSeconds expiryTime = 2; +} + +/** + * This contains two Fee Schedules with expiry timestamp. + */ +message CurrentAndNextFeeSchedule { + /** + * Contains current Fee Schedule + */ + FeeSchedule currentFeeSchedule = 1; + + /** + * Contains next Fee Schedule + */ + FeeSchedule nextFeeSchedule = 2; +} + +/** + * Contains the IP address and the port representing a service endpoint of a Node in a network. Used + * to reach the Hedera API and submit transactions to the network. + */ +message ServiceEndpoint { + /** + * The 32-bit IPv4 address of the node encoded in left to right order (e.g. 127.0.0.1 has 127 + * as its first byte) + */ + bytes ipAddressV4 = 1; + + /** + * The port of the node + */ + int32 port = 2; +} + +/** + * The data about a node, including its service endpoints and the Hedera account to be paid for + * services provided by the node (that is, queries answered and transactions submitted.) + * + * If the serviceEndpoint list is not set, or empty, then the endpoint given by the + * (deprecated) ipAddress and portno fields should be used. + * + * All fields are populated in the 0.0.102 address book file while only fields that start with # are + * populated in the 0.0.101 address book file. + */ +message NodeAddress { + /** + * The IP address of the Node with separator & octets encoded in UTF-8. Usage is deprecated, + * ServiceEndpoint is preferred to retrieve a node's list of IP addresses and ports + */ + bytes ipAddress = 1 [deprecated=true]; + + /** + * The port number of the grpc server for the node. Usage is deprecated, ServiceEndpoint is + * preferred to retrieve a node's list of IP addresses and ports + */ + int32 portno = 2 [deprecated=true]; + + /** + * Usage is deprecated, nodeAccountId is preferred to retrieve a node's account ID + */ + bytes memo = 3 [deprecated=true]; + + /** + * The node's X509 RSA public key used to sign stream files (e.g., record stream + * files). Precisely, this field is a string of hexadecimal characters which, + * translated to binary, are the public key's DER encoding. + */ + string RSA_PubKey = 4; + + /** + * # A non-sequential identifier for the node + */ + int64 nodeId = 5; + + /** + * # The account to be paid for queries and transactions sent to this node + */ + AccountID nodeAccountId = 6; + + /** + * # Hash of the node's TLS certificate. Precisely, this field is a string of + * hexadecimal characters which, translated to binary, are the SHA-384 hash of + * the UTF-8 NFKD encoding of the node's TLS cert in PEM format. Its value can be + * used to verify the node's certificate it presents during TLS negotiations. + */ + bytes nodeCertHash = 7; + + /** + * # A node's service IP addresses and ports + */ + repeated ServiceEndpoint serviceEndpoint = 8; + + /** + * A description of the node, with UTF-8 encoding up to 100 bytes + */ + string description = 9; + + /** + * [Deprecated] The amount of tinybars staked to the node + */ + int64 stake = 10 [deprecated = true]; +} + +/** + * A list of nodes and their metadata that contains all details of the nodes for the network. Used + * to parse the contents of system files 0.0.101 and 0.0.102. + */ +message NodeAddressBook { + /** + * Metadata of all nodes in the network + */ + repeated NodeAddress nodeAddress = 1; +} + +/** + * Hedera follows semantic versioning (https://semver.org/) for both the HAPI protobufs and the + * Services software. This type allows the getVersionInfo query in the + * NetworkService to return the deployed versions of both protobufs and software on the + * node answering the query. + */ +message SemanticVersion { + /** + * Increases with incompatible API changes + */ + int32 major = 1; + + /** + * Increases with backwards-compatible new functionality + */ + int32 minor = 2; + + /** + * Increases with backwards-compatible bug fixes + */ + int32 patch = 3; + + /** + * A pre-release version MAY be denoted by appending a hyphen and a series of dot separated + * identifiers (https://semver.org/#spec-item-9); so given a semver 0.14.0-alpha.1+21AF26D3, + * this field would contain 'alpha.1' + */ + string pre = 4; + + /** + * Build metadata MAY be denoted by appending a plus sign and a series of dot separated + * identifiers immediately following the patch or pre-release version + * (https://semver.org/#spec-item-10); so given a semver 0.14.0-alpha.1+21AF26D3, this field + * would contain '21AF26D3' + */ + string build = 5; +} + +/** + * UNDOCUMENTED + */ +message Setting { + /** + * name of the property + */ + string name = 1; + + /** + * value of the property + */ + string value = 2; + + /** + * any data associated with property + */ + bytes data = 3; +} + +/** + * UNDOCUMENTED + */ +message ServicesConfigurationList { + /** + * list of name value pairs of the application properties + */ + repeated Setting nameValue = 1; +} + +/** + * Token's information related to the given Account + */ +message TokenRelationship { + /** + * The ID of the token + */ + TokenID tokenId = 1; + + /** + * The Symbol of the token + */ + string symbol = 2; + + /** + * For token of type FUNGIBLE_COMMON - the balance that the Account holds in the smallest + * denomination. For token of type NON_FUNGIBLE_UNIQUE - the number of NFTs held by the account + */ + uint64 balance = 3; + + /** + * The KYC status of the account (KycNotApplicable, Granted or Revoked). If the token does not + * have KYC key, KycNotApplicable is returned + */ + TokenKycStatus kycStatus = 4; + + /** + * The Freeze status of the account (FreezeNotApplicable, Frozen or Unfrozen). If the token does + * not have Freeze key, FreezeNotApplicable is returned + */ + TokenFreezeStatus freezeStatus = 5; + + /** + * Tokens divide into 10decimals pieces + */ + uint32 decimals = 6; + + /** + * Specifies if the relationship is created implicitly. False : explicitly associated, True : + * implicitly associated. + */ + bool automatic_association = 7; +} + +/** + * A number of transferable units of a certain token. + * + * The transferable unit of a token is its smallest denomination, as given by the token's + * decimals property---each minted token contains 10decimals + * transferable units. For example, we could think of the cent as the transferable unit of the US + * dollar (decimals=2); and the tinybar as the transferable unit of hbar + * (decimals=8). + * + * Transferable units are not directly comparable across different tokens. + */ +message TokenBalance { + /** + * A unique token id + */ + TokenID tokenId = 1; + + /** + * Number of transferable units of the identified token. For token of type FUNGIBLE_COMMON - + * balance in the smallest denomination. For token of type NON_FUNGIBLE_UNIQUE - the number of + * NFTs held by the account + */ + uint64 balance = 2; + + /** + * Tokens divide into 10decimals pieces + */ + uint32 decimals = 3; +} + +/** + * A sequence of token balances + */ +message TokenBalances { + repeated TokenBalance tokenBalances = 1; +} + +/* A token - account association */ +message TokenAssociation { + TokenID token_id = 1; // The token involved in the association + AccountID account_id = 2; // The account involved in the association +} + +/** + * Staking metadata for an account or a contract returned in CryptoGetInfo or ContractGetInfo queries + */ +message StakingInfo { + + /** + * If true, this account or contract declined to receive a staking reward. + */ + bool decline_reward = 1; + + /** + * The staking period during which either the staking settings for this account or contract changed (such as starting + * staking or changing staked_node_id) or the most recent reward was earned, whichever is later. If this account or contract + * is not currently staked to a node, then this field is not set. + */ + Timestamp stake_period_start = 2; + + /** + * The amount in tinybars that will be received in the next reward situation. + */ + int64 pending_reward = 3; + + /** + * The total of balance of all accounts staked to this account or contract. + */ + int64 staked_to_me = 4; + + /** + * ID of the account or node to which this account or contract is staking. + */ + oneof staked_id { + + /** + * The account to which this account or contract is staking. + */ + AccountID staked_account_id = 5; + + /** + * The ID of the node this account or contract is staked to. + */ + int64 staked_node_id = 6; + } +} diff --git a/src/Hedera/Protobuf/crypto_transfer.proto b/src/Hedera/Protobuf/crypto_transfer.proto new file mode 100644 index 00000000000..0c6c0b1b23e --- /dev/null +++ b/src/Hedera/Protobuf/crypto_transfer.proto @@ -0,0 +1,55 @@ +// Taken from https://github.com/hashgraph/hedera-protobufs/tree/main/services + +syntax = "proto3"; + +package proto; + +/*- + * ‌ + * Hedera Network Services Protobuf + * ​ + * Copyright (C) 2018 - 2021 Hedera Hashgraph, LLC + * ​ + * 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. + * ‍ + */ + +option java_package = "com.hederahashgraph.api.proto.java"; +option java_multiple_files = true; + +import "basic_types.proto"; + +/** + * Transfers cryptocurrency among two or more accounts by making the desired adjustments to their + * balances. Each transfer list can specify up to 10 adjustments. Each negative amount is withdrawn + * from the corresponding account (a sender), and each positive one is added to the corresponding + * account (a receiver). The amounts list must sum to zero. Each amount is a number of tinybars + * (there are 100,000,000 tinybars in one hbar). If any sender account fails to have sufficient + * hbars, then the entire transaction fails, and none of those transfers occur, though the + * transaction fee is still charged. This transaction must be signed by the keys for all the sending + * accounts, and for any receiving accounts that have receiverSigRequired == true. The signatures + * are in the same order as the accounts, skipping those accounts that don't need a signature. + */ +message CryptoTransferTransactionBody { + /** + * The desired hbar balance adjustments + */ + TransferList transfers = 1; + + /** + * The desired token unit balance adjustments; if any custom fees are assessed, the ledger will + * try to deduct them from the payer of this CryptoTransfer, resolving the transaction to + * INSUFFICIENT_PAYER_BALANCE_FOR_CUSTOM_FEE if this is not possible + */ + repeated TokenTransferList tokenTransfers = 2; +} diff --git a/src/Hedera/Protobuf/duration.proto b/src/Hedera/Protobuf/duration.proto new file mode 100644 index 00000000000..2b096068c8c --- /dev/null +++ b/src/Hedera/Protobuf/duration.proto @@ -0,0 +1,38 @@ +// Taken from https://github.com/hashgraph/hedera-protobufs/tree/main/services + +syntax = "proto3"; + +package proto; + +/*- + * ‌ + * Hedera Network Services Protobuf + * ​ + * Copyright (C) 2018 - 2021 Hedera Hashgraph, LLC + * ​ + * 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. + * ‍ + */ + +option java_package = "com.hederahashgraph.api.proto.java"; +option java_multiple_files = true; + +/** + * A length of time in seconds. + */ +message Duration { + /** + * The number of seconds + */ + int64 seconds = 1; +} diff --git a/src/Hedera/Protobuf/timestamp.proto b/src/Hedera/Protobuf/timestamp.proto new file mode 100644 index 00000000000..b7e8e9a8831 --- /dev/null +++ b/src/Hedera/Protobuf/timestamp.proto @@ -0,0 +1,54 @@ +// Taken from https://github.com/hashgraph/hedera-protobufs/tree/main/services + +syntax = "proto3"; + +package proto; + +/*- + * ‌ + * Hedera Network Services Protobuf + * ​ + * Copyright (C) 2018 - 2021 Hedera Hashgraph, LLC + * ​ + * 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. + * ‍ + */ + +option java_package = "com.hederahashgraph.api.proto.java"; +option java_multiple_files = true; + +/** + * An exact date and time. This is the same data structure as the protobuf Timestamp.proto (see the + * comments in https://github.com/google/protobuf/blob/master/src/google/protobuf/timestamp.proto) + */ +message Timestamp { + /** + * Number of complete seconds since the start of the epoch + */ + int64 seconds = 1; + + /** + * Number of nanoseconds since the start of the last second + */ + int32 nanos = 2; +} + +/** + * An exact date and time, with a resolution of one second (no nanoseconds). + */ +message TimestampSeconds { + /** + * Number of complete seconds since the start of the epoch + */ + int64 seconds = 1; +} diff --git a/src/Hedera/Protobuf/transaction_body.proto b/src/Hedera/Protobuf/transaction_body.proto new file mode 100644 index 00000000000..0687b6f851d --- /dev/null +++ b/src/Hedera/Protobuf/transaction_body.proto @@ -0,0 +1,76 @@ +// Taken from https://github.com/hashgraph/hedera-protobufs/tree/main/services + +syntax = "proto3"; + +package proto; + +/*- + * ‌ + * Hedera Network Services Protobuf + * ​ + * Copyright (C) 2018 - 2021 Hedera Hashgraph, LLC + * ​ + * 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. + * ‍ + */ + +option java_package = "com.hederahashgraph.api.proto.java"; +option java_multiple_files = true; + +import "crypto_transfer.proto"; +import "duration.proto"; +import "basic_types.proto"; + +/** + * A single transaction. All transaction types are possible here. + */ +message TransactionBody { + /** + * The ID for this transaction, which includes the payer's account (the account paying the + * transaction fee). If two transactions have the same transactionID, they won't both have an + * effect + */ + TransactionID transactionID = 1; + + /** + * The account of the node that submits the client's transaction to the network + */ + AccountID nodeAccountID = 2; + + /** + * The maximum transaction fee the client is willing to pay + */ + uint64 transactionFee = 3; + + /** + * The transaction is invalid if consensusTimestamp > transactionID.transactionValidStart + + * transactionValidDuration + */ + Duration transactionValidDuration = 4; + + /** + * Any notes or descriptions that should be put into the record (max length 100) + */ + string memo = 6; + + /** + * The choices here are arranged by service in roughly lexicographical order. The field ordinals are non-sequential, and a result of the historical order of implementation. + */ + oneof data { + + /** + * Transfer amount between accounts + */ + CryptoTransferTransactionBody cryptoTransfer = 14; + } +} diff --git a/src/Hedera/Protobuf/transaction_contents.proto b/src/Hedera/Protobuf/transaction_contents.proto new file mode 100644 index 00000000000..2af320a2220 --- /dev/null +++ b/src/Hedera/Protobuf/transaction_contents.proto @@ -0,0 +1,42 @@ +// Taken from https://github.com/hashgraph/hedera-protobufs/tree/main/services + +syntax = "proto3"; + +package proto; + +/*- + * ‌ + * Hedera Network Services Protobuf + * ​ + * Copyright (C) 2018 - 2021 Hedera Hashgraph, LLC + * ​ + * 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. + * ‍ + */ + +option java_package = "com.hederahashgraph.api.proto.java"; +option java_multiple_files = true; + +import "basic_types.proto"; + +message SignedTransaction { + /** + * TransactionBody serialized into bytes, which needs to be signed + */ + bytes bodyBytes = 1; + + /** + * The signatures on the body with the new format, to authorize the transaction + */ + SignatureMap sigMap = 2; +} diff --git a/src/Hedera/Signer.cpp b/src/Hedera/Signer.cpp new file mode 100644 index 00000000000..feb90281317 --- /dev/null +++ b/src/Hedera/Signer.cpp @@ -0,0 +1,107 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Signer.h" +#include "Address.h" +#include "HexCoding.h" +#include "Protobuf/transaction_body.pb.h" +#include "Protobuf/transaction_contents.pb.h" +#include "../PublicKey.h" + +namespace TW::Hedera::internals { +static inline proto::AccountID accountIDfromStr(const std::string& input) { + const auto hederaAccount = Address(input); + auto accountID = proto::AccountID(); + accountID.set_accountnum(static_cast(hederaAccount.num())); + accountID.set_realmnum(static_cast(hederaAccount.realm())); + accountID.set_shardnum(static_cast(hederaAccount.shard())); + return accountID; +} + +static inline proto::Timestamp timestampFromTWProto(const Proto::Timestamp& input) { + auto timestamp = proto::Timestamp(); + timestamp.set_seconds(input.seconds()); + timestamp.set_nanos(input.nanos()); + return timestamp; +} + +static inline proto::TransactionID transactionIDFromSigningInput(const Proto::SigningInput& input) { + auto transactionID = proto::TransactionID(); + *transactionID.mutable_transactionvalidstart() = timestampFromTWProto(input.body().transactionid().transactionvalidstart()); + *transactionID.mutable_accountid() = accountIDfromStr(input.body().transactionid().accountid()); + return transactionID; +} + +static inline proto::TransactionBody transactionBodyPrerequisites(const Proto::SigningInput& input) { + auto body = proto::TransactionBody(); + body.set_memo(input.body().memo()); + body.set_transactionfee(input.body().transactionfee()); + *body.mutable_nodeaccountid() = accountIDfromStr(input.body().nodeaccountid()); + body.mutable_transactionvalidduration()->set_seconds(input.body().transactionvalidduration()); + *body.mutable_transactionid() = transactionIDFromSigningInput(input); + return body; +} + +static inline proto::TransferList transferListFromInput(const Proto::SigningInput& input) { + auto transferList = proto::TransferList(); + auto fromAccountID = accountIDfromStr(input.body().transfer().from()); + auto amount = input.body().transfer().amount(); + auto* to = transferList.add_accountamounts(); + to->set_amount(amount); + *to->mutable_accountid() = accountIDfromStr(input.body().transfer().to()); + auto* from = transferList.add_accountamounts(); + from->set_amount(-amount); + *from->mutable_accountid() = fromAccountID; + return transferList; +} + +static inline proto::CryptoTransferTransactionBody cryptoTransferFromInput(const Proto::SigningInput& input) { + auto transferList = transferListFromInput(input); + auto cryptoTransfer = proto::CryptoTransferTransactionBody(); + *cryptoTransfer.mutable_transfers() = transferList; + return cryptoTransfer; +} + +static inline Proto::SigningOutput sign(const proto::TransactionBody& body, const PrivateKey& privateKey) { + auto protoOutput = Proto::SigningOutput(); + Data encoded; + auto encodedBody = data(body.SerializeAsString()); + auto signedBody = privateKey.sign(encodedBody, TWCurveED25519); + auto sigMap = proto::SignatureMap(); + auto* sigPair = sigMap.add_sigpair(); + sigPair->set_ed25519(signedBody.data(), signedBody.size()); + auto pubKey = privateKey.getPublicKey(TWPublicKeyTypeED25519).bytes; + sigPair->set_pubkeyprefix(pubKey.data(), pubKey.size()); + auto signedTx = proto::SignedTransaction(); + signedTx.set_bodybytes(encodedBody.data(), encodedBody.size()); + *signedTx.mutable_sigmap() = sigMap; + encoded = data(signedTx.SerializeAsString()); + protoOutput.set_encoded(encoded.data(), encoded.size()); + return protoOutput; +} + +} // namespace TW::Hedera::internals + +namespace TW::Hedera { + +Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { + auto privateKey = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); + auto body = internals::transactionBodyPrerequisites(input); + + switch (input.body().data_case()) { + case Proto::TransactionBody::kTransfer: { + *body.mutable_cryptotransfer() = internals::cryptoTransferFromInput(input); + break; + } + case Proto::TransactionBody::DATA_NOT_SET: + break; + default: + break; + } + return internals::sign(body, privateKey); +} + +} // namespace TW::Hedera diff --git a/src/Hedera/Signer.h b/src/Hedera/Signer.h new file mode 100644 index 00000000000..19a54e3052a --- /dev/null +++ b/src/Hedera/Signer.h @@ -0,0 +1,25 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" +#include "../PrivateKey.h" +#include "../proto/Hedera.pb.h" + +namespace TW::Hedera { + +/// Helper class that performs Hedera transaction signing. +class Signer { +public: + /// Hide default constructor + Signer() = delete; + + /// Signs a Proto::SigningInput transaction + static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept; +}; + +} // namespace TW::Hedera diff --git a/src/algorithm/string.hpp b/src/algorithm/string.hpp new file mode 100644 index 00000000000..c5c1bfdfe79 --- /dev/null +++ b/src/algorithm/string.hpp @@ -0,0 +1,27 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include +#include + +namespace TW { + +static std::vector ssplit(const std::string& input, char delimiter) { + std::istringstream iss(input); + std::vector tokens; + std::string token; + while (std::getline(iss, token, delimiter)) { + if (!token.empty()) { + tokens.emplace_back(token); + } + } + return tokens; +} + +} // namespace TW diff --git a/src/proto/Hedera.proto b/src/proto/Hedera.proto new file mode 100644 index 00000000000..ff9a2746eaf --- /dev/null +++ b/src/proto/Hedera.proto @@ -0,0 +1,98 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +syntax = "proto3"; + +package TW.Hedera.Proto; +option java_package = "wallet.core.jni.proto"; + +// An exact date and time. This is the same data structure as the protobuf Timestamp.proto +// (see the comments in https://github.com/google/protobuf/blob/master/src/google/protobuf/timestamp.proto) +message Timestamp { + // Number of complete seconds since the start of the epoch + int64 seconds = 1; + // Number of nanoseconds since the start of the last second + int32 nanos = 2; +} + +// The ID for a transaction. This is used for retrieving receipts and records for a transaction, for +// appending to a file right after creating it, for instantiating a smart contract with bytecode in +// a file just created, and internally by the network for detecting when duplicate transactions are +// submitted. A user might get a transaction processed faster by submitting it to N nodes, each with +// a different node account, but all with the same TransactionID. Then, the transaction will take +// effect when the first of all those nodes submits the transaction and it reaches consensus. The +// other transactions will not take effect. So this could make the transaction take effect faster, +// if any given node might be slow. However, the full transaction fee is charged for each +// transaction, so the total fee is N times as much if the transaction is sent to N nodes. +// +// Applicable to Scheduled Transactions: +// - The ID of a Scheduled Transaction has transactionValidStart and accountIDs inherited from the +// ScheduleCreate transaction that created it. That is to say that they are equal +// - The scheduled property is true for Scheduled Transactions +// - transactionValidStart, accountID and scheduled properties should be omitted +message TransactionID { + // The transaction is invalid if consensusTimestamp < transactionID.transactionStartValid + Timestamp transactionValidStart = 1; + // The Account ID that paid for this transaction + string accountID = 2; + // Whether the Transaction is of type Scheduled or no + bool scheduled = 3; + // The identifier for an internal transaction that was spawned as part + // of handling a user transaction. (These internal transactions share the + // transactionValidStart and accountID of the user transaction, so a + // nonce is necessary to give them a unique TransactionID.) + // + // An example is when a "parent" ContractCreate or ContractCall transaction + // calls one or more HTS precompiled contracts; each of the "child" transactions spawned for a precompile has a id + // with a different nonce. + int32 nonce = 4; +} + +// Necessary fields to process a TransferMessage +message TransferMessage { + // Source Account address (string) + string from = 1; + // Destination Account address (string) + string to = 2; + // Amount to be transferred (sint64) + sint64 amount = 3; +} + +// A single transaction. All transaction types are possible here. +message TransactionBody { + // The ID for this transaction, which includes the payer's account (the account paying the transaction fee). + // If two transactions have the same transactionID, they won't both have an effect + TransactionID transactionID = 1; + // The account of the node that submits the client's transaction to the network + string nodeAccountID = 2; + // The maximum transaction fee the client is willing to pay + uint64 transactionFee = 3; + // The transaction is invalid if consensusTimestamp > transactionID.transactionValidStart + transactionValidDuration + int64 transactionValidDuration = 4; + // Any notes or descriptions that should be put into the record (max length 100) + string memo = 5; + // The choices here are arranged by service in roughly lexicographical order. The field ordinals are non-sequential, + // and a result of the historical order of implementation. + oneof data { + // Transfer amount between accounts + TransferMessage transfer = 6; + } +} + +// Input data necessary to create a signed transaction. +message SigningInput { + // Private key to sign the transaction (bytes) + bytes private_key = 1; + + // The transaction body + TransactionBody body = 2; +} + +// Transaction signing output. +message SigningOutput { + // Signed and encoded transaction bytes. + bytes encoded = 1; +} diff --git a/swift/Tests/Blockchains/HederaTests.swift b/swift/Tests/Blockchains/HederaTests.swift new file mode 100644 index 00000000000..c71dd7d1f87 --- /dev/null +++ b/swift/Tests/Blockchains/HederaTests.swift @@ -0,0 +1,59 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import WalletCore +import XCTest + +class HederaTests: XCTestCase { + func testAddress() { + let anyAddress = AnyAddress(string: "0.0.1377988", coin: .hedera) + + XCTAssertEqual(anyAddress?.description, "0.0.1377988") + XCTAssertEqual(anyAddress?.coin, .hedera) + + let invalid = "0.0.a" + XCTAssertNil(Data(hexString: invalid)) + XCTAssertNil(AnyAddress(string: invalid, coin: .hedera)) + XCTAssertFalse(AnyAddress.isValid(string: invalid, coin: .hedera)) + } + + func testSignSimpleTransfer() { + // Successfully broadcasted: https://hashscan.io/testnet/transaction/0.0.48694347-1667222879-749068449?t=1667222891.440398729&p=1 + let privateKeyData = Data(hexString: "e87a5584c0173263e138db689fdb2a7389025aaae7cb1a18a1017d76012130e8")! + + let transfer = HederaTransferMessage.with { + $0.amount = 100000000 + $0.from = "0.0.48694347" + $0.to = "0.0.48462050" + } + + let transactionID = HederaTransactionID.with { + $0.accountID = "0.0.48694347" + $0.transactionValidStart = HederaTimestamp.with { + $0.seconds = 1667222879 + $0.nanos = 749068449 + } + } + + let body = HederaTransactionBody.with { + $0.memo = "" + $0.nodeAccountID = "0.0.9" + $0.transactionFee = 100000000 + $0.transactionValidDuration = 120 + $0.transactionID = transactionID + $0.transfer = transfer + } + + let input = HederaSigningInput.with { + $0.privateKey = privateKeyData + $0.body = body + } + + let output: HederaSigningOutput = AnySigner.sign(input: input, coin: .hedera) + let expectedEncoded = "0a440a150a0c08df9aff9a0610a1c197e502120518cb889c17120218091880c2d72f22020878721e0a1c0a0c0a0518e2f18d17108084af5f0a0c0a0518cb889c1710ff83af5f12660a640a205d3a70d08b2beafb72c7a68986b3ff819a306078b8c359d739e4966e82e6d40e1a40612589c3b15f1e3ed6084b5a3a5b1b81751578cac8d6c922f31731b3982a5bac80a22558b2197276f5bae49b62503a4d39448ceddbc5ef3ba9bee4c0f302f70c" + XCTAssertEqual(output.encoded.hexString, expectedEncoded) + } +} diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 5dd2b6d4ef4..83311e02ca9 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -256,6 +256,10 @@ class CoinAddressDerivationTests: XCTestCase { case .aptos: let expectedResult = "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"; assertCoinDerivation(coin, expectedResult, derivedAddress, address) + case .hedera: + let expectedResult = "0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5"; + assertCoinDerivation(coin, expectedResult, derivedAddress, address) + @unknown default: fatalError() } diff --git a/tests/chains/Hedera/AddressTests.cpp b/tests/chains/Hedera/AddressTests.cpp new file mode 100644 index 00000000000..9a740750d41 --- /dev/null +++ b/tests/chains/Hedera/AddressTests.cpp @@ -0,0 +1,58 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "Hedera/Address.h" +#include "PublicKey.h" +#include "PrivateKey.h" + +#include "TestUtilities.h" + +#include +#include + +namespace TW::Hedera::tests { + +TEST(HederaAddress, FromStandardArgument) { + { + // 0.0.1377988 + Address addr(0uL, 0uL, 1'377'988uL); + ASSERT_EQ(addr.shard(), 0uL); + ASSERT_EQ(addr.realm(), 0uL); + ASSERT_EQ(addr.num(), 1'377'988uL); + ASSERT_EQ(addr.string(), "0.0.1377988"); + ASSERT_TRUE(addr.isValid(addr.string())); + } + + { + // 0.0.302a300506032b65700321007df3e1ab790b28de4706d36a7aa99a0e043cb3e2c3d6ec6686e4af7f638b0860 + // https://github.com/hashgraph/hedera-sdk-rust/blob/c1c10d5750552e6bb857132cc824c430bd890a6b/sdk/rust/src/key/public_key/mod.rs#L306 + auto pubkey = PublicKey(parse_hex("7df3e1ab790b28de4706d36a7aa99a0e043cb3e2c3d6ec6686e4af7f638b0860"), TWPublicKeyTypeED25519); + Address addr(0uL, 0uL, 0uL, pubkey); + ASSERT_EQ(addr.shard(), 0uL); + ASSERT_EQ(addr.realm(), 0uL); + ASSERT_EQ(addr.num(), 0uL); + ASSERT_EQ(addr.alias().string(), "302a300506032b65700321007df3e1ab790b28de4706d36a7aa99a0e043cb3e2c3d6ec6686e4af7f638b0860"); + ASSERT_EQ(addr.string(), "0.0.302a300506032b65700321007df3e1ab790b28de4706d36a7aa99a0e043cb3e2c3d6ec6686e4af7f638b0860"); + ASSERT_TRUE(addr.isValid(addr.string())); + } +} + +TEST(HederaAddress, Valid) { + ASSERT_FALSE(Address::isValid("invalid")); + ASSERT_FALSE(Address::isValid("302a300506032b65700321007df3e1ab790b28de4706d36a7aa99a0e043cb3e2c3d6ec6686e4af7f638b0860")); + ASSERT_FALSE(Address::isValid("0.0.abc")); + ASSERT_TRUE(Address::isValid("0.0.1")); + ASSERT_TRUE(Address::isValid("0.0.1377988")); + ASSERT_TRUE(Address::isValid("0.0.302a300506032b65700321007df3e1ab790b28de4706d36a7aa99a0e043cb3e2c3d6ec6686e4af7f638b0860")); +} + +TEST(HederaAddress, FromString) { + auto address = Address("0.0.1377988"); + ASSERT_EQ(address.string(), "0.0.1377988"); +} + +} // namespace TW::Hedera::tests diff --git a/tests/chains/Hedera/SignerTests.cpp b/tests/chains/Hedera/SignerTests.cpp new file mode 100644 index 00000000000..f39c6d10915 --- /dev/null +++ b/tests/chains/Hedera/SignerTests.cpp @@ -0,0 +1,238 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Hedera/Address.h" +#include "Hedera/Protobuf/basic_types.pb.h" +#include "Hedera/Protobuf/crypto_transfer.pb.h" +#include "Hedera/Protobuf/transaction_body.pb.h" +#include "Hedera/Signer.h" +#include "HexCoding.h" +#include "PrivateKey.h" +#include "PublicKey.h" + +#include + +namespace TW::Hedera::tests { + +TEST(HederaSigner, Sign) { + // Successfully broadcasted: https://hashscan.io/testnet/transaction/0.0.48694347-1667222879-749068449?t=1667222891.440398729&p=1 + Proto::SigningInput input; + auto privateKey = PrivateKey(parse_hex("e87a5584c0173263e138db689fdb2a7389025aaae7cb1a18a1017d76012130e8")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto* body = input.mutable_body(); + + *body->mutable_memo() = ""; + *body->mutable_nodeaccountid() = "0.0.9"; + body->set_transactionfee(100000000); + body->set_transactionvalidduration(120); + auto* transferMsg = body->mutable_transfer(); + transferMsg->set_from("0.0.48694347"); + transferMsg->set_to("0.0.48462050"); + transferMsg->set_amount(100000000); + + auto* transactionID = body->mutable_transactionid(); + transactionID->mutable_transactionvalidstart()->set_seconds(1667222879); + transactionID->mutable_transactionvalidstart()->set_nanos(749068449); + transactionID->set_accountid("0.0.48694347"); + + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.encoded()), "0a440a150a0c08df9aff9a0610a1c197e502120518cb889c17120218091880c2d72f22020878721e0a1c0a0c0a0518e2f18d17108084af5f0a0c0a0518cb889c1710ff83af5f12660a640a205d3a70d08b2beafb72c7a68986b3ff819a306078b8c359d739e4966e82e6d40e1a40612589c3b15f1e3ed6084b5a3a5b1b81751578cac8d6c922f31731b3982a5bac80a22558b2197276f5bae49b62503a4d39448ceddbc5ef3ba9bee4c0f302f70c"); +} + +TEST(HederaSigner, SignWithMemo) { + // Successfully broadcasted: https://hashscan.io/testnet/transaction/0.0.48694347-1667227300-854561449?t=1667227312.554926003 + Proto::SigningInput input; + auto privateKey = PrivateKey(parse_hex("e87a5584c0173263e138db689fdb2a7389025aaae7cb1a18a1017d76012130e8")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto* body = input.mutable_body(); + + *body->mutable_memo() = "wallet core"; + *body->mutable_nodeaccountid() = "0.0.7"; + body->set_transactionfee(100000000); + body->set_transactionvalidduration(120); + auto* transferMsg = body->mutable_transfer(); + transferMsg->set_from("0.0.48694347"); + transferMsg->set_to("0.0.48462050"); + transferMsg->set_amount(100000000); + + auto* transactionID = body->mutable_transactionid(); + transactionID->mutable_transactionvalidstart()->set_seconds(1667227300); + transactionID->mutable_transactionvalidstart()->set_nanos(854561449); + transactionID->set_accountid("0.0.48694347"); + + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.encoded()), "0a510a150a0c08a4bdff9a0610a9a5be9703120518cb889c17120218071880c2d72f22020878320b77616c6c657420636f7265721e0a1c0a0c0a0518e2f18d17108084af5f0a0c0a0518cb889c1710ff83af5f12660a640a205d3a70d08b2beafb72c7a68986b3ff819a306078b8c359d739e4966e82e6d40e1a40ee1764c9acf79b68a675c1a78c8c43cb7d136f5f230b48b44992ad3e7ba87a8256758b823120a76142e58b94f082a0551000cf68cd3336fc4393c6b2191d8603"); +} + +TEST(HederaSigner, SignWithMemoMainnet) { + // Successfully broadcasted: https://hashscan.io/mainnet/transaction/0.0.1377988-1667566445-926176449?t=1667566457.533804616 + Proto::SigningInput input; + auto privateKey = PrivateKey(parse_hex("650c5120cbdc6244e3d10001eb27eea4dd3f80c331b3b6969fa434797d4edd50")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto* body = input.mutable_body(); + + *body->mutable_memo() = "wallet core"; + *body->mutable_nodeaccountid() = "0.0.12"; + body->set_transactionfee(100000000); + body->set_transactionvalidduration(120); + auto* transferMsg = body->mutable_transfer(); + transferMsg->set_from("0.0.1377988"); + transferMsg->set_to("0.0.19783"); + transferMsg->set_amount(100000000); + + auto* transactionID = body->mutable_transactionid(); + transactionID->mutable_transactionvalidstart()->set_seconds(1667566445); + transactionID->mutable_transactionvalidstart()->set_nanos(926176449); + transactionID->set_accountid("0.0.1377988"); + + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.encoded()), "0a4e0a140a0c08ed96949b0610c1a9d1b903120418c48d541202180c1880c2d72f22020878320b77616c6c657420636f7265721c0a1a0a0b0a0418c79a01108084af5f0a0b0a0418c48d5410ff83af5f12660a640a207df3e1ab790b28de4706d36a7aa99a0e043cb3e2c3d6ec6686e4af7f638b08601a4020a527f81c10a256b089fb2fbe2a1fc5917e0d221c0d06b8bb9095a6b26390634610f2034b99025ad70db4d84e08751841c2a70651220e32d1213a4b05ec9906"); +} + +TEST(HederaSigner, ProtoTestsTransferList) { + auto transferList = proto::TransferList(); + auto* to = transferList.add_accountamounts(); + to->set_amount(100000000); + auto accountIdTo = to->mutable_accountid(); + accountIdTo->set_shardnum(0); + accountIdTo->set_realmnum(0); + accountIdTo->set_accountnum(48462050); + + auto encoded = hex(transferList.SerializeAsString()); + ASSERT_EQ(encoded, "0a0c0a0518e2f18d17108084af5f"); +} + +TEST(HederaSigner, ProtoTestsDoubleTransferList) { + auto transferList = proto::TransferList(); + + { + auto* to = transferList.add_accountamounts(); + to->set_amount(100000000); + auto* accountIdTo = to->mutable_accountid(); + accountIdTo->set_shardnum(0); + accountIdTo->set_realmnum(0); + accountIdTo->set_accountnum(48462050); + } + + { + auto* from = transferList.add_accountamounts(); + from->set_amount(-100000000); + auto* accountIdFrom = from->mutable_accountid(); + accountIdFrom->set_shardnum(0); + accountIdFrom->set_realmnum(0); + accountIdFrom->set_accountnum(48694347); + } + + auto encoded = hex(transferList.SerializeAsString()); + ASSERT_EQ(encoded, "0a0c0a0518e2f18d17108084af5f0a0c0a0518cb889c1710ff83af5f"); +} + +TEST(HederaSigner, ProtoTestsCryptoTransfer) { + auto transferList = proto::TransferList(); + + { + auto* to = transferList.add_accountamounts(); + to->set_amount(100000000); + auto* accountIdTo = to->mutable_accountid(); + accountIdTo->set_shardnum(0); + accountIdTo->set_realmnum(0); + accountIdTo->set_accountnum(48462050); + } + + { + auto* from = transferList.add_accountamounts(); + from->set_amount(-100000000); + auto* accountIdFrom = from->mutable_accountid(); + accountIdFrom->set_shardnum(0); + accountIdFrom->set_realmnum(0); + accountIdFrom->set_accountnum(48694347); + } + + auto cryptoTransfer = proto::CryptoTransferTransactionBody(); + *cryptoTransfer.mutable_transfers() = transferList; + + auto encoded = hex(cryptoTransfer.SerializeAsString()); + ASSERT_EQ(encoded, "0a1c0a0c0a0518e2f18d17108084af5f0a0c0a0518cb889c1710ff83af5f"); +} + +TEST(HederaSigner, ProtoTestsTransactionBody) { + auto transferList = proto::TransferList(); + + { + auto* to = transferList.add_accountamounts(); + to->set_amount(100000000); + auto* accountIdTo = to->mutable_accountid(); + accountIdTo->set_shardnum(0); + accountIdTo->set_realmnum(0); + accountIdTo->set_accountnum(48462050); + } + + { + auto* from = transferList.add_accountamounts(); + from->set_amount(-100000000); + auto* accountIdFrom = from->mutable_accountid(); + accountIdFrom->set_shardnum(0); + accountIdFrom->set_realmnum(0); + accountIdFrom->set_accountnum(48694347); + } + + auto cryptoTransfer = proto::CryptoTransferTransactionBody(); + *cryptoTransfer.mutable_transfers() = transferList; + + auto transactionBody = proto::TransactionBody(); + *transactionBody.mutable_cryptotransfer() = cryptoTransfer; + transactionBody.set_transactionfee(100000000); + transactionBody.mutable_nodeaccountid()->set_accountnum(9); + transactionBody.mutable_transactionvalidduration()->set_seconds(120); + auto& transactionID = *transactionBody.mutable_transactionid(); + transactionID.mutable_accountid()->set_accountnum(48694347); + transactionID.mutable_transactionvalidstart()->set_nanos(749068449); + transactionID.mutable_transactionvalidstart()->set_seconds(1667222879); + + auto encoded = hex(transactionBody.SerializeAsString()); + + ASSERT_EQ(encoded, "0a150a0c08df9aff9a0610a1c197e502120518cb889c17120218091880c2d72f22020878721e0a1c0a0c0a0518e2f18d17108084af5f0a0c0a0518cb889c1710ff83af5f"); +} + +TEST(HederaSigner, ProtoTestsTransactionBodyWithMemo) { + auto transferList = proto::TransferList(); + { + auto* to = transferList.add_accountamounts(); + to->set_amount(100000000); + auto* accountIdTo = to->mutable_accountid(); + accountIdTo->set_shardnum(0); + accountIdTo->set_realmnum(0); + accountIdTo->set_accountnum(48462050); + } + + { + auto* from = transferList.add_accountamounts(); + from->set_amount(-100000000); + auto* accountIdFrom = from->mutable_accountid(); + accountIdFrom->set_shardnum(0); + accountIdFrom->set_realmnum(0); + accountIdFrom->set_accountnum(48694347); + } + + auto cryptoTransfer = proto::CryptoTransferTransactionBody(); + *cryptoTransfer.mutable_transfers() = transferList; + + auto transactionBody = proto::TransactionBody(); + transactionBody.set_memo("wallet core"); + *transactionBody.mutable_cryptotransfer() = cryptoTransfer; + transactionBody.set_transactionfee(100000000); + transactionBody.mutable_nodeaccountid()->set_accountnum(3); + transactionBody.mutable_transactionvalidduration()->set_seconds(120); + auto& transactionID = *transactionBody.mutable_transactionid(); + transactionID.mutable_accountid()->set_accountnum(48694347); + transactionID.mutable_transactionvalidstart()->set_nanos(942876449); + transactionID.mutable_transactionvalidstart()->set_seconds(1667215034); + + auto encoded = hex(transactionBody.SerializeAsString()); + ASSERT_EQ(encoded, "0a150a0c08baddfe9a0610a1ceccc103120518cb889c17120218031880c2d72f22020878320b77616c6c657420636f7265721e0a1c0a0c0a0518e2f18d17108084af5f0a0c0a0518cb889c1710ff83af5f"); +} + +} // namespace TW::Hedera::tests diff --git a/tests/chains/Hedera/TWAnySignerTests.cpp b/tests/chains/Hedera/TWAnySignerTests.cpp new file mode 100644 index 00000000000..a4958691315 --- /dev/null +++ b/tests/chains/Hedera/TWAnySignerTests.cpp @@ -0,0 +1,42 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include "Hedera/Signer.h" +#include "HexCoding.h" + +#include "TestUtilities.h" +#include + +namespace TW::Hedera::tests { + +TEST(TWAnySignerHedera, Sign) { + // Successfully broadcasted: https://hashscan.io/testnet/transaction/0.0.48694347-1667222879-749068449?t=1667222891.440398729&p=1 + Proto::SigningInput input; + auto privateKey = PrivateKey(parse_hex("e87a5584c0173263e138db689fdb2a7389025aaae7cb1a18a1017d76012130e8")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto* body = input.mutable_body(); + + *body->mutable_memo() = ""; + *body->mutable_nodeaccountid() = "0.0.9"; + body->set_transactionfee(100000000); + body->set_transactionvalidduration(120); + auto* transferMsg = body->mutable_transfer(); + transferMsg->set_from("0.0.48694347"); + transferMsg->set_to("0.0.48462050"); + transferMsg->set_amount(100000000); + + auto* transactionID = body->mutable_transactionid(); + transactionID->mutable_transactionvalidstart()->set_seconds(1667222879); + transactionID->mutable_transactionvalidstart()->set_nanos(749068449); + transactionID->set_accountid("0.0.48694347"); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeHedera); + ASSERT_EQ(hex(output.encoded()), "0a440a150a0c08df9aff9a0610a1c197e502120518cb889c17120218091880c2d72f22020878721e0a1c0a0c0a0518e2f18d17108084af5f0a0c0a0518cb889c1710ff83af5f12660a640a205d3a70d08b2beafb72c7a68986b3ff819a306078b8c359d739e4966e82e6d40e1a40612589c3b15f1e3ed6084b5a3a5b1b81751578cac8d6c922f31731b3982a5bac80a22558b2197276f5bae49b62503a4d39448ceddbc5ef3ba9bee4c0f302f70c"); +} + +} diff --git a/tests/chains/Hedera/TWCoinTypeTests.cpp b/tests/chains/Hedera/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..ccaf1145074 --- /dev/null +++ b/tests/chains/Hedera/TWCoinTypeTests.cpp @@ -0,0 +1,33 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "TestUtilities.h" +#include +#include + + +TEST(TWHederaCoinType, TWCoinType) { + const auto coin = TWCoinTypeHedera; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("0.0.19790-1666769504-858851231")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0.0.19790")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "hedera"); + assertStringsEqual(name, "Hedera"); + assertStringsEqual(symbol, "HBAR"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 8); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainHedera); + assertStringsEqual(txUrl, "https://hashscan.io/mainnet/transaction/0.0.19790-1666769504-858851231"); + assertStringsEqual(accUrl, "https://hashscan.io/mainnet/account/0.0.19790"); +} diff --git a/tests/common/CoinAddressDerivationTests.cpp b/tests/common/CoinAddressDerivationTests.cpp index 5bd9acd5d63..eacfaa549e9 100644 --- a/tests/common/CoinAddressDerivationTests.cpp +++ b/tests/common/CoinAddressDerivationTests.cpp @@ -252,6 +252,9 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeAptos: EXPECT_EQ(address, "0xce2fd04ac9efa74f17595e5785e847a2399d7e637f5e8179244f76191f653276"); break; + case TWCoinTypeHedera: + EXPECT_EQ(address, "0.0.302a300506032b6570032100ee93a4f66f8d16b819bb9beb9ffccdfcdc1412e87fee6a324c2a99a1e0e67148"); + break; // no default branch here, intentionally, to better notice any missing coins } } diff --git a/tests/common/HDWallet/HDWalletTests.cpp b/tests/common/HDWallet/HDWalletTests.cpp index 9bc90832bed..7430101c7da 100644 --- a/tests/common/HDWallet/HDWalletTests.cpp +++ b/tests/common/HDWallet/HDWalletTests.cpp @@ -10,6 +10,7 @@ #include "Bitcoin/CashAddress.h" #include "Bitcoin/SegwitAddress.h" #include "Ethereum/Address.h" +#include "Hedera/DER.h" #include "HexCoding.h" #include "PublicKey.h" #include "Hash.h" @@ -433,5 +434,27 @@ TEST(HDWallet, AptosKey) { } } +TEST(HDWallet, HederaKey) { + // https://github.com/hashgraph/hedera-sdk-js/blob/e0cd39c84ab189d59a6bcedcf16e4102d7bb8beb/packages/cryptography/test/unit/Mnemonic.js#L47 + { + const auto derivPath = "m/44'/3030'/0'/0'/0"; + HDWallet wallet = HDWallet("inmate flip alley wear offer often piece magnet surge toddler submit right radio absent pear floor belt raven price stove replace reduce plate home", ""); + { + const auto privateKey = wallet.getKey(TWCoinTypeHedera, DerivationPath(derivPath)); + EXPECT_EQ(Hedera::gHederaDerPrefixPrivate + hex(privateKey.bytes), "302e020100300506032b657004220420853f15aecd22706b105da1d709b4ac05b4906170c2b9c7495dff9af49e1391da"); + EXPECT_EQ(Hedera::gHederaDerPrefixPublic + hex(privateKey.getPublicKey(TWPublicKeyTypeED25519).bytes), "302a300506032b6570032100b63b3815f453cf697b53b290b1d78e88c725d39bde52c34c79fb5b4c93894673"); + } + } + { + const auto derivPath = "m/44'/3030'/0'/0'/0"; + HDWallet wallet = HDWallet("walk gun glide frequent exhaust sugar siege prosper staff skill swarm label", ""); + { + const auto privateKey = wallet.getKey(TWCoinTypeHedera, DerivationPath(derivPath)); + EXPECT_EQ(Hedera::gHederaDerPrefixPrivate + hex(privateKey.bytes), "302e020100300506032b657004220420650c5120cbdc6244e3d10001eb27eea4dd3f80c331b3b6969fa434797d4edd50"); + EXPECT_EQ(Hedera::gHederaDerPrefixPublic + hex(privateKey.getPublicKey(TWPublicKeyTypeED25519).bytes), "302a300506032b65700321007df3e1ab790b28de4706d36a7aa99a0e043cb3e2c3d6ec6686e4af7f638b0860"); + } + } +} + } // namespace diff --git a/tests/common/algorithm/string.cpp b/tests/common/algorithm/string.cpp new file mode 100644 index 00000000000..081e5e99939 --- /dev/null +++ b/tests/common/algorithm/string.cpp @@ -0,0 +1,19 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "algorithm/string.hpp" + +#include "gtest/gtest.h" + +namespace TW::tests { + TEST(Algorithm, StringSplit) { + auto splitted = TW::ssplit("0.0.1", '.'); + ASSERT_EQ(splitted.size(), 3uL); + ASSERT_EQ(splitted[0], "0"); + ASSERT_EQ(splitted[1], "0"); + ASSERT_EQ(splitted[2], "1"); + } +} diff --git a/tools/generate-files b/tools/generate-files index aa694add2cc..e6d74be818e 100755 --- a/tools/generate-files +++ b/tools/generate-files @@ -63,6 +63,7 @@ fi "$PROTOC" -I=$PREFIX/include -I=src/Tron/Protobuf --cpp_out=src/Tron/Protobuf src/Tron/Protobuf/*.proto "$PROTOC" -I=$PREFIX/include -I=src/Zilliqa/Protobuf --cpp_out=src/Zilliqa/Protobuf src/Zilliqa/Protobuf/*.proto "$PROTOC" -I=$PREFIX/include -I=src/Cosmos/Protobuf --cpp_out=src/Cosmos/Protobuf src/Cosmos/Protobuf/*.proto +"$PROTOC" -I=$PREFIX/include -I=src/Hedera/Protobuf --cpp_out=src/Hedera/Protobuf src/Hedera/Protobuf/*.proto "$PROTOC" -I=$PREFIX/include -I=tests/chains/Cosmos/Protobuf --cpp_out=tests/chains/Cosmos/Protobuf tests/chains/Cosmos/Protobuf/*.proto # Generate Proto interface file diff --git a/wasm/CMakeLists.txt b/wasm/CMakeLists.txt index 379042f09e6..e7ea9f4ca0e 100644 --- a/wasm/CMakeLists.txt +++ b/wasm/CMakeLists.txt @@ -16,7 +16,7 @@ target_compile_options(${TARGET_NAME} PRIVATE "-Wall") set_target_properties(${TARGET_NAME} PROPERTIES - CXX_STANDARD 17 + CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON ) @@ -39,6 +39,6 @@ set_target_properties(${TARGET_NAME} set_target_properties(${TARGET_NAME} PROPERTIES - COMPILE_FLAGS "-O2 -sSTRICT -sUSE_BOOST_HEADERS=1" + COMPILE_FLAGS "-O2 -sSTRICT -sUSE_BOOST_HEADERS=1" LINK_FLAGS "--bind --no-entry --closure 1 -O2 -sSTRICT -sASSERTIONS -sMODULARIZE=1 -sALLOW_MEMORY_GROWTH=1 -sDYNAMIC_EXECUTION=0" ) diff --git a/wasm/tests/Blockchain/Hedera.test.ts b/wasm/tests/Blockchain/Hedera.test.ts new file mode 100644 index 00000000000..6c26bfadd6c --- /dev/null +++ b/wasm/tests/Blockchain/Hedera.test.ts @@ -0,0 +1,62 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import "mocha"; +import { assert } from "chai"; +import { Buffer } from "buffer"; +import { TW } from "../../dist"; +import Long = require("long"); + +describe("Hedera", () => { + + it("test address", () => { + const { PrivateKey, HexCoding, AnyAddress, CoinType, Curve } = globalThis.core; + const address = AnyAddress.createWithString("0.0.48694347", CoinType.hedera); + assert.equal(address.description(), "0.0.48694347"); + assert.equal(AnyAddress.isValid("0.0.48694347", CoinType.hedera), true); + assert.equal(AnyAddress.isValid("0.0.a", CoinType.hedera), false); + address.delete(); + }); + + it("test sign simple transfer Hedera", () => { + const { PrivateKey, HexCoding, AnySigner, AnyAddress, CoinType } = globalThis.core; + const transferMsg = TW.Hedera.Proto.TransferMessage.create({ + from: "0.0.48694347", + to: "0.0.48462050", + amount: new Long(100000000) + }) + + const transactionID = TW.Hedera.Proto.TransactionID.create({ + accountID: "0.0.48694347", + transactionValidStart: TW.Hedera.Proto.Timestamp.create({ + seconds: new Long(1667222879), + nanos: 749068449 + }) + }) + + const transactionBody = TW.Hedera.Proto.TransactionBody.create({ + memo: "", + nodeAccountID: "0.0.9", + transactionFee: new Long(100000000), + transactionValidDuration: new Long(120), + transfer: transferMsg, + transactionID: transactionID + }) + + const txDataInput = TW.Hedera.Proto.SigningInput.create({ + privateKey: PrivateKey.createWithData( + HexCoding.decode( + "0xe87a5584c0173263e138db689fdb2a7389025aaae7cb1a18a1017d76012130e8", + ), + ).data(), + body: transactionBody + }); + const input = TW.Hedera.Proto.SigningInput.encode(txDataInput).finish(); + const outputData = AnySigner.sign(input, CoinType.hedera); + const output = TW.Hedera.Proto.SigningOutput.decode(outputData); + assert.equal(HexCoding.encode(output.encoded), "0x0a440a150a0c08df9aff9a0610a1c197e502120518cb889c17120218091880c2d72f22020878721e0a1c0a0c0a0518e2f18d17108084af5f0a0c0a0518cb889c1710ff83af5f12660a640a205d3a70d08b2beafb72c7a68986b3ff819a306078b8c359d739e4966e82e6d40e1a40612589c3b15f1e3ed6084b5a3a5b1b81751578cac8d6c922f31731b3982a5bac80a22558b2197276f5bae49b62503a4d39448ceddbc5ef3ba9bee4c0f302f70c") + }); +}); From b69c9b276150fcc25a4c43e5ada61564a9d759b8 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Wed, 9 Nov 2022 17:40:35 +0900 Subject: [PATCH 133/497] update oeth name (#2711) --- registry.json | 2 +- tests/chains/Optimism/TWCoinTypeTests.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/registry.json b/registry.json index fe76a261485..d2dcc9d2b74 100644 --- a/registry.json +++ b/registry.json @@ -2042,7 +2042,7 @@ { "id": "optimism", "name": "Optimism", - "displayName": "Optimistic Ethereum", + "displayName": "Optimism Ethereum", "coinId": 10000070, "slip44": 60, "symbol": "ETH", diff --git a/tests/chains/Optimism/TWCoinTypeTests.cpp b/tests/chains/Optimism/TWCoinTypeTests.cpp index 1cc6ff0e4c3..c95173bfe5f 100644 --- a/tests/chains/Optimism/TWCoinTypeTests.cpp +++ b/tests/chains/Optimism/TWCoinTypeTests.cpp @@ -9,7 +9,6 @@ #include #include - TEST(TWOptimismCoinType, TWCoinType) { auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeOptimism)); auto txId = WRAPS(TWStringCreateWithUTF8Bytes("0x6fd99288be9bf71eb002bb31da10a4fb0fbbb3c45ae73693b212f49c9db7df8f")); @@ -26,5 +25,5 @@ TEST(TWOptimismCoinType, TWCoinType) { assertStringsEqual(txUrl, "https://optimistic.etherscan.io/tx/0x6fd99288be9bf71eb002bb31da10a4fb0fbbb3c45ae73693b212f49c9db7df8f"); assertStringsEqual(accUrl, "https://optimistic.etherscan.io/address/0x1f932361e31d206b4f6b2478123a9d0f8c761031"); assertStringsEqual(id, "optimism"); - assertStringsEqual(name, "Optimistic Ethereum"); + assertStringsEqual(name, "Optimism Ethereum"); } From 1009d570554d48c7ed530cca9394ec2b7fcf903d Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 10 Nov 2022 03:05:09 +0100 Subject: [PATCH 134/497] [License]: 3rd party licensing (#2709) * feat(license): add 3rd party license file * Update LICENSE-3RD-PARTY.txt Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- LICENSE-3RD-PARTY.txt | 850 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 850 insertions(+) create mode 100644 LICENSE-3RD-PARTY.txt diff --git a/LICENSE-3RD-PARTY.txt b/LICENSE-3RD-PARTY.txt new file mode 100644 index 00000000000..93b7fb0a22a --- /dev/null +++ b/LICENSE-3RD-PARTY.txt @@ -0,0 +1,850 @@ +3RD PARTY LICENSES + +Note that not all files in the wallet-core repository and in the released +software packages belong to the wallet-core project. For 3rd party files, +the individual licenses apply. + + +############################################################################# +LICENSE TEXTS +############################################################################# + +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +############################################################################# + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + +############################################################################# + +Copyright 2008 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + +############################################################################# + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + + +## Runtime Library Exception to the Apache 2.0 License: ## + + + As an exception, if you use this Software to compile your source code and + portions of this Software are embedded into the binary product as a result, + you may redistribute such product without providing attribution as would + otherwise be required by Sections 4(a), 4(b) and 4(d) of the License. + +############################################################################# + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +############################################################################# + +The MIT License (MIT) + +Copyright (c) 2013 Tomas Dzetkulic +Copyright (c) 2013 Pavol Rusnak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From c61a47d2862680c954369939f4951497705acb14 Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Thu, 10 Nov 2022 13:50:14 +0000 Subject: [PATCH 135/497] [Staking]: add ETH pooled staking tests (#2707) --- .../ethereum/TestEthereumTransactionSigner.kt | 62 +++++++++++ swift/Tests/Blockchains/EthereumTests.swift | 61 +++++++++++ tests/chains/Ethereum/TWAnySignerTests.cpp | 100 ++++++++++++++++++ 3 files changed, 223 insertions(+) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumTransactionSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumTransactionSigner.kt index ab3b38bf229..61a6b9a42df 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumTransactionSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumTransactionSigner.kt @@ -9,6 +9,8 @@ import wallet.core.java.AnySigner import wallet.core.jni.CoinType import wallet.core.jni.CoinType.ETHEREUM import wallet.core.jni.proto.Ethereum +import wallet.core.jni.EthereumAbi +import wallet.core.jni.EthereumAbiFunction import wallet.core.jni.proto.Ethereum.SigningOutput import wallet.core.jni.proto.Ethereum.TransactionMode import com.trustwallet.core.app.utils.Numeric @@ -147,6 +149,66 @@ class TestEthereumTransactionSigner { assertEquals(Numeric.toHexString(output.data.toByteArray()), "0xf242432a000000000000000000000000718046867b5b1782379a14ea4fc0c9b724da94fc0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000000000000023c47ee50000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000") } + @Test + fun testEthereumStakeRocketPool() { + val function = EthereumAbiFunction("deposit") + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + chainId = ByteString.copyFrom("01".toHexByteArray()) + nonce = ByteString.copyFrom("01".toHexByteArray()) + txMode = TransactionMode.Enveloped + gasPrice = ByteString.copyFrom("77541880".toHexByteArray()) // 2002000000 + gasLimit = ByteString.copyFrom("0320c8".toHexByteArray()) // 205000 + maxFeePerGas = ByteString.copyFrom("067ef83700".toHexByteArray()) // 27900000000 + maxInclusionFeePerGas = ByteString.copyFrom("3b9aca00".toHexByteArray()) // 1000000000 + toAddress = "0x2cac916b2a963bf162f076c0a8a4a8200bcfbfb4" // contract + privateKey = ByteString.copyFrom(PrivateKey("9f56448d33de406db1561aae15fce64bdf0e9706ff15c45d4409e8fcbfd1a498".toHexByteArray()).data()) + transaction = Ethereum.Transaction.newBuilder().apply { + transfer = Ethereum.Transaction.Transfer.newBuilder().apply { + amount = ByteString.copyFrom("2386f26fc10000".toHexByteArray()) // 0.01 ETH + data = ByteString.copyFrom(EthereumAbi.encode(function)) + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + // https://etherscan.io/tx/0xfeba0c579f3e964fbc4eafa500e86891b9f4113735b1364edd4433d765506f1e + assertEquals(Numeric.toHexString(output.r.toByteArray()), "0xfb39e5079d7a0598ec45785d73a06b91fe1db707b9c6a150c87ffce2492c66d6") + assertEquals(Numeric.toHexString(output.s.toByteArray()), "0x7fbd43a6f4733b2b4f98ad1bc4678ea2615f5edf56ad91408337adec2f07c0ac") + } + + @Test + fun testEthereumUnstakeRocketPool() { + val function = EthereumAbiFunction("burn") + function.addParamUInt256("0x21faa32ab2502b".toHexByteArray(), false) + + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + chainId = ByteString.copyFrom("01".toHexByteArray()) + nonce = ByteString.copyFrom("03".toHexByteArray()) + txMode = TransactionMode.Enveloped + gasPrice = ByteString.copyFrom("77541880".toHexByteArray()) // 2002000000 + gasLimit = ByteString.copyFrom("055730".toHexByteArray()) // 350000 + maxFeePerGas = ByteString.copyFrom("067ef83700".toHexByteArray()) // 27900000000 + maxInclusionFeePerGas = ByteString.copyFrom("3b9aca00".toHexByteArray()) // 1000000000 + toAddress = "0xae78736Cd615f374D3085123A210448E74Fc6393" // contract + privateKey = ByteString.copyFrom(PrivateKey("9f56448d33de406db1561aae15fce64bdf0e9706ff15c45d4409e8fcbfd1a498".toHexByteArray()).data()) + transaction = Ethereum.Transaction.newBuilder().apply { + contractGeneric = Ethereum.Transaction.ContractGeneric.newBuilder().apply { + amount = ByteString.copyFrom("00".toHexByteArray()) + data = ByteString.copyFrom(EthereumAbi.encode(function)) + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + // https://etherscan.io/tx/0x7fd3c0e9b8b309b4258baa7677c60f5e00e8db7b647fbe3a52adda25058a4b37 + assertEquals(Numeric.toHexString(output.r.toByteArray()), "0x1fc6e94908107584357799e952b4e3fb87f088aeb66d7930a7015643f19c9e7f") + assertEquals(Numeric.toHexString(output.s.toByteArray()), "0x2c56a0b70ff2e52bf374a3dcd404bc42317d5ca15d319f5e33665352eb48f06f") + } + @Test fun testSignJSON() { val json = """ diff --git a/swift/Tests/Blockchains/EthereumTests.swift b/swift/Tests/Blockchains/EthereumTests.swift index b16ba0bf7db..c3091e428b6 100644 --- a/swift/Tests/Blockchains/EthereumTests.swift +++ b/swift/Tests/Blockchains/EthereumTests.swift @@ -158,6 +158,67 @@ class EthereumTests: XCTestCase { XCTAssertEqual(output.data.hexString, "f242432a000000000000000000000000718046867b5b1782379a14ea4fc0c9b724da94fc0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000000000000023c47ee50000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000") } + func testSignStakeRocketPool() { + let function = EthereumAbiFunction(name: "deposit") + + let input = EthereumSigningInput.with { + $0.chainID = Data(hexString: "01")! + $0.nonce = Data(hexString: "01")! + $0.txMode = .enveloped + $0.gasPrice = Data(hexString: "77541880")! // 2002000000 + $0.gasLimit = Data(hexString: "0320c8")! // 205000 + $0.maxFeePerGas = Data(hexString: "067ef83700")! // 27900000000 + $0.maxInclusionFeePerGas = Data(hexString: "3b9aca00")! // 1000000000 + $0.toAddress = "0x2cac916b2a963bf162f076c0a8a4a8200bcfbfb4" // contract + $0.privateKey = Data(hexString: "9f56448d33de406db1561aae15fce64bdf0e9706ff15c45d4409e8fcbfd1a498")! + + $0.transaction = EthereumTransaction.with { + $0.transfer = EthereumTransaction.Transfer.with { + $0.amount = Data(hexString: "2386f26fc10000")! // 0.01 ETH + $0.data = Data(hexString: EthereumAbi.encode(fn: function).hexString)! + } + } + } + let output: EthereumSigningOutput = AnySigner.sign(input: input, coin: .ethereum) + + // https://etherscan.io/tx/0xfeba0c579f3e964fbc4eafa500e86891b9f4113735b1364edd4433d765506f1e + XCTAssertEqual(output.r.hexString, "fb39e5079d7a0598ec45785d73a06b91fe1db707b9c6a150c87ffce2492c66d6") + XCTAssertEqual(output.v.hexString, "00") + XCTAssertEqual(output.s.hexString, "7fbd43a6f4733b2b4f98ad1bc4678ea2615f5edf56ad91408337adec2f07c0ac") + XCTAssertEqual(output.encoded.hexString, "02f8770101843b9aca0085067ef83700830320c8942cac916b2a963bf162f076c0a8a4a8200bcfbfb4872386f26fc1000084d0e30db0c080a0fb39e5079d7a0598ec45785d73a06b91fe1db707b9c6a150c87ffce2492c66d6a07fbd43a6f4733b2b4f98ad1bc4678ea2615f5edf56ad91408337adec2f07c0ac") + } + + func testSignUnstakeRocketPool() { + let function = EthereumAbiFunction(name: "burn") + function.addParamUInt256(val: Data(hexString: "0x21faa32ab2502b")!, isOutput: false) + + let input = EthereumSigningInput.with { + $0.chainID = Data(hexString: "01")! + $0.nonce = Data(hexString: "03")! + $0.txMode = .enveloped + $0.gasPrice = Data(hexString: "77541880")! // 2002000000 + $0.gasLimit = Data(hexString: "055730")! // 350000 + $0.maxFeePerGas = Data(hexString: "067ef83700")! // 27900000000 + $0.maxInclusionFeePerGas = Data(hexString: "3b9aca00")! // 1000000000 + $0.toAddress = "0xae78736Cd615f374D3085123A210448E74Fc6393" // contract + $0.privateKey = Data(hexString: "9f56448d33de406db1561aae15fce64bdf0e9706ff15c45d4409e8fcbfd1a498")! + + $0.transaction = EthereumTransaction.with { + $0.contractGeneric = EthereumTransaction.ContractGeneric.with { + $0.amount = Data(hexString: "00")! + $0.data = Data(hexString: EthereumAbi.encode(fn: function).hexString)! + } + } + } + let output: EthereumSigningOutput = AnySigner.sign(input: input, coin: .ethereum) + + // https://etherscan.io/tx/0x7fd3c0e9b8b309b4258baa7677c60f5e00e8db7b647fbe3a52adda25058a4b37 + XCTAssertEqual(output.r.hexString, "1fc6e94908107584357799e952b4e3fb87f088aeb66d7930a7015643f19c9e7f") + XCTAssertEqual(output.v.hexString, "00") + XCTAssertEqual(output.s.hexString, "2c56a0b70ff2e52bf374a3dcd404bc42317d5ca15d319f5e33665352eb48f06f") + XCTAssertEqual(output.encoded.hexString, "02f8900103843b9aca0085067ef837008305573094ae78736cd615f374d3085123a210448e74fc639380a442966c680000000000000000000000000000000000000000000000000021faa32ab2502bc080a01fc6e94908107584357799e952b4e3fb87f088aeb66d7930a7015643f19c9e7fa02c56a0b70ff2e52bf374a3dcd404bc42317d5ca15d319f5e33665352eb48f06f") + } + func testSignJSON() { let json = """ { diff --git a/tests/chains/Ethereum/TWAnySignerTests.cpp b/tests/chains/Ethereum/TWAnySignerTests.cpp index c50cef17583..bf4079e3f77 100644 --- a/tests/chains/Ethereum/TWAnySignerTests.cpp +++ b/tests/chains/Ethereum/TWAnySignerTests.cpp @@ -9,9 +9,11 @@ #include "HexCoding.h" #include "uint256.h" #include "proto/Ethereum.pb.h" +#include "Ethereum/Address.h" #include "Ethereum/ABI/Function.h" #include "Ethereum/ABI/ParamBase.h" #include "Ethereum/ABI/ParamAddress.h" +#include "PrivateKey.h" #include @@ -485,4 +487,102 @@ TEST(TWAnySignerEthereum, SignERC1155Transfer_1559) { ASSERT_EQ(hex(output.encoded()), "02f901500180847735940084b2d05e00830130b9944e45e92ed38f885d39a733c14f1817217a89d42580b8e4f242432a000000000000000000000000718046867b5b1782379a14ea4fc0c9b724da94fc0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000000000000023c47ee50000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000c080a0533df41dda5540c57257b7fe89c29cefff0155c333e063220df2bf9680fcc15aa036a844fd20de5a51de96ceaaf078558e87d86426a4a5d4b215ee1fd0fa397f8a"); } +TEST(TWAnySignerEthereum, StakeRocketPool) { + auto chainId = store(uint256_t(1)); + auto nonce = store(uint256_t(1)); + auto gasPrice = store(uint256_t(2002000000)); + auto gasLimit = store(uint256_t(205000)); + auto maxFeePerGas = store(uint256_t(27900000000)); + auto maxInclusionFeePerGas = store(uint256_t(1000000000)); + auto toAddress = "0x2cac916b2a963bf162f076c0a8a4a8200bcfbfb4"; + auto key = parse_hex("9f56448d33de406db1561aae15fce64bdf0e9706ff15c45d4409e8fcbfd1a498"); + const auto pk = PrivateKey(key); + + // 0.01 ETH + auto valueData = store(uint256_t(10000000000000000)); + + Data payload; + { + auto func = ABI::Function("deposit", std::vector>{ }); + func.encode(payload); + } + + + Proto::SigningInput input; + input.set_tx_mode(Proto::TransactionMode::Enveloped); + + input.set_chain_id(chainId.data(), chainId.size()); + input.set_nonce(nonce.data(), nonce.size()); + + input.set_gas_price(gasPrice.data(), gasPrice.size()); + input.set_gas_limit(gasLimit.data(), gasLimit.size()); + input.set_max_fee_per_gas(maxFeePerGas.data(), maxFeePerGas.size()); + input.set_max_inclusion_fee_per_gas(maxInclusionFeePerGas.data(), maxInclusionFeePerGas.size()); + + input.set_to_address(toAddress); + input.set_private_key(key.data(), key.size()); + + auto& transfer = *input.mutable_transaction()->mutable_transfer(); + transfer.set_amount(valueData.data(), valueData.size()); + transfer.set_data(payload.data(), payload.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeEthereum); + + // https://etherscan.io/tx/0xfeba0c579f3e964fbc4eafa500e86891b9f4113735b1364edd4433d765506f1e + EXPECT_EQ(hex(output.r()), "fb39e5079d7a0598ec45785d73a06b91fe1db707b9c6a150c87ffce2492c66d6"); + EXPECT_EQ(hex(output.v()), "00"); + EXPECT_EQ(hex(output.s()), "7fbd43a6f4733b2b4f98ad1bc4678ea2615f5edf56ad91408337adec2f07c0ac"); + EXPECT_EQ(hex(output.encoded()), "02f8770101843b9aca0085067ef83700830320c8942cac916b2a963bf162f076c0a8a4a8200bcfbfb4872386f26fc1000084d0e30db0c080a0fb39e5079d7a0598ec45785d73a06b91fe1db707b9c6a150c87ffce2492c66d6a07fbd43a6f4733b2b4f98ad1bc4678ea2615f5edf56ad91408337adec2f07c0ac"); +} + +TEST(TWAnySignerEthereum, UnstakeRocketPool) { + auto chainId = store(uint256_t(1)); + auto nonce = store(uint256_t(3)); + auto gasPrice = store(uint256_t(2002000000)); + auto gasLimit = store(uint256_t(350000)); + auto maxFeePerGas = store(uint256_t(27900000000)); + auto maxInclusionFeePerGas = store(uint256_t(1000000000)); + auto toAddress = "0xae78736Cd615f374D3085123A210448E74Fc6393"; + auto key = parse_hex("9f56448d33de406db1561aae15fce64bdf0e9706ff15c45d4409e8fcbfd1a498"); + const auto pk = PrivateKey(key); + + auto valueData = store(uint256_t(0)); + + Data payload; + { + auto func = ABI::Function("burn", std::vector>{ + std::make_shared(uint256_t(0x21faa32ab2502b))}); + func.encode(payload); + } + + Proto::SigningInput input; + input.set_tx_mode(Proto::TransactionMode::Enveloped); + + input.set_chain_id(chainId.data(), chainId.size()); + input.set_nonce(nonce.data(), nonce.size()); + + input.set_gas_price(gasPrice.data(), gasPrice.size()); + input.set_gas_limit(gasLimit.data(), gasLimit.size()); + input.set_max_fee_per_gas(maxFeePerGas.data(), maxFeePerGas.size()); + input.set_max_inclusion_fee_per_gas(maxInclusionFeePerGas.data(), maxInclusionFeePerGas.size()); + + input.set_to_address(toAddress); + input.set_private_key(key.data(), key.size()); + + auto& transfer = *input.mutable_transaction()->mutable_contract_generic(); + transfer.set_amount(valueData.data(), valueData.size()); + transfer.set_data(payload.data(), payload.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeEthereum); + + // https://etherscan.io/tx/0x7fd3c0e9b8b309b4258baa7677c60f5e00e8db7b647fbe3a52adda25058a4b37 + EXPECT_EQ(hex(output.r()), "1fc6e94908107584357799e952b4e3fb87f088aeb66d7930a7015643f19c9e7f"); + EXPECT_EQ(hex(output.v()), "00"); + EXPECT_EQ(hex(output.s()), "2c56a0b70ff2e52bf374a3dcd404bc42317d5ca15d319f5e33665352eb48f06f"); + EXPECT_EQ(hex(output.encoded()), "02f8900103843b9aca0085067ef837008305573094ae78736cd615f374d3085123a210448e74fc639380a442966c680000000000000000000000000000000000000000000000000021faa32ab2502bc080a01fc6e94908107584357799e952b4e3fb87f088aeb66d7930a7015643f19c9e7fa02c56a0b70ff2e52bf374a3dcd404bc42317d5ca15d319f5e33665352eb48f06f"); +} + + } // namespace TW::Ethereum From c462a63014b970690279a4bfc5a8a3454d275330 Mon Sep 17 00:00:00 2001 From: Ahmad Heidari Date: Mon, 14 Nov 2022 11:37:28 +0300 Subject: [PATCH 136/497] Add Memes wallet to the list that use Wallet core (#2725) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 36b798cb3cd..2b39eab1cdc 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ Projects using Trust Wallet Core. Add yours too! | [Alice](https://www.alicedapp.com/) | [Frontier](https://frontier.xyz/) | [Tokenary](https://tokenary.io/) +| [MemesWallet](https://planetmemes.com/) # Community From efca5eeef5ab79df88914c7be2c287317cd10234 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Mon, 14 Nov 2022 14:06:44 +0100 Subject: [PATCH 137/497] Support affiliate fee fields in memo (#2715) * Support affiliate fee fields in memo * Increase max OP_RETURN len to 80 bytes * Update iOS and android tests. * BitcoinScript test fix --- .../thorchain/TestTHORSwapSigning.kt | 10 +- docs/registry.md | 2 +- src/Bitcoin/Script.cpp | 2 +- src/THORChain/Swap.cpp | 33 +++- src/THORChain/Swap.h | 8 +- src/THORChain/TWSwap.cpp | 5 +- src/proto/THORChainSwap.proto | 9 ++ .../Blockchains/THORChainSwapTests.swift | 10 +- tests/chains/Bitcoin/BitcoinScriptTests.cpp | 11 +- tests/chains/THORChain/SwapTests.cpp | 142 ++++++++++++++++-- tests/chains/THORChain/TWSwapTests.cpp | 6 +- 11 files changed, 203 insertions(+), 35 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt index 2d1d3caf77e..e65151148a7 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt @@ -20,7 +20,7 @@ class TestTHORChainSwap { } @Test - fun testSwapEthBnb() { + fun testSwapEthBnbWithFee() { // prepare swap input val input = THORChainSwap.SwapInput.newBuilder() input.apply { @@ -36,15 +36,17 @@ class TestTHORChainSwap { routerAddress = "0x42A5Ed456650a09Dc10EBc6361A7480fDd61f27B" fromAmount = "50000000000000000" toAmountLimit = "600003" + affiliateFeeAddress = "tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy" + affiliateFeeRateBp = "10" } // serialize input val inputSerialized = input.build().toByteArray() - assertEquals(Numeric.toHexString(inputSerialized), "0x0802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a1135303030303030303030303030303030304206363030303033") + assertEquals(Numeric.toHexString(inputSerialized), "0x0802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a11353030303030303030303030303030303042063630303030334a2f7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c327463717952023130") // invoke swap val outputData = buildSwap(inputSerialized) - assertEquals(outputData.count(), 311) + assertEquals(outputData.count(), 375) // parse result in proto val outputProto = THORChainSwap.SwapOutput.newBuilder().mergeFrom(outputData) @@ -66,6 +68,6 @@ class TestTHORChainSwap { // sign and encode resulting input val output = AnySigner.sign(txInputFull, ETHEREUM, SigningOutput.parser()) - assertEquals(Numeric.toHexString(output.encoded.toByteArray()), "0xf90151038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b8e41fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003e535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a363030303033000025a06ae104be3201baca38315352f81fac70ca4dd47339981914e64e91149813e780a066a3f0b2c44ddf5a96a38481274f623f552a593d723237d6742185f4885c0064") + assertEquals(Numeric.toHexString(output.encoded.toByteArray()), "0xf90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000071535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000026a027da86e94739f39e8b493f240eb043888a0dd6962a657963ff7fb26f10291ca8a03fed75d6703d5036402be4d0197432725e17fe6a5d3059abdcca74bd7a789cc8") } } diff --git a/docs/registry.md b/docs/registry.md index 3db48715d95..a1cecf40e66 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -76,7 +76,7 @@ This list is generated from [./registry.json](../registry.json) | 5718350 | Wanchain | WAN | | | | 5741564 | Waves | WAVES | | | | 10000025 | Cronos Chain | CRO | | | -| 10000070 | Optimistic Ethereum | ETH | | | +| 10000070 | Optimism Ethereum | ETH | | | | 10000100 | Gnosis Chain | xDAI | | | | 10000118 | Osmosis | OSMO | | | | 10000145 | Smart Bitcoin Cash | BCH | | | diff --git a/src/Bitcoin/Script.cpp b/src/Bitcoin/Script.cpp index 7000814c396..82c26bf8660 100644 --- a/src/Bitcoin/Script.cpp +++ b/src/Bitcoin/Script.cpp @@ -259,7 +259,7 @@ Script Script::buildPayToV1WitnessProgram(const Data& publicKey) { } Script Script::buildOpReturnScript(const Data& data) { - static const size_t MaxOpReturnLength = 64; + static const size_t MaxOpReturnLength = 80; Script script; script.bytes.push_back(OP_RETURN); size_t size = std::min(data.size(), MaxOpReturnLength); diff --git a/src/THORChain/Swap.cpp b/src/THORChain/Swap.cpp index 17d47ebf51e..b799b645023 100644 --- a/src/THORChain/Swap.cpp +++ b/src/THORChain/Swap.cpp @@ -54,13 +54,33 @@ std::string chainName(Chain chain) { } } -std::string Swap::buildMemo(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& toAddress, uint64_t limit) { +std::string Swap::buildMemo(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& toAddress, uint64_t limit, const std::string& feeAddress, std::optional feeRate, const std::string& extra) { std::string prefix = "SWAP"; if (toChain == Chain::ETH) { prefix = "="; } const auto toCoinToken = (!toTokenId.empty() && toTokenId != "0x0000000000000000000000000000000000000000") ? toTokenId : toSymbol; - return prefix + ":" + chainName(toChain) + "." + toCoinToken + ":" + toAddress + ":" + std::to_string(limit); + std::stringstream memo; + memo << prefix + ":" + chainName(toChain) + "." + toCoinToken + ":" + toAddress + ":" + std::to_string(limit); + + if (!feeAddress.empty() || feeRate.has_value() || !extra.empty()) { + memo << ":"; + if (!feeAddress.empty()) { + memo << feeAddress; + } + if (feeRate.has_value() || !extra.empty()) { + memo << ":"; + if (feeRate.has_value()) { + memo << std::to_string(feeRate.value()); + } + if (!extra.empty()) { + memo << ":"; + memo << extra; + } + } + } + + return memo.str(); } bool validateAddress(Chain chain, const std::string& address) { @@ -77,7 +97,10 @@ std::tuple Swap::build( const std::string& vaultAddress, const std::string& routerAddress, const std::string& fromAmount, - const std::string& toAmountLimit + const std::string& toAmountLimit, + const std::string& affFeeAddress, + const std::string& affFeeRate, + const std::string& extraMemo ) { if (!validateAddress(fromChain, fromAddress)) { return std::make_tuple({}, static_cast(Proto::ErrorCode::Error_Invalid_from_address), "Invalid from address"); @@ -88,7 +111,9 @@ std::tuple Swap::build( uint64_t fromAmountNum = std::atoll(fromAmount.c_str()); uint64_t toAmountLimitNum = std::atoll(toAmountLimit.c_str()); - const auto memo = buildMemo(toChain, toSymbol, toTokenId, toAddress, toAmountLimitNum); + std::optional feeRateNum = affFeeRate.empty() ? std::nullopt : std::optional(std::atoll(affFeeRate.c_str())); + + const auto memo = buildMemo(toChain, toSymbol, toTokenId, toAddress, toAmountLimitNum, affFeeAddress, feeRateNum, extraMemo); switch (fromChain) { case Chain::BTC: { diff --git a/src/THORChain/Swap.h b/src/THORChain/Swap.h index 723b4ee83f2..6f74f047c0e 100644 --- a/src/THORChain/Swap.h +++ b/src/THORChain/Swap.h @@ -10,6 +10,7 @@ #include #include +#include namespace TW::THORChainSwap { @@ -37,7 +38,10 @@ class Swap { const std::string& vaultAddress, // ThorChainSwap vault, on the source chain. Should be queried afresh, as it may change const std::string& routerAddress, // ThorChain router, only in case of Ethereum source network const std::string& fromAmount, // The source amount, as integer in the smallest native unit of the chain - const std::string& toAmountLimit // The minimum accepted destination amount. Actual destination amount will depend on current rates, limit amount can be used to prevent using very unfavorable rates. + const std::string& toAmountLimit, // The minimum accepted destination amount. Actual destination amount will depend on current rates, limit amount can be used to prevent using very unfavorable rates. + const std::string& affFeeAddress = "", // Optional affiliate fee destination address. A Rune address. + const std::string& affFeeRate = "", // Optional affiliate fee, percentage base points, e.g. 100 means 1%, 0 - 1000, as string. + const std::string& extraMemo = "" // Optional extra custom memo, reserved for later use. ); protected: @@ -46,7 +50,7 @@ class Swap { static std::pair buildBinance(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& fromAddress, const std::string& toAddress, const std::string& vaultAddress, uint64_t amount, const std::string& memo, Data& out); public: - static std::string buildMemo(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& toAddress, uint64_t limit); + static std::string buildMemo(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& toAddress, uint64_t limit, const std::string& feeAddress, std::optional feeRate, const std::string& extra); }; } // namespace TW diff --git a/src/THORChain/TWSwap.cpp b/src/THORChain/TWSwap.cpp index 9f1341c50fe..2b9c70c567a 100644 --- a/src/THORChain/TWSwap.cpp +++ b/src/THORChain/TWSwap.cpp @@ -34,7 +34,10 @@ TWData* _Nonnull TWTHORChainSwapBuildSwap(TWData* _Nonnull input) { inputProto.vault_address(), inputProto.router_address(), inputProto.from_amount(), - inputProto.to_amount_limit()); + inputProto.to_amount_limit(), + inputProto.affiliate_fee_address(), + inputProto.affiliate_fee_rate_bp(), + inputProto.extra_memo()); outputProto.set_from_chain(fromChain); outputProto.set_to_chain(toChain); diff --git a/src/proto/THORChainSwap.proto b/src/proto/THORChainSwap.proto index 7f3a20396c0..90ef10fcb19 100644 --- a/src/proto/THORChainSwap.proto +++ b/src/proto/THORChainSwap.proto @@ -75,6 +75,15 @@ message SwapInput { // The minimum accepted destination amount. Actual destination amount will depend on current rates, limit amount can be used to prevent using very unfavorable rates. string to_amount_limit = 8; + + // Optional affiliate fee destination address. A Rune address. + string affiliate_fee_address = 9; + + // Optional affiliate fee, percentage base points, e.g. 100 means 1%, 0 - 1000, as string. Empty means to ignore it. + string affiliate_fee_rate_bp = 10; + + // Optional extra custom memo, reserved for later use. + string extra_memo = 11; } // Result of the swap, a SigningInput struct for the specific chain diff --git a/swift/Tests/Blockchains/THORChainSwapTests.swift b/swift/Tests/Blockchains/THORChainSwapTests.swift index cb51dd73711..56a1d6a851d 100644 --- a/swift/Tests/Blockchains/THORChainSwapTests.swift +++ b/swift/Tests/Blockchains/THORChainSwapTests.swift @@ -9,7 +9,7 @@ import WalletCore class THORSwapTests: XCTestCase { - func testSignerEthBnb() throws { + func testSignerEthBnbWithFee() throws { // prepare swap input let input = THORChainSwapSwapInput.with { $0.fromChain = .eth @@ -24,15 +24,17 @@ class THORSwapTests: XCTestCase { $0.routerAddress = "0x42A5Ed456650a09Dc10EBc6361A7480fDd61f27B" $0.fromAmount = "50000000000000000" $0.toAmountLimit = "600003" + $0.affiliateFeeAddress = "tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy" + $0.affiliateFeeRateBp = "10" } // serialize input let inputSerialized = try input.serializedData() - XCTAssertEqual(inputSerialized.hexString, "0802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a1135303030303030303030303030303030304206363030303033") + XCTAssertEqual(inputSerialized.hexString, "0802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a11353030303030303030303030303030303042063630303030334a2f7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c327463717952023130") // invoke swap let outputData = THORChainSwap.buildSwap(input: inputSerialized) - XCTAssertEqual(outputData.count, 311) + XCTAssertEqual(outputData.count, 375) // parse result in proto let outputProto = try THORChainSwapSwapOutput(serializedData: outputData) @@ -51,7 +53,7 @@ class THORSwapTests: XCTestCase { // sign and encode resulting input let output: EthereumSigningOutput = AnySigner.sign(input: txInput, coin: .ethereum) - XCTAssertEqual(output.encoded.hexString, "f90151038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b8e41fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003e535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a363030303033000025a06ae104be3201baca38315352f81fac70ca4dd47339981914e64e91149813e780a066a3f0b2c44ddf5a96a38481274f623f552a593d723237d6742185f4885c0064") + XCTAssertEqual(output.encoded.hexString, "f90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000071535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000026a027da86e94739f39e8b493f240eb043888a0dd6962a657963ff7fb26f10291ca8a03fed75d6703d5036402be4d0197432725e17fe6a5d3059abdcca74bd7a789cc8") } func testSignerBnbBtc() throws { diff --git a/tests/chains/Bitcoin/BitcoinScriptTests.cpp b/tests/chains/Bitcoin/BitcoinScriptTests.cpp index 66c50b9701e..57d53a23310 100644 --- a/tests/chains/Bitcoin/BitcoinScriptTests.cpp +++ b/tests/chains/Bitcoin/BitcoinScriptTests.cpp @@ -313,11 +313,18 @@ TEST(BitcoinScript, OpReturn) { Script script = Script::buildOpReturnScript(data); EXPECT_EQ(hex(script.bytes), "6a3b535741503a54484f522e52554e453a74686f72317470657263616d6b6b7865633071306a6b366c74646e6c7176737732396775617038776d636c3a"); } + { + Data data = Data(69); + data.push_back(0xab); + Script script = Script::buildOpReturnScript(data); + EXPECT_EQ(hex(script.bytes), "6a46000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab"); + } { // too long, truncated - Data data = Data(70); + Data data = Data(89); + data.push_back(0xab); Script script = Script::buildOpReturnScript(data); - EXPECT_EQ(hex(script.bytes), "6a4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + EXPECT_EQ(hex(script.bytes), "6a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); } } diff --git a/tests/chains/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp index 1f0738595e4..e8fe49bd51c 100644 --- a/tests/chains/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -85,11 +85,11 @@ TEST(THORChainSwap, SwapBtcEth) { "1234000000000000000000000000000000000000000000000000000000005678" "00000000" "00" "" "ffffffff" "03" // outputs "40420f0000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" - "609deb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" - "0000000000000000" "42" "6a403d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030" + "d49ceb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" + "0000000000000000" "49" "6a473d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a313430303030303030303030303030303030" // witness "02" - "47" "304402205de19c68b5ea683b9d701d45b09f96658088db76e59ad27bd7b8383ee5d484ec0220245459a4d6d679d8b457564fccc7ecc5831c7ebed49e0366c65ac031e8a5b49201" + "48" "3045022100a67f84cbde5affbb46ffff2b33c1453ff2de70ef990fc974175d9a609e5a87ed0220589c57d958208f866c9477c7d6c9075dea4c58622debb02eab85032b8b6d373001" "21" "021e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" "00000000" // nLockTime ); @@ -139,11 +139,11 @@ TEST(THORChainSwap, SwapBtcBnb) { "eb48da786cbd9430bf5ef3d1d3bc7206a4182fd7d5ac3f4e8d05754c3a5cae8e" "00000000" "00" "" "fcffffff" "03" // outputs "400d030000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" - "108d030000000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" - "0000000000000000" "42" "6a40535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3134303030303030" + "c08c030000000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" + "0000000000000000" "43" "6a41535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a313430303030303030" // witness "02" - "48" "30450221008427ac07af830abbf9f2e1b182096d9faefc9e5b4324786ec68386579b05d02102204fd062817a59255d62aba24b1b0c66bc070d0ddbb70bf130a6159cc057e7f6c801210" + "47" "3044022071616db5a7fc9e01307ed90eb9a0a30f1441b528ba7631dc8cc8d37448369eed02202e338a0bf857c8dd096173f921fbe0d7d5f154197ab2ca7800079432f6ba486301210" "21" "e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" "00000000" // nLockTime ); @@ -365,14 +365,130 @@ TEST(THORChainSwap, SwapBnbBnbToken) { // https://explorer.binance.org/tx/60C54C9F253B89C36A2788AB66951045E8AC5F5729597CB6C64A13013A7A54CC } +TEST(THORChainSwap, SwapBtcEthWithAffFee) { + auto res = Swap::build(Chain::BTC, Chain::ETH, Address1Btc, "ETH", "", Address1Eth, VaultBtc, "", "1000000", "140000000000000000", "tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy", "10"); + ASSERT_EQ(std::get<1>(res), 0); + ASSERT_EQ(std::get<2>(res), ""); + EXPECT_EQ(hex(std::get<0>(res)), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a7a3d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a3130"); + + auto tx = Bitcoin::Proto::SigningInput(); + ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + + // check fields + EXPECT_EQ(tx.amount(), 1000000); + EXPECT_EQ(tx.to_address(), VaultBtc); + EXPECT_EQ(tx.change_address(), Address1Btc); + EXPECT_EQ(tx.output_op_return(), "=:ETH.ETH:0xb9f5771c27664bf2282d98e09d7f50cec7cb01a7:140000000000000000:tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy:10"); + EXPECT_EQ(tx.coin_type(), 0ul); + EXPECT_EQ(tx.private_key_size(), 0); + EXPECT_FALSE(tx.has_plan()); + + // set few fields before signing + tx.set_byte_fee(20); + EXPECT_EQ(Bitcoin::SegwitAddress(PrivateKey(TestKey1Btc).getPublicKey(TWPublicKeyTypeSECP256k1), "bc").string(), Address1Btc); + tx.add_private_key(TestKey1Btc.data(), TestKey1Btc.size()); + auto& utxo = *tx.add_utxo(); + Data utxoHash = parse_hex("1234000000000000000000000000000000000000000000000000000000005678"); + utxo.mutable_out_point()->set_hash(utxoHash.data(), utxoHash.size()); + utxo.mutable_out_point()->set_index(0); + utxo.mutable_out_point()->set_sequence(UINT32_MAX); + auto utxoScript = Bitcoin::Script::lockScriptForAddress(Address1Btc, TWCoinTypeBitcoin); + utxo.set_script(utxoScript.bytes.data(), utxoScript.bytes.size()); + utxo.set_amount(50000000); + tx.set_use_max_amount(false); + + // sign and encode resulting input + Bitcoin::Proto::SigningOutput output; + ANY_SIGN(tx, TWCoinTypeBitcoin); + EXPECT_EQ(output.error(), 0); + EXPECT_EQ(hex(output.encoded()), // printed using prettyPrintTransaction + "01000000" // version + "0001" // marker & flag + "01" // inputs + "1234000000000000000000000000000000000000000000000000000000005678" "00000000" "00" "" "ffffffff" + "03" // outputs + "40420f0000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" + "209ceb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" + "0000000000000000" "52" "6a503d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7474686f7231716c" + // witness + "02" + "48" "3045022100d655ed4d84a5308f206039ff6125e456134e606fe620a81bc86c142a024226eb02207e53622e7572b7099b73af60ffdcc1e1e983f7ccca07dc3e3d496efb2270ada701" + "21" "021e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" + "00000000" // nLockTime + ); +} + +TEST(THORChainSwap, SwapEthBnbWithAffFee) { + auto res = Swap::build(Chain::ETH, Chain::BNB, Address1Eth, "BNB", "", Address1Bnb, VaultEth, RouterEth, "50000000000000000", "600003", "tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy", "10"); + ASSERT_EQ(std::get<1>(res), 0); + ASSERT_EQ(std::get<2>(res), ""); + EXPECT_EQ(hex(std::get<0>(res)), "0a01001201002201002a0100422a30783432413545643435363635306130394463313045426336333631413734383066446436316632374252b30232b0020a07b1a2bc2ec5000012a4021fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000071535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a3130000000000000000000000000000000"); + + auto tx = Ethereum::Proto::SigningInput(); + ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + + // check fields + EXPECT_EQ(tx.to_address(), RouterEth); + ASSERT_TRUE(tx.transaction().has_contract_generic()); + + Data vaultAddressBin = SwapTest_ethAddressStringToData(VaultEth); + EXPECT_EQ(hex(vaultAddressBin), "1091c4de6a3cf09cda00abdaed42c7c3b69c83ec"); + auto func = Ethereum::ABI::Function("deposit", std::vector>{ + std::make_shared(vaultAddressBin), + std::make_shared(parse_hex("0000000000000000000000000000000000000000")), + std::make_shared(uint256_t(50000000000000000)), + std::make_shared("SWAP:BNB.BNB:bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx:600003:tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy:10") + }); + Data payload; + func.encode(payload); + EXPECT_EQ(hex(payload), "1fece7b4" + "0000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec" + "0000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000b1a2bc2ec50000" + "0000000000000000000000000000000000000000000000000000000000000080" + "0000000000000000000000000000000000000000000000000000000000000071" + "535741503a424e422e424e423a626e6231757334377764686678303863683937" + "7a6475656833783375356d757266727833306a656372783a3630303030333a74" + "74686f7231716c3274637179727173676e716c32746371796a326e386b66646d" + "74396c6830797a716c32746371793a3130000000000000000000000000000000"); + + EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().amount())), "b1a2bc2ec50000"); + EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().data())), hex(payload)); + + EXPECT_EQ(hex(TW::data(tx.private_key())), ""); + + // set few fields before signing + auto chainId = store(uint256_t(1)); + tx.set_chain_id(chainId.data(), chainId.size()); + auto nonce = store(uint256_t(3)); + tx.set_nonce(nonce.data(), nonce.size()); + auto gasPrice = store(uint256_t(30000000000)); + tx.set_gas_price(gasPrice.data(), gasPrice.size()); + auto gasLimit = store(uint256_t(80000)); + tx.set_gas_limit(gasLimit.data(), gasLimit.size()); + tx.set_private_key(""); + tx.set_private_key(TestKey1Eth.data(), TestKey1Eth.size()); + + // sign and encode resulting input + Ethereum::Proto::SigningOutput output; + ANY_SIGN(tx, TWCoinTypeEthereum); + EXPECT_EQ(hex(output.encoded()), "f90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000071535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000026a027da86e94739f39e8b493f240eb043888a0dd6962a657963ff7fb26f10291ca8a03fed75d6703d5036402be4d0197432725e17fe6a5d3059abdcca74bd7a789cc8"); +} + TEST(THORChainSwap, Memo) { - EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234), "SWAP:BTC.BTC:btc123:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::BNB, "BNB", "", "bnb123", 1234), "SWAP:BNB.BNB:bnb123:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::ETH, "ETH", "", "0xaabbccdd", 1234), "=:ETH.ETH:0xaabbccdd:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::ETH, "ETH", "", "0xaabbccdd", 1234), "=:ETH.ETH:0xaabbccdd:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::ETH, "ETH", "0x0000000000000000000000000000000000000000", "0xaabbccdd", 1234), "=:ETH.ETH:0xaabbccdd:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::ETH, "ETH", "0x4B0F1812e5Df2A09796481Ff14017e6005508003", "0xaabbccdd", 1234), "=:ETH.0x4B0F1812e5Df2A09796481Ff14017e6005508003:0xaabbccdd:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::BNB, "BNB", "TWT-8C2", "bnb123", 1234), "SWAP:BNB.TWT-8C2:bnb123:1234"); + EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "", std::nullopt, ""), "SWAP:BTC.BTC:btc123:1234"); + EXPECT_EQ(Swap::buildMemo(Chain::BNB, "BNB", "", "bnb123", 1234, "", std::nullopt, ""), "SWAP:BNB.BNB:bnb123:1234"); + EXPECT_EQ(Swap::buildMemo(Chain::ETH, "ETH", "", "0xaabbccdd", 1234, "", std::nullopt, ""), "=:ETH.ETH:0xaabbccdd:1234"); + EXPECT_EQ(Swap::buildMemo(Chain::ETH, "ETH", "", "0xaabbccdd", 1234, "", std::nullopt, ""), "=:ETH.ETH:0xaabbccdd:1234"); + EXPECT_EQ(Swap::buildMemo(Chain::ETH, "ETH", "0x0000000000000000000000000000000000000000", "0xaabbccdd", 1234, "", std::nullopt, ""), "=:ETH.ETH:0xaabbccdd:1234"); + EXPECT_EQ(Swap::buildMemo(Chain::ETH, "ETH", "0x4B0F1812e5Df2A09796481Ff14017e6005508003", "0xaabbccdd", 1234, "", std::nullopt, ""), "=:ETH.0x4B0F1812e5Df2A09796481Ff14017e6005508003:0xaabbccdd:1234"); + EXPECT_EQ(Swap::buildMemo(Chain::BNB, "BNB", "TWT-8C2", "bnb123", 1234, "", std::nullopt, ""), "SWAP:BNB.TWT-8C2:bnb123:1234"); + EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "feeaddr", std::nullopt, ""), "SWAP:BTC.BTC:btc123:1234:feeaddr"); + EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "feeaddr", 10, ""), "SWAP:BTC.BTC:btc123:1234:feeaddr:10"); + EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "feeaddr", 10, "extramemo"), "SWAP:BTC.BTC:btc123:1234:feeaddr:10:extramemo"); + EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "feeaddr", 0, ""), "SWAP:BTC.BTC:btc123:1234:feeaddr:0"); + EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "", 10, ""), "SWAP:BTC.BTC:btc123:1234::10"); + EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "", std::nullopt, "extramemo"), "SWAP:BTC.BTC:btc123:1234:::extramemo"); } TEST(THORChainSwap, WrongFromAddress) { diff --git a/tests/chains/THORChain/TWSwapTests.cpp b/tests/chains/THORChain/TWSwapTests.cpp index ea266cb6584..c82b276e299 100644 --- a/tests/chains/THORChain/TWSwapTests.cpp +++ b/tests/chains/THORChain/TWSwapTests.cpp @@ -105,11 +105,11 @@ TEST(TWTHORChainSwap, SwapBtcToEth) { "1234000000000000000000000000000000000000000000000000000000005678" "00000000" "00" "" "ffffffff" "03" // outputs "40420f0000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" - "609deb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" - "0000000000000000" "42" "6a403d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030" + "d49ceb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" + "0000000000000000" "49" "6a473d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a313430303030303030303030303030303030" // witness "02" - "47" "304402205de19c68b5ea683b9d701d45b09f96658088db76e59ad27bd7b8383ee5d484ec0220245459a4d6d679d8b457564fccc7ecc5831c7ebed49e0366c65ac031e8a5b49201" + "48" "3045022100a67f84cbde5affbb46ffff2b33c1453ff2de70ef990fc974175d9a609e5a87ed0220589c57d958208f866c9477c7d6c9075dea4c58622debb02eab85032b8b6d373001" "21" "021e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" "00000000" // nLockTime ); From 9378130d26ec263abb2403920750f1a55f154a10 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Fri, 18 Nov 2022 10:36:38 +0100 Subject: [PATCH 138/497] BitcoinScript/ThorSwap: Treat as error cases when memo is too long (do not truncate) (#2741) --- src/Bitcoin/Script.cpp | 10 ++-- src/Bitcoin/Script.h | 4 +- src/Bitcoin/TransactionBuilder.h | 18 +++++-- src/Bitcoin/TransactionSigner.cpp | 12 ++++- src/Zcash/TransactionBuilder.h | 11 ++-- tests/chains/Bitcoin/BitcoinScriptTests.cpp | 17 +++--- .../chains/Bitcoin/TWBitcoinSigningTests.cpp | 2 +- tests/chains/THORChain/SwapTests.cpp | 52 ++++++++++++++++--- 8 files changed, 95 insertions(+), 31 deletions(-) diff --git a/src/Bitcoin/Script.cpp b/src/Bitcoin/Script.cpp index 82c26bf8660..7c8b8da75f4 100644 --- a/src/Bitcoin/Script.cpp +++ b/src/Bitcoin/Script.cpp @@ -260,11 +260,15 @@ Script Script::buildPayToV1WitnessProgram(const Data& publicKey) { Script Script::buildOpReturnScript(const Data& data) { static const size_t MaxOpReturnLength = 80; + if (data.size() > MaxOpReturnLength) { + // data too long, cannot fit, fail (do not truncate) + return Script(); + } + assert(data.size() <= MaxOpReturnLength); Script script; script.bytes.push_back(OP_RETURN); - size_t size = std::min(data.size(), MaxOpReturnLength); - script.bytes.push_back(static_cast(size)); - script.bytes.insert(script.bytes.end(), data.begin(), data.begin() + size); + script.bytes.push_back(static_cast(data.size())); + script.bytes.insert(script.bytes.end(), data.begin(), data.begin() + data.size()); return script; } diff --git a/src/Bitcoin/Script.h b/src/Bitcoin/Script.h index 39cc5c874fc..f4c27c32517 100644 --- a/src/Bitcoin/Script.h +++ b/src/Bitcoin/Script.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -91,7 +91,7 @@ class Script { /// Builds a V1 pay-to-witness-program script, P2TR (from a 32-byte Schnorr public key). static Script buildPayToV1WitnessProgram(const Data& publicKey); - /// Builds an OP_RETURN script with given data + /// Builds an OP_RETURN script with given data. Returns empty script on error, if data is too long (>80). static Script buildOpReturnScript(const Data& data); /// Builds a appropriate lock script for the given diff --git a/src/Bitcoin/TransactionBuilder.h b/src/Bitcoin/TransactionBuilder.h index b2c9feeb8c0..caa6bef7b97 100644 --- a/src/Bitcoin/TransactionBuilder.h +++ b/src/Bitcoin/TransactionBuilder.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,6 +10,7 @@ #include "Transaction.h" #include "TransactionPlan.h" #include "InputSelector.h" +#include "../Result.h" #include "../proto/Bitcoin.pb.h" #include @@ -25,18 +26,22 @@ class TransactionBuilder { /// Builds a transaction with the selected input UTXOs, and one main output and an optional change output. template - static Transaction build(const TransactionPlan& plan, const std::string& toAddress, + static Result build(const TransactionPlan& plan, const std::string& toAddress, const std::string& changeAddress, enum TWCoinType coin, uint32_t lockTime) { Transaction tx; tx.lockTime = lockTime; auto outputTo = prepareOutputWithScript(toAddress, plan.amount, coin); - if (!outputTo.has_value()) { return {}; } + if (!outputTo.has_value()) { + return Result::failure(Common::Proto::Error_invalid_address); + } tx.outputs.push_back(outputTo.value()); if (plan.change > 0) { auto outputChange = prepareOutputWithScript(changeAddress, plan.change, coin); - if (!outputChange.has_value()) { return {}; } + if (!outputChange.has_value()) { + return Result::failure(Common::Proto::Error_invalid_address); + } tx.outputs.push_back(outputChange.value()); } @@ -48,10 +53,13 @@ class TransactionBuilder { // Optional OP_RETURN output if (plan.outputOpReturn.size() > 0) { auto lockingScriptOpReturn = Script::buildOpReturnScript(plan.outputOpReturn); + if (lockingScriptOpReturn.bytes.size() == 0) { + return Result::failure(Common::Proto::Error_invalid_memo); + } tx.outputs.emplace_back(0, lockingScriptOpReturn); } - return tx; + return Result(tx); } /// Prepares a TransactionOutput with given address and amount, prepares script for it diff --git a/src/Bitcoin/TransactionSigner.cpp b/src/Bitcoin/TransactionSigner.cpp index 0e87be108e8..c67a4b2de08 100644 --- a/src/Bitcoin/TransactionSigner.cpp +++ b/src/Bitcoin/TransactionSigner.cpp @@ -27,7 +27,11 @@ Result TransactionSigner(plan, input.toAddress, input.changeAddress, input.coinType, input.lockTime); + auto tx_result = TransactionBuilder::template build(plan, input.toAddress, input.changeAddress, input.coinType, input.lockTime); + if (!tx_result) { + return Result::failure(tx_result.error()); + } + Transaction transaction = tx_result.payload(); SigningMode signingMode = estimationMode ? SigningMode_SizeEstimationOnly : optionalExternalSigs.has_value() ? SigningMode_External : SigningMode_Normal; @@ -43,7 +47,11 @@ Result TransactionSigner(plan, input.toAddress, input.changeAddress, input.coinType, input.lockTime); + auto tx_result = TransactionBuilder::template build(plan, input.toAddress, input.changeAddress, input.coinType, input.lockTime); + if (!tx_result) { + return Result::failure(tx_result.error()); + } + Transaction transaction = tx_result.payload(); SignatureBuilder signer(std::move(input), plan, transaction, SigningMode_HashOnly); auto signResult = signer.sign(); if (!signResult) { diff --git a/src/Zcash/TransactionBuilder.h b/src/Zcash/TransactionBuilder.h index 1c5cd9fde1e..02c8db82d57 100644 --- a/src/Zcash/TransactionBuilder.h +++ b/src/Zcash/TransactionBuilder.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -11,6 +11,7 @@ #include "../Bitcoin/TransactionPlan.h" #include "../proto/Bitcoin.pb.h" #include "../HexCoding.h" +#include "../Result.h" #include #include @@ -25,18 +26,20 @@ struct TransactionBuilder { /// Builds a transaction by selecting UTXOs and calculating fees. template - static Transaction build(const Bitcoin::TransactionPlan& plan, const std::string& toAddress, + static Result build(const Bitcoin::TransactionPlan& plan, const std::string& toAddress, const std::string& changeAddress, enum TWCoinType coin, uint32_t lockTime) { coin = TWCoinTypeZcash; - Transaction tx = + auto tx_result = Bitcoin::TransactionBuilder::build(plan, toAddress, changeAddress, coin, lockTime); + if (!tx_result) { return Result::failure(tx_result.error()); } + Transaction tx = tx_result.payload(); // if not set, always use latest consensus branch id if (plan.branchId.empty()) { std::copy(BlossomBranchID.begin(), BlossomBranchID.end(), tx.branchId.begin()); } else { std::copy(plan.branchId.begin(), plan.branchId.end(), tx.branchId.begin()); } - return tx; + return Result(tx); } }; diff --git a/tests/chains/Bitcoin/BitcoinScriptTests.cpp b/tests/chains/Bitcoin/BitcoinScriptTests.cpp index 57d53a23310..0bdc3d92768 100644 --- a/tests/chains/Bitcoin/BitcoinScriptTests.cpp +++ b/tests/chains/Bitcoin/BitcoinScriptTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -319,13 +319,14 @@ TEST(BitcoinScript, OpReturn) { Script script = Script::buildOpReturnScript(data); EXPECT_EQ(hex(script.bytes), "6a46000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab"); } - { - // too long, truncated - Data data = Data(89); - data.push_back(0xab); - Script script = Script::buildOpReturnScript(data); - EXPECT_EQ(hex(script.bytes), "6a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - } +} + +TEST(BitcoinScript, OpReturnTooLong) { + // too long, truncated + Data data = Data(89); + data.push_back(0xab); + Script script = Script::buildOpReturnScript(data); + EXPECT_EQ(hex(script.bytes), ""); } TEST(BitcoinTransactionSigner, PushAllEmpty) { diff --git a/tests/chains/Bitcoin/TWBitcoinSigningTests.cpp b/tests/chains/Bitcoin/TWBitcoinSigningTests.cpp index f2c26b2691c..bdf001a94a8 100644 --- a/tests/chains/Bitcoin/TWBitcoinSigningTests.cpp +++ b/tests/chains/Bitcoin/TWBitcoinSigningTests.cpp @@ -1071,7 +1071,7 @@ TEST(BitcoinSigning, Sign_NegativeInvalidAddress) { auto result = TransactionSigner::sign(input); ASSERT_FALSE(result); - EXPECT_EQ(result.error(), Common::Proto::Error_missing_input_utxos); + EXPECT_EQ(result.error(), Common::Proto::Error_invalid_address); } TEST(BitcoinSigning, Plan_10input_MaxAmount) { diff --git a/tests/chains/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp index e8fe49bd51c..1f2e5fc5a37 100644 --- a/tests/chains/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -366,10 +366,10 @@ TEST(THORChainSwap, SwapBnbBnbToken) { } TEST(THORChainSwap, SwapBtcEthWithAffFee) { - auto res = Swap::build(Chain::BTC, Chain::ETH, Address1Btc, "ETH", "", Address1Eth, VaultBtc, "", "1000000", "140000000000000000", "tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy", "10"); + auto res = Swap::build(Chain::BTC, Chain::ETH, Address1Btc, "ETH", "", Address1Eth, VaultBtc, "", "1000000", "140000000000000000", "thrnm", "10"); ASSERT_EQ(std::get<1>(res), 0); ASSERT_EQ(std::get<2>(res), ""); - EXPECT_EQ(hex(std::get<0>(res)), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a7a3d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a3130"); + EXPECT_EQ(hex(std::get<0>(res)), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a503d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7468726e6d3a3130"); auto tx = Bitcoin::Proto::SigningInput(); ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); @@ -378,7 +378,7 @@ TEST(THORChainSwap, SwapBtcEthWithAffFee) { EXPECT_EQ(tx.amount(), 1000000); EXPECT_EQ(tx.to_address(), VaultBtc); EXPECT_EQ(tx.change_address(), Address1Btc); - EXPECT_EQ(tx.output_op_return(), "=:ETH.ETH:0xb9f5771c27664bf2282d98e09d7f50cec7cb01a7:140000000000000000:tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy:10"); + EXPECT_EQ(tx.output_op_return(), "=:ETH.ETH:0xb9f5771c27664bf2282d98e09d7f50cec7cb01a7:140000000000000000:thrnm:10"); EXPECT_EQ(tx.coin_type(), 0ul); EXPECT_EQ(tx.private_key_size(), 0); EXPECT_FALSE(tx.has_plan()); @@ -409,10 +409,10 @@ TEST(THORChainSwap, SwapBtcEthWithAffFee) { "03" // outputs "40420f0000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" "209ceb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" - "0000000000000000" "52" "6a503d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7474686f7231716c" + "0000000000000000" "52" "6a503d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7468726e6d3a3130" // witness "02" - "48" "3045022100d655ed4d84a5308f206039ff6125e456134e606fe620a81bc86c142a024226eb02207e53622e7572b7099b73af60ffdcc1e1e983f7ccca07dc3e3d496efb2270ada701" + "48" "3045022100801dc46b14eb1b630050d48db27557b66254c3b9439909d864747eafbb12f7e902201fdf5433eaf4968a5596989330bc56513b5769c5c9fd77c41f9bdb55cf8202cd01" "21" "021e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" "00000000" // nLockTime ); @@ -475,6 +475,46 @@ TEST(THORChainSwap, SwapEthBnbWithAffFee) { EXPECT_EQ(hex(output.encoded()), "f90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000071535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000026a027da86e94739f39e8b493f240eb043888a0dd6962a657963ff7fb26f10291ca8a03fed75d6703d5036402be4d0197432725e17fe6a5d3059abdcca74bd7a789cc8"); } +TEST(THORChainSwap, SwapBtcNegativeMemoTooLong) { + auto res = Swap::build(Chain::BTC, Chain::ETH, Address1Btc, "ETH", "", Address1Eth, VaultBtc, "", "1000000", "140000000000000000", "affiliate_address", "10", "extra_memo_very_loooooooooooooong"); + ASSERT_EQ(std::get<1>(res), 0); + ASSERT_EQ(std::get<2>(res), ""); + EXPECT_EQ(hex(std::get<0>(res)), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a7e3d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a616666696c696174655f616464726573733a31303a65787472615f6d656d6f5f766572795f6c6f6f6f6f6f6f6f6f6f6f6f6f6f6f6e67"); + + auto tx = Bitcoin::Proto::SigningInput(); + ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + + // check fields + EXPECT_EQ(tx.amount(), 1000000); + EXPECT_EQ(tx.to_address(), VaultBtc); + EXPECT_EQ(tx.change_address(), Address1Btc); + EXPECT_EQ(tx.output_op_return(), "=:ETH.ETH:0xb9f5771c27664bf2282d98e09d7f50cec7cb01a7:140000000000000000:affiliate_address:10:extra_memo_very_loooooooooooooong"); + EXPECT_EQ(tx.output_op_return().length(), 126ul); + EXPECT_EQ(tx.coin_type(), 0ul); + EXPECT_EQ(tx.private_key_size(), 0); + EXPECT_FALSE(tx.has_plan()); + + // set few fields before signing + tx.set_byte_fee(20); + EXPECT_EQ(Bitcoin::SegwitAddress(PrivateKey(TestKey1Btc).getPublicKey(TWPublicKeyTypeSECP256k1), "bc").string(), Address1Btc); + tx.add_private_key(TestKey1Btc.data(), TestKey1Btc.size()); + auto& utxo = *tx.add_utxo(); + Data utxoHash = parse_hex("1234000000000000000000000000000000000000000000000000000000005678"); + utxo.mutable_out_point()->set_hash(utxoHash.data(), utxoHash.size()); + utxo.mutable_out_point()->set_index(0); + utxo.mutable_out_point()->set_sequence(UINT32_MAX); + auto utxoScript = Bitcoin::Script::lockScriptForAddress(Address1Btc, TWCoinTypeBitcoin); + utxo.set_script(utxoScript.bytes.data(), utxoScript.bytes.size()); + utxo.set_amount(50000000); + tx.set_use_max_amount(false); + + // sign and encode resulting input + Bitcoin::Proto::SigningOutput output; + ANY_SIGN(tx, TWCoinTypeBitcoin); + EXPECT_EQ(output.error(), Common::Proto::Error_invalid_memo); + EXPECT_EQ(hex(output.encoded()), ""); +} + TEST(THORChainSwap, Memo) { EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "", std::nullopt, ""), "SWAP:BTC.BTC:btc123:1234"); EXPECT_EQ(Swap::buildMemo(Chain::BNB, "BNB", "", "bnb123", 1234, "", std::nullopt, ""), "SWAP:BNB.BNB:bnb123:1234"); From 984fed1b212123b760c283d5f7181516310ccf83 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 18 Nov 2022 14:53:17 +0100 Subject: [PATCH 139/497] feat(ios): update Package.swift (#2733) --- Package.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Package.swift b/Package.swift index 7f6216bde07..7448baba099 100644 --- a/Package.swift +++ b/Package.swift @@ -12,13 +12,13 @@ let package = Package( targets: [ .binaryTarget( name: "WalletCore", - url: "https://github.com/trustwallet/wallet-core/releases/download/3.0.6/WalletCore.xcframework.zip", - checksum: "a3df0c2b30fc59ede0a2600266fc19b8c0cf655dbef3fb832488c8ddedcb6b93" + url: "https://github.com/trustwallet/wallet-core/releases/download/3.1.0/WalletCore.xcframework.zip", + checksum: "2487af30a8f6f4775a41f29456f792f15269f4f4daae2da7e4b9ef8747613e3a" ), .binaryTarget( name: "SwiftProtobuf", - url: "https://github.com/trustwallet/wallet-core/releases/download/3.0.6/SwiftProtobuf.xcframework.zip", - checksum: "61fa8483d4bd43f1898db6997eff0279426f15f9e518e12db0d762ec5f927a9b" + url: "https://github.com/trustwallet/wallet-core/releases/download/3.1.0/SwiftProtobuf.xcframework.zip", + checksum: "2038b1d43c9f6aeb4957e3763382b8558983a1a811b168dca71be3636bb8350a" ) ] ) From e3398f63c2970426ef56b4bb8ba226a634ccfa14 Mon Sep 17 00:00:00 2001 From: Uri Moszkowicz Date: Fri, 18 Nov 2022 08:12:24 -0600 Subject: [PATCH 140/497] [Breaking Change] Add Ripple token and NFT support (#2696) * Add Ripple token and NFT support --- .../ripple/TestRippleTransactionSigner.kt | 19 +- src/XRP/BinaryCoding.h | 22 ++- src/XRP/Signer.cpp | 100 ++++++++-- src/XRP/Signer.h | 7 + src/XRP/Transaction.cpp | 158 +++++++++++++++- src/XRP/Transaction.h | 151 ++++++++++++--- src/proto/Ripple.proto | 97 ++++++++-- swift/Tests/Blockchains/RippleTests.swift | 34 ++-- tests/chains/XRP/TWAnySignerTests.cpp | 176 +++++++++++++++++- tests/chains/XRP/TransactionTests.cpp | 30 ++- 10 files changed, 690 insertions(+), 104 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ripple/TestRippleTransactionSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ripple/TestRippleTransactionSigner.kt index d98aab2490d..9ec91772b1b 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ripple/TestRippleTransactionSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ripple/TestRippleTransactionSigner.kt @@ -19,20 +19,25 @@ class TestRippleTransactionSigner { @Test fun testRippleTransactionSigning() { + val operation = Ripple.OperationPayment.newBuilder() + operation.apply { + amount = 10 + destination = "rU893viamSnsfP3zjzM2KPxjqZjXSXK6VF" + } val signingInput = Ripple.SigningInput.newBuilder() signingInput.apply { - account = "rDpysuumkweqeC7XdNgYNtzL5GxbdsmrtF" - amount = 29_000_000 - destination = "rU893viamSnsfP3zjzM2KPxjqZjXSXK6VF" - fee = 200_000 - sequence = 1 - privateKey = ByteString.copyFrom(PrivateKey("ba005cd605d8a02e3d5dfd04234cef3a3ee4f76bfbad2722d1fb5af8e12e6764".toHexByteArray()).data()) + account = "rfxdLwsZnoespnTDDb1Xhvbc8EFNdztaoq" + fee = 10 + sequence = 32268248 + lastLedgerSequence = 32268269 + privateKey = ByteString.copyFrom(PrivateKey("a5576c0f63da10e584568c8d134569ff44017b0a249eb70657127ae04f38cc77".toHexByteArray()).data()) + opPayment = operation.build() } val sign = AnySigner.sign(signingInput.build(), XRP, SigningOutput.parser()) val signBytes = sign.encoded.toByteArray() - assertEquals(signBytes.toHex(), "0x12000022800000002400000001614000000001ba8140684000000000030d407321026cc34b92cefb3a4537b3edb0b6044c04af27c01583c577823ecc69a9a21119b6744630440220067f20b3eebfc7107dd0bcc72337a236ac3be042c0469f2341d76694a17d4bb9022048393d7ee7dcb729783b33f5038939ddce1bb8337e66d752974626854556bbb681148400b6b6d08d5d495653d73eda6804c249a5148883148132e4e20aecf29090ac428a9c43f230a829220d") + assertEquals(signBytes.toHex(), "0x12000022000000002401ec5fd8201b01ec5fed61400000000000000a68400000000000000a732103d13e1152965a51a4a9fd9a8b4ea3dd82a4eba6b25fcad5f460a2342bb650333f74463044022037d32835c9394f39b2cfd4eaf5b0a80e0db397ace06630fa2b099ff73e425dbc02205288f780330b7a88a1980fa83c647b5908502ad7de9a44500c08f0750b0d9e8481144c55f5a78067206507580be7bb2686c8460adff983148132e4e20aecf29090ac428a9c43f230a829220d") } } diff --git a/src/XRP/BinaryCoding.h b/src/XRP/BinaryCoding.h index d606116d6c2..5f88d79d739 100644 --- a/src/XRP/BinaryCoding.h +++ b/src/XRP/BinaryCoding.h @@ -9,6 +9,7 @@ #include #include #include +#include "Data.h" namespace TW::Ripple { @@ -17,11 +18,20 @@ enum class FieldType; /// Encodes a field type. inline void encodeType(FieldType type, int key, std::vector& data) { const auto typeValue = static_cast(type); - if (key <= 0xf) { - data.push_back(static_cast((typeValue << 4) | key)); + if (typeValue <= 0xf) { + if (key <= 0xf) { + data.emplace_back(static_cast((typeValue << 4) | key)); + } else { + data.emplace_back(static_cast(typeValue << 4)); + data.emplace_back(static_cast(key)); + } + } else if (key <= 0xf) { + data.emplace_back(static_cast(key)); + data.emplace_back(static_cast(typeValue)); } else { - data.push_back(static_cast(typeValue << 4)); - data.push_back(static_cast(key)); + data.emplace_back(0); + data.emplace_back(static_cast(typeValue)); + data.emplace_back(static_cast(key)); } } @@ -47,4 +57,8 @@ inline void encodeBytes(std::vector bytes, std::vector& data) data.insert(data.end(), bytes.begin(), bytes.end()); } +inline void encodeZeros(std::size_t len, std::vector& data) { + append(data, Data(len)); +} + } // namespace TW::Ripple diff --git a/src/XRP/Signer.cpp b/src/XRP/Signer.cpp index 52237c2fdba..f72a257e9bd 100644 --- a/src/XRP/Signer.cpp +++ b/src/XRP/Signer.cpp @@ -10,39 +10,67 @@ namespace TW::Ripple { -static const int64_t fullyCanonical = 0x80000000; Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto output = Proto::SigningOutput(); - const int64_t tag = input.destination_tag(); - if (tag > std::numeric_limits::max() || tag < 0) { - output.set_error(Common::Proto::SigningError::Error_invalid_memo); - return output; + auto transaction = + Transaction( + input.fee(), + input.flags(), + input.sequence(), + input.last_ledger_sequence(), + Address(input.account())); + switch (input.operation_oneof_case()) { + case Proto::SigningInput::kOpPayment: + signPayment(input, output, transaction); + break; + + case Proto::SigningInput::kOpNftokenBurn: + transaction.createNFTokenBurn(input.op_nftoken_burn().nftoken_id()); + break; + + case Proto::SigningInput::kOpNftokenCreateOffer: + transaction.createNFTokenCreateOffer( + input.op_nftoken_create_offer().nftoken_id(), + input.op_nftoken_create_offer().destination()); + break; + + case Proto::SigningInput::kOpNftokenAcceptOffer: + transaction.createNFTokenAcceptOffer(input.op_nftoken_accept_offer().sell_offer()); + break; + + case Proto::SigningInput::kOpNftokenCancelOffer: + signNfTokenCancelOffer(input, transaction); + break; + + case Proto::SigningInput::kOpTrustSet: + transaction.createTrustSet( + input.op_trust_set().limit_amount().currency(), + input.op_trust_set().limit_amount().value(), + input.op_trust_set().limit_amount().issuer()); + break; + + default: + break; } - auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); - auto transaction = Transaction( - /* amount */ input.amount(), - /* fee */ input.fee(), - /* flags */ input.flags(), - /* sequence */ input.sequence(), - /* last_ledger_sequence */ input.last_ledger_sequence(), - /* account */ Address(input.account()), - /* destination */ input.destination(), - /* destination_tag*/ tag); + if (output.error()) { + return output; + } auto signer = Signer(); + auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); signer.sign(key, transaction); auto encoded = transaction.serialize(); output.set_encoded(encoded.data(), encoded.size()); + return output; } void Signer::sign(const PrivateKey& privateKey, Transaction& transaction) const noexcept { /// See https://github.com/trezor/trezor-core/blob/master/src/apps/ripple/sign_tx.py#L59 - transaction.flags |= fullyCanonical; transaction.pub_key = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1).bytes; auto unsignedTx = transaction.getPreImage(); @@ -52,4 +80,44 @@ void Signer::sign(const PrivateKey& privateKey, Transaction& transaction) const transaction.signature = privateKey.signAsDER(half); } +void Signer::signPayment(const Proto::SigningInput& input, + Proto::SigningOutput& output, + Transaction& transaction) noexcept { + const int64_t tag = input.op_payment().destination_tag(); + if (tag > std::numeric_limits::max() || tag < 0) { + output.set_error(Common::Proto::SigningError::Error_invalid_memo); + return; + } + + switch (input.op_payment().amount_oneof_case()) { + case Proto::OperationPayment::kAmount: + transaction.createXrpPayment( + input.op_payment().amount(), + input.op_payment().destination(), + tag); + break; + + case Proto::OperationPayment::kCurrencyAmount: + transaction.createTokenPayment( + input.op_payment().currency_amount().currency(), + input.op_payment().currency_amount().value(), + input.op_payment().currency_amount().issuer(), + input.op_payment().destination(), + tag); + break; + + default: + break; + } +} + +void Signer::signNfTokenCancelOffer(const Proto::SigningInput& input, Transaction& transaction) noexcept { + std::vector token_offers; + for (int i = 0; i < input.op_nftoken_cancel_offer().token_offers_size(); i++) { + token_offers.emplace_back(input.op_nftoken_cancel_offer().token_offers(i)); + } + + transaction.createNFTokenCancelOffer(token_offers); +} + } // namespace TW::Ripple diff --git a/src/XRP/Signer.h b/src/XRP/Signer.h index ab49851839b..2225e751ce2 100644 --- a/src/XRP/Signer.h +++ b/src/XRP/Signer.h @@ -21,6 +21,13 @@ class Signer { /// Signs the given transaction. void sign(const PrivateKey& privateKey, Transaction& transaction) const noexcept; + + private: + static void signPayment(const Proto::SigningInput& input, + Proto::SigningOutput& output, + Transaction& transaction) noexcept; + + static void signNfTokenCancelOffer(const Proto::SigningInput& input, Transaction& transaction) noexcept; }; } // namespace TW::Ripple diff --git a/src/XRP/Transaction.cpp b/src/XRP/Transaction.cpp index 00846a905c7..25b6625aaef 100644 --- a/src/XRP/Transaction.cpp +++ b/src/XRP/Transaction.cpp @@ -9,55 +9,103 @@ #include "../BinaryCoding.h" #include +#include +#include namespace TW::Ripple { const int NETWORK_PREFIX = 0x53545800; Data Transaction::serialize() const { + // See https://xrpl.org/serialization.html + auto data = Data(); + /// field must be sorted by field type then by field name /// "type" encodeType(FieldType::int16, 2, data); - encode16BE(uint16_t(TransactionType::payment), data); + encode16BE(uint16_t(transaction_type), data); + /// "flags" encodeType(FieldType::int32, 2, data); encode32BE(static_cast(flags), data); + /// "sequence" encodeType(FieldType::int32, 4, data); encode32BE(sequence, data); + /// "destinationTag" - if (encode_tag) { + if ((transaction_type == TransactionType::payment) && encode_tag) { encodeType(FieldType::int32, 14, data); encode32BE(static_cast(destination_tag), data); } + /// "lastLedgerSequence" if (last_ledger_sequence > 0) { encodeType(FieldType::int32, 27, data); encode32BE(last_ledger_sequence, data); } + + /// "NFTokenId" + if ((transaction_type == TransactionType::NFTokenCreateOffer) || + (transaction_type == TransactionType::NFTokenBurn)) { + encodeType(FieldType::hash256, 10, data); + data.insert(data.end(), nftoken_id.begin(), nftoken_id.end()); + } + + /// "NFTokenAcceptOffer" + if (transaction_type == TransactionType::NFTokenAcceptOffer) { + encodeType(FieldType::hash256, 29, data); + data.insert(data.end(), sell_offer.begin(), sell_offer.end()); + } + /// "amount" - encodeType(FieldType::amount, 1, data); - append(data, serializeAmount(amount)); + if ((transaction_type == TransactionType::payment) || + (transaction_type == TransactionType::NFTokenCreateOffer)) { + encodeType(FieldType::amount, 1, data); + append(data, + (currency_amount.currency.size() > 0) ? + serializeCurrencyAmount(currency_amount) : + serializeAmount(amount)); + } else if (transaction_type == TransactionType::TrustSet) { + encodeType(FieldType::amount, 3, data); + append(data, serializeCurrencyAmount(limit_amount)); + } + /// "fee" encodeType(FieldType::amount, 8, data); append(data, serializeAmount(fee)); + /// "signingPubKey" if (!pub_key.empty()) { encodeType(FieldType::vl, 3, data); encodeBytes(pub_key, data); } + /// "txnSignature" if (!signature.empty()) { encodeType(FieldType::vl, 4, data); encodeBytes(signature, data); } + /// "account" encodeType(FieldType::account, 1, data); encodeBytes(serializeAddress(account), data); + /// "destination" - encodeType(FieldType::account, 3, data); - encodeBytes(destination, data); + if ((transaction_type == TransactionType::payment) || + (transaction_type == TransactionType::NFTokenCreateOffer)) { + encodeType(FieldType::account, 3, data); + encodeBytes(destination, data); + } + + /// "NFTokenOffers" + if (transaction_type == TransactionType::NFTokenCancelOffer) { + // only support one offer + encodeType(FieldType::vector256, 4, data); + encodeBytes(token_offers, data); + } + return data; } @@ -81,6 +129,104 @@ Data Transaction::serializeAmount(int64_t amount) { return data; } +Data Transaction::serializeCurrencyAmount(const CurrencyAmount& currency_amount) { + // Calculate value + // https://xrpl.org/serialization.html#token-amount-format + int64_t sign = 0; + int64_t mantissa = 0; + int32_t exp = 0; + try { + int32_t num_after_dot = 0; + bool after_dot = false; + bool after_e = false; + bool has_exp = false; + std::ostringstream mantissa_oss, exp_oss; + for (auto i : currency_amount.value) { + if (i == '.') { + after_dot = true; + } else if (i == 'e') { + after_dot = false; + after_e = true; + } else if (after_e) { + has_exp = true; + exp_oss << i; + } else { + mantissa_oss << i; + if (after_dot) { + num_after_dot++; + } + } + } + + mantissa = std::stoll(mantissa_oss.str()); + sign = (mantissa >= 0) ? 1 : 0; + mantissa = (mantissa < 0) ? (mantissa * -1) : mantissa; + + exp = has_exp ? std::stoi(exp_oss.str()) : 0; + exp -= num_after_dot; + } catch (const std::exception& e) { + return Data(); + } + + int64_t min_mantissa = (uint64_t)pow(10, 15); + int64_t max_mantissa = (uint64_t)pow(10, 16) - 1; + int32_t min_exp = -96; + int32_t max_exp = 80; + + while ((mantissa < min_mantissa) && (exp > min_exp)) { + mantissa *= 10; + exp--; + } + + while (mantissa > max_mantissa) { + if (exp >= max_exp) { + return Data(); + } + + mantissa /= 10; + exp++; + } + + if (((exp < min_exp) || (mantissa < min_mantissa)) || + ((exp > max_exp) || (mantissa > max_mantissa))) { + return Data(); + } + + typedef union { + uint64_t value; + struct { + uint64_t mantissa : 54; + uint64_t exp : 8; + uint64_t sign : 1; + uint64_t not_xrp : 1; + } parts; + } AmountCast; + + AmountCast amount_cast; + amount_cast.parts.mantissa = mantissa; + amount_cast.parts.exp = exp + 97; + amount_cast.parts.sign = sign; + amount_cast.parts.not_xrp = 1; + + // Serialize fields + // https://xrpl.org/serialization.html#amount-fields + auto data = Data(); + encode64BE(amount_cast.value, data); + + // ISO-4217 currency code + encodeZeros(1, data); // type code (0x00) + encodeZeros(11, data); // reserved + if (currency_amount.currency.size() == 3) { + data.insert(data.end(), currency_amount.currency.begin(), currency_amount.currency.end()); + } else { + encodeZeros(3, data); // none + } + + encodeZeros(5, data); // reserved + data.insert(data.end(), currency_amount.issuer.begin(), currency_amount.issuer.end()); + return data; +} + Data Transaction::serializeAddress(Address address) { auto data = Data(20); std::copy(&address.bytes[0] + 1, &address.bytes[0] + std::min(address.bytes.size(), size_t(21)), &data[0]); diff --git a/src/XRP/Transaction.h b/src/XRP/Transaction.h index a51f82eefab..836fcc5a4a5 100644 --- a/src/XRP/Transaction.h +++ b/src/XRP/Transaction.h @@ -10,25 +10,50 @@ #include "XAddress.h" #include "Data.h" #include "../proto/Ripple.pb.h" +#include "../HexCoding.h" namespace TW::Ripple { +// See https://github.com/XRPLF/rippled/blob/master/src/ripple/protocol/SField.h#L57-L74 enum class FieldType: int { - int16 = 1, - int32 = 2, - amount = 6, - vl = 7, - account = 8 + int16 = 1, + int32 = 2, + hash256 = 5, + amount = 6, + vl = 7, + account = 8, + vector256 = 19 }; -enum class TransactionType { payment = 0 }; +// See https://github.com/XRPLF/xrpl.js/blob/main/packages/ripple-binary-codec/src/enums/definitions.json +enum class TransactionType { + no_type = -1, + payment = 0, + TrustSet = 20, + NFTokenBurn = 26, + NFTokenCreateOffer = 27, + NFTokenCancelOffer = 28, + NFTokenAcceptOffer = 29 +}; + +// See https://xrpl.org/nftokencreateoffer.html +enum class NFTokenCreateOfferFlags: int64_t { + tfSellNFToken = 0x00000001 +}; class Transaction { - /// We only support transaction types other than the Payment transaction. - /// Non-XRP currencies are not supported. Float and negative amounts are not supported. + /// Float and negative amounts are not supported. /// See https://github.com/trezor/trezor-core/tree/master/src/apps/ripple#transactions public: + struct CurrencyAmount { + Data currency; + Data value; + Data issuer; + }; + int64_t amount; + CurrencyAmount currency_amount; + CurrencyAmount limit_amount; int64_t fee; int64_t flags; int32_t sequence; @@ -39,28 +64,74 @@ class Transaction { int64_t destination_tag; Data pub_key; Data signature; + Data nftoken_id; + Data sell_offer; + Data token_offers; + TransactionType transaction_type; - Transaction(int64_t amount, int64_t fee, int64_t flags, int32_t sequence, - int32_t last_ledger_sequence, Address account, const std::string& destination, - int64_t destination_tag) - : amount(amount) + Transaction(int64_t fee, int64_t flags, int32_t sequence, int32_t last_ledger_sequence, Address p_account) + : amount(0) , fee(fee) , flags(flags) , sequence(sequence) , last_ledger_sequence(last_ledger_sequence) - , account(account) { - try { - auto address = Address(destination); - encode_tag = destination_tag > 0; - this->destination_tag = destination_tag; - this->destination = Data(address.bytes.begin() + 1, address.bytes.end()); - } catch(const std::exception& e) { - auto xAddress = XAddress(destination); - encode_tag = xAddress.flag != TagFlag::none; - this->destination_tag = xAddress.tag; - this->destination = Data(xAddress.bytes.begin(), xAddress.bytes.end()); - } + , account(p_account) + , encode_tag(false) + , destination_tag(0) + , nftoken_id(0) + , sell_offer(0) + , token_offers(0) + , transaction_type(TransactionType::no_type) {} + + void createXrpPayment(int64_t p_amount, const std::string& p_destination, int64_t p_destination_tag) { + transaction_type = TransactionType::payment; + amount = p_amount; + setDestination(p_destination, p_destination_tag); + } + + void createTrustSet(const std::string& currency, const std::string& issuer) { + // Use maximum amount + // https://xrpl.org/currency-formats.html + std::string value("9999999999999999e80"); + createTrustSet(currency, value, issuer); + } + + void createTrustSet(const std::string& currency, const std::string& value, const std::string& issuer) { + transaction_type = TransactionType::TrustSet; + setCurrencyAmount(limit_amount, currency, value, issuer); + } + + void createTokenPayment(const std::string& currency, const std::string& value, const std::string& issuer, + const std::string& p_destination, int64_t p_destination_tag) { + transaction_type = TransactionType::payment; + setDestination(p_destination, p_destination_tag); + setCurrencyAmount(currency_amount, currency, value, issuer); + } + + void createNFTokenBurn(const std::string& p_nftoken_id) { + transaction_type = TransactionType::NFTokenBurn; + nftoken_id = parse_hex(p_nftoken_id); + } + + void createNFTokenCreateOffer(const std::string& p_nftoken_id, const std::string& p_destination) { + transaction_type = TransactionType::NFTokenCreateOffer; + flags = int64_t(NFTokenCreateOfferFlags::tfSellNFToken); + nftoken_id = parse_hex(p_nftoken_id); + setAccount(p_destination, destination); + } + + void createNFTokenAcceptOffer(const std::string& p_sell_offer) { + transaction_type = TransactionType::NFTokenAcceptOffer; + sell_offer = parse_hex(p_sell_offer); + } + + void createNFTokenCancelOffer(const std::vector p_token_offers) { + transaction_type = TransactionType::NFTokenCancelOffer; + for (auto i : p_token_offers) { + Data token_offer = parse_hex(i); + token_offers.insert(token_offers.end(), token_offer.begin(), token_offer.end()); } + } public: /// simplified serialization format tailored for Payment transaction type @@ -69,7 +140,39 @@ class Transaction { Data getPreImage() const; static Data serializeAmount(int64_t amount); + static Data serializeCurrencyAmount(const CurrencyAmount& currency_amount); static Data serializeAddress(Address address); + + private: + void setCurrencyAmount(CurrencyAmount& p_currency_amount, const std::string& currency, const std::string& value, const std::string& issuer) { + p_currency_amount.currency = Data(currency.begin(), currency.end()); + p_currency_amount.value = Data(value.begin(), value.end()); + setAccount(issuer, p_currency_amount.issuer); + } + + void setDestination(const std::string& p_destination, int64_t p_destination_tag) { + try { + auto address = Address(p_destination); + encode_tag = p_destination_tag > 0; + destination_tag = p_destination_tag; + destination = Data(address.bytes.begin() + 1, address.bytes.end()); + } catch(const std::exception& e) { + auto xAddress = XAddress(p_destination); + encode_tag = xAddress.flag != TagFlag::none; + destination_tag = xAddress.tag; + destination = Data(xAddress.bytes.begin(), xAddress.bytes.end()); + } + } + + void setAccount(const std::string& p_account, Data& data) { + try { + auto address = Address(p_account); + data = Data(address.bytes.begin() + 1, address.bytes.end()); + } catch(const std::exception& e) { + auto xAddress = XAddress(p_account); + data = Data(xAddress.bytes.begin(), xAddress.bytes.end()); + } + } }; } // namespace TW::Ripple diff --git a/src/proto/Ripple.proto b/src/proto/Ripple.proto index ffbb863741c..dd903dc7435 100644 --- a/src/proto/Ripple.proto +++ b/src/proto/Ripple.proto @@ -5,34 +5,101 @@ option java_package = "wallet.core.jni.proto"; import "Common.proto"; -// Input data necessary to create a signed transaction. -message SigningInput { +// https://xrpl.org/currency-formats.html#token-amounts +message CurrencyAmount { + // Currency code + // https://xrpl.org/currency-formats.html#currency-codes + string currency = 1; + + // String number + // https://xrpl.org/currency-formats.html#string-numbers + string value = 2; + + // Account + // https://xrpl.org/accounts.html + string issuer = 3; +} + +// https://xrpl.org/trustset.html +message OperationTrustSet { + CurrencyAmount limit_amount = 1; +} + +// https://xrpl.org/payment.html +message OperationPayment { // Transfer amount - int64 amount = 1; + oneof amount_oneof { + int64 amount = 1; + CurrencyAmount currency_amount = 2; + } + + // Target account + string destination = 3; + + // A Destination Tag + int64 destination_tag = 4; +} + +// https://xrpl.org/nftokenburn.html +message OperationNFTokenBurn { + // Hash256 NFTokenId + bytes nftoken_id = 1; +} + +// https://xrpl.org/nftokencreateoffer.html +message OperationNFTokenCreateOffer { + // Hash256 NFTokenId + bytes nftoken_id = 1; + + // Destination account + string destination = 2; +} + +// https://xrpl.org/nftokenacceptoffer.html +message OperationNFTokenAcceptOffer { + // Hash256 NFTokenOffer + bytes sell_offer = 1; +} + +// https://xrpl.org/nftokencanceloffer.html +message OperationNFTokenCancelOffer { + // Vector256 NFTokenOffers + repeated bytes token_offers = 1; +} +// Input data necessary to create a signed transaction. +message SigningInput { // Transfer fee - int64 fee = 2; + int64 fee = 1; // Account sequence number - int32 sequence = 3; + int32 sequence = 2; // Ledger sequence number - int32 last_ledger_sequence = 4; + int32 last_ledger_sequence = 3; // Source account - string account = 5; - - // Target account - string destination = 6; - - // A Destination Tag - int64 destination_tag = 7; + string account = 4; // Transaction flags, optional - int64 flags = 8; + int64 flags = 5; // The secret private key used for signing (32 bytes). - bytes private_key = 9; + bytes private_key = 6; + + oneof operation_oneof { + OperationTrustSet op_trust_set = 7; + + OperationPayment op_payment = 8; + + OperationNFTokenBurn op_nftoken_burn = 9; + + OperationNFTokenCreateOffer op_nftoken_create_offer = 10; + + OperationNFTokenAcceptOffer op_nftoken_accept_offer = 11; + + OperationNFTokenCancelOffer op_nftoken_cancel_offer = 12; + } } // Result containing the signed and encoded transaction. diff --git a/swift/Tests/Blockchains/RippleTests.swift b/swift/Tests/Blockchains/RippleTests.swift index e42151c04e3..c2e96a65781 100644 --- a/swift/Tests/Blockchains/RippleTests.swift +++ b/swift/Tests/Blockchains/RippleTests.swift @@ -29,25 +29,33 @@ class RippleTests: XCTestCase { } func testSigner() { - let input = RippleSigningInput.with { - $0.amount = 29_000_000 - $0.fee = 200_000 - $0.sequence = 1 // from account info api - $0.account = "rDpysuumkweqeC7XdNgYNtzL5GxbdsmrtF" + let operation = RippleOperationPayment.with { $0.destination = "rU893viamSnsfP3zjzM2KPxjqZjXSXK6VF" - $0.privateKey = Data(hexString: "ba005cd605d8a02e3d5dfd04234cef3a3ee4f76bfbad2722d1fb5af8e12e6764")! + $0.amount = 10 + } + let input = RippleSigningInput.with { + $0.fee = 10 + $0.sequence = 32268248 // from account info api + $0.lastLedgerSequence = 32268269 + $0.account = "rfxdLwsZnoespnTDDb1Xhvbc8EFNdztaoq" + $0.privateKey = Data(hexString: "a5576c0f63da10e584568c8d134569ff44017b0a249eb70657127ae04f38cc77")! + $0.opPayment = operation } let output: RippleSigningOutput = AnySigner.sign(input: input, coin: .xrp) - XCTAssertEqual(output.encoded.hexString, "12000022800000002400000001614000000001ba8140684000000000030d407321026cc34b92cefb3a4537b3edb0b6044c04af27c01583c577823ecc69a9a21119b6744630440220067f20b3eebfc7107dd0bcc72337a236ac3be042c0469f2341d76694a17d4bb9022048393d7ee7dcb729783b33f5038939ddce1bb8337e66d752974626854556bbb681148400b6b6d08d5d495653d73eda6804c249a5148883148132e4e20aecf29090ac428a9c43f230a829220d") + XCTAssertEqual(output.encoded.hexString, "12000022000000002401ec5fd8201b01ec5fed61400000000000000a68400000000000000a732103d13e1152965a51a4a9fd9a8b4ea3dd82a4eba6b25fcad5f460a2342bb650333f74463044022037d32835c9394f39b2cfd4eaf5b0a80e0db397ace06630fa2b099ff73e425dbc02205288f780330b7a88a1980fa83c647b5908502ad7de9a44500c08f0750b0d9e8481144c55f5a78067206507580be7bb2686c8460adff983148132e4e20aecf29090ac428a9c43f230a829220d") - let input2 = RippleSigningInput.with { - $0.amount = 29_000_000 - $0.fee = 200_000 - $0.sequence = 1 // from account info api - $0.account = "rDpysuumkweqeC7XdNgYNtzL5GxbdsmrtF" + let operation2 = RippleOperationPayment.with { $0.destination = "XVfvixWZQKkcenFRYApCjpTUyJ4BePMjMaPqnob9QVPiVJV" - $0.privateKey = Data(hexString: "ba005cd605d8a02e3d5dfd04234cef3a3ee4f76bfbad2722d1fb5af8e12e6764")! + $0.amount = 10 + } + let input2 = RippleSigningInput.with { + $0.fee = 10 + $0.sequence = 32268248 // from account info api + $0.lastLedgerSequence = 32268269 + $0.account = "rfxdLwsZnoespnTDDb1Xhvbc8EFNdztaoq" + $0.privateKey = Data(hexString: "a5576c0f63da10e584568c8d134569ff44017b0a249eb70657127ae04f38cc77")! + $0.opPayment = operation } let output2: RippleSigningOutput = AnySigner.sign(input: input2, coin: .xrp) XCTAssertEqual(output2.encoded, output.encoded) diff --git a/tests/chains/XRP/TWAnySignerTests.cpp b/tests/chains/XRP/TWAnySignerTests.cpp index 1b9e05728e6..47fcbd9d232 100644 --- a/tests/chains/XRP/TWAnySignerTests.cpp +++ b/tests/chains/XRP/TWAnySignerTests.cpp @@ -16,24 +16,26 @@ using namespace TW; namespace TW::Ripple::tests { -TEST(TWAnySignerRipple, Sign) { - auto key = parse_hex("ba005cd605d8a02e3d5dfd04234cef3a3ee4f76bfbad2722d1fb5af8e12e6764"); +TEST(TWAnySignerRipple, SignXrpPayment) { + // https://testnet.xrpl.org/transactions/A202034796F37F38D1D20F2025DECECB1623FC801F041FC694199C0D0E49A739 + auto key = parse_hex("a5576c0f63da10e584568c8d134569ff44017b0a249eb70657127ae04f38cc77"); Proto::SigningInput input; - input.set_amount(29000000); - input.set_fee(200000); - input.set_sequence(1); - input.set_account("rDpysuumkweqeC7XdNgYNtzL5GxbdsmrtF"); - input.set_destination("rU893viamSnsfP3zjzM2KPxjqZjXSXK6VF"); + input.mutable_op_payment()->set_amount(10); + input.set_fee(10); + input.set_sequence(32268248); + input.set_last_ledger_sequence(32268269); + input.set_account("rfxdLwsZnoespnTDDb1Xhvbc8EFNdztaoq"); + input.mutable_op_payment()->set_destination("rU893viamSnsfP3zjzM2KPxjqZjXSXK6VF"); input.set_private_key(key.data(), key.size()); Proto::SigningOutput output; ANY_SIGN(input, TWCoinTypeXRP); - EXPECT_EQ(hex(output.encoded()), "12000022800000002400000001614000000001ba8140684000000000030d407321026cc34b92cefb3a4537b3edb0b6044c04af27c01583c577823ecc69a9a21119b6744630440220067f20b3eebfc7107dd0bcc72337a236ac3be042c0469f2341d76694a17d4bb9022048393d7ee7dcb729783b33f5038939ddce1bb8337e66d752974626854556bbb681148400b6b6d08d5d495653d73eda6804c249a5148883148132e4e20aecf29090ac428a9c43f230a829220d"); + EXPECT_EQ(hex(output.encoded()), "12000022000000002401ec5fd8201b01ec5fed61400000000000000a68400000000000000a732103d13e1152965a51a4a9fd9a8b4ea3dd82a4eba6b25fcad5f460a2342bb650333f74463044022037d32835c9394f39b2cfd4eaf5b0a80e0db397ace06630fa2b099ff73e425dbc02205288f780330b7a88a1980fa83c647b5908502ad7de9a44500c08f0750b0d9e8481144c55f5a78067206507580be7bb2686c8460adff983148132e4e20aecf29090ac428a9c43f230a829220d"); // invalid tag - input.set_destination_tag(641505641505); + input.mutable_op_payment()->set_destination_tag(641505641505); ANY_SIGN(input, TWCoinTypeXRP); @@ -41,4 +43,160 @@ TEST(TWAnySignerRipple, Sign) { EXPECT_EQ(output.encoded(), ""); } +TEST(TWAnySignerRipple, SignXrpPaymentMain) { + // https://xrpscan.com/tx/4B9D022E8C77D798B7D11C41FDFDCF468F03A5564151C520EECA1E96FF1A1610 + auto key = parse_hex("acf1bbf6264e699da0cc65d17ac03fcca6ded1522d19529df7762db46097ff9f"); + Proto::SigningInput input; + + input.mutable_op_payment()->set_amount(1000000); + input.set_fee(10); + input.set_sequence(75674534); + input.set_last_ledger_sequence(75674797); + input.set_account("rGV1v1xw23PHcRn4Km4tF8R2mfh6yTZkcP"); + input.mutable_op_payment()->set_destination("rNLpgsBTCwiaZAnHe2ZViAN1GcXZtYW6rg"); + input.set_private_key(key.data(), key.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeXRP); + + EXPECT_EQ(hex(output.encoded()), "1200002200000000240482b3a6201b0482b4ad6140000000000f424068400000000000000a7321027efc5f15071d2ae5e73ee09a0c17456c5d9170a41d67e3297c554829199be80b74473045022100e1c746c3aeebc8278c627ee4c2ce5cae97e3856292c7fe5388f803920230a37b02207d2eccb76cd35dd379d6b24c2cabd786e62d34a564cf083e863176109c5b6bb48114aa000c09c692ef1f82787e51e22833149941ea2083149232ef60695add51f0f84534cc4084e4fdfc698e"); +} + +TEST(TWAnySignerRipple, SignTrustSetPayment) { + // https://testnet.xrpl.org/transactions/31042345374CFF785B3F7E2A3716E3BAB7E2CAA30D40F5E488E67ABA116655B9 + auto key = parse_hex("8753e78ee2963f301f82e5eeab2754f593fc242ce94273dd2fb0684e3b0f2b91"); + Proto::SigningInput input; + + input.mutable_op_trust_set()->mutable_limit_amount()->set_currency("USD"); + input.mutable_op_trust_set()->mutable_limit_amount()->set_value("10"); + input.mutable_op_trust_set()->mutable_limit_amount()->set_issuer("rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"); + input.set_fee(10); + input.set_sequence(32268473); + input.set_last_ledger_sequence(32268494); + input.set_account("rnRkLPni2Q5yMxSqyJSJEkKUfQNFkaAspS"); + input.set_private_key(key.data(), key.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeXRP); + + EXPECT_EQ(hex(output.encoded()), "12001422000000002401ec60b9201b01ec60ce63d4c38d7ea4c6800000000000000000000000000055534400000000004b4e9c06f24296074f7bc48f92a97916c6dc5ea968400000000000000a732103dc4a0dae2d550de7cace9c26c1a331a114e3e7efee5577204b476d27e2dc683a7446304402206ebcc7a689845df373dd2566cd3789862d426d9ad4e6a09c2d2772b57e82696a022066b1f217a0f0d834d167613a313f74097423a9ccd11f1ae7f90ffab0d2fc26b58114308ea8e515b64f2e6616a33b42e1bbb9fa00bbd2"); +} + +TEST(TWAnySignerRipple, SignTokenPayment0) { + // https://testnet.xrpl.org/transactions/8F7820892294598B58CFA2E1101D15ED98C179B25A2BA6DAEB4F5B727CB00D4E + for (auto value : std::vector({"10", "10e0", "10.0", "10.0e0", "1e1", ".1e2", "0.1e2", "100e-1", "10000000000000000e-15", "0.0000000000000001e17"})) { + auto key = parse_hex("4ba5fd2ebf0f5d7e579b3c354c263ebb39cda4093845125786a280301af14e21"); + Proto::SigningInput input; + + input.mutable_op_payment()->mutable_currency_amount()->set_currency("USD"); + input.mutable_op_payment()->mutable_currency_amount()->set_value("10"); + input.mutable_op_payment()->mutable_currency_amount()->set_issuer("rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"); + input.set_fee(10); + input.set_sequence(32268645); + input.set_last_ledger_sequence(32268666); + input.set_account("raPAA61ca99bdwNiZs5JJukR5rvkHWvkBX"); + input.mutable_op_payment()->set_destination("rU893viamSnsfP3zjzM2KPxjqZjXSXK6VF"); + input.set_private_key(key.data(), key.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeXRP); + + EXPECT_EQ(hex(output.encoded()), "12000022000000002401ec6165201b01ec617a61d4c38d7ea4c6800000000000000000000000000055534400000000004b4e9c06f24296074f7bc48f92a97916c6dc5ea968400000000000000a7321020652a477b0cca8b74d6e68a6a386a836b226101617481b95180eaffbe841b3227446304402203e925caeb05006afb135254e9ae4e46de2019db6c6f68614ef969885063a777602206af110fc29775256fcad8b14974c6a838141d82193192d3b57324fe1079afa1781143b2fa4f36553e5b7a4f54ff9e6883e44b4b0dbb383148132e4e20aecf29090ac428a9c43f230a829220d"); + } +} + +TEST(TWAnySignerRipple, SignTokenPayment1) { + // https://testnet.xrpl.org/transactions/14606DAAFA54DB29B738000DFC133312B341FFC1D22D57AE0C8D54C9C56E19D8 + auto key = parse_hex("4041882ce8c2ceea6f4cfe1a067b927c1e1eb2f5eb025eaf2f429479a7ec3738"); + Proto::SigningInput input; + + input.mutable_op_payment()->mutable_currency_amount()->set_currency("USD"); + input.mutable_op_payment()->mutable_currency_amount()->set_value("29.3e-1"); + input.mutable_op_payment()->mutable_currency_amount()->set_issuer("rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"); + input.set_fee(10); + input.set_sequence(32268768); + input.set_last_ledger_sequence(32268789); + input.set_account("raJe5XVt99649qn5Pg7cKdmgEYdN3d4Mky"); + input.mutable_op_payment()->set_destination("rU893viamSnsfP3zjzM2KPxjqZjXSXK6VF"); + input.set_private_key(key.data(), key.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeXRP); + + EXPECT_EQ(hex(output.encoded()), "12000022000000002401ec61e0201b01ec61f561d48a68d1c931200000000000000000000000000055534400000000004b4e9c06f24296074f7bc48f92a97916c6dc5ea968400000000000000a73210348c331ab218ba964150490c83875b06ccad2100b1f5707f296764712738cf1ca74473045022100a938783258d33e2e3e6099d1ab68fd85c3fd21adfa00e136a67bed8fddec6c9a02206cc6784c1f212f19dc939207643d361ceaa8334eb366722cf33b24dc7669dd7a81143a2f2f189d05abb8519cc9dee0e2dbc6fa53924183148132e4e20aecf29090ac428a9c43f230a829220d"); +} + +TEST(TWAnySignerRipple, SignNfTokenBurn) { + // https://devnet.xrpl.org/transactions/37DA90BE3C30016B3A2C3D47D9677278A3F6D4141B318793CE6AA467A6530E2D + auto key = parse_hex("7c2ea5c7b1fd7dfc62d879918b7fc779cdff6bf6391d02ec99854297e916318e"); + Proto::SigningInput input; + + input.mutable_op_nftoken_burn()->set_nftoken_id("000b013a95f14b0044f78a264e41713c64b5f89242540ee208c3098e00000d65"); + input.set_fee(10); + input.set_sequence(22858395); + input.set_last_ledger_sequence(22858416); + input.set_account("rhR1mTXkg4iSGhz7zsEKBLbV3MkopivPVF"); + input.set_private_key(key.data(), key.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeXRP); + + EXPECT_EQ(hex(output.encoded()), "12001a220000000024015cca9b201b015ccab05a000b013a95f14b0044f78a264e41713c64b5f89242540ee208c3098e00000d6568400000000000000a73210254fc876043109af1ff11b832320be4436ef51dcc344da5970c9b6c6d1fbcddcf744730450221008b4d437bc92aa4643b275b17c0f88a1bef2c1c160ece5faf93b03e2d31b8278602207640e7e35426352deaafecf61e2b401a4ea1fc645839280370a72fa3c41aea7d8114259cbcf9635360bc302f27d0ce72c18d4dbe9c8d"); +} + +TEST(TWAnySignerRipple, SignNfTokenCreateOffer) { + // https://devnet.xrpl.org/transactions/E61D66E261DB89CEAAB4F54ECF792B329296CB524E8B40EA99D27CF5E16DD27D + auto key = parse_hex("1963884da4a4da79ad7681d106b2c55fb652c68ca7b288dd12bb86cd40b9d940"); + Proto::SigningInput input; + + input.mutable_op_nftoken_create_offer()->set_nftoken_id("000b013a95f14b0044f78a264e41713c64b5f89242540ee208c3098e00000d65"); + input.mutable_op_nftoken_create_offer()->set_destination("rDxTa8vhigDUCq9nmZY8jAkFne5XrcYbxG"); + input.set_fee(10); + input.set_sequence(22857522); + input.set_last_ledger_sequence(22857543); + input.set_account("rJdxtrVoL3Tak74EzN8SdMxFF6RP9smjJJ"); + input.set_private_key(key.data(), key.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeXRP); + + EXPECT_EQ(hex(output.encoded()), "12001b220000000124015cc732201b015cc7475a000b013a95f14b0044f78a264e41713c64b5f89242540ee208c3098e00000d6561400000000000000068400000000000000a7321022707066e4f8b87b749ef802338be064065dc978f0ea52ea9c8c8ea0a6145571974473045022100a148140469b8e9e2f9aa43631f3101e532d161d49a05e739cd3494ea208bd657022029a9752df3fc0d23b8fdb46d2274e69ab198ce6f373aeb7cdd0d81ab05aff6f48114c177c23ed1f5d175f42fd7970ece74ac18d61c4d83148e1e2ca343165bf30e96abead961f7a34510ad93"); +} + +TEST(TWAnySignerRipple, SignNfTokenAcceptOffer) { + // https://devnet.xrpl.org/transactions/6BB00A7BABB8797D60E3AB0E52DB64562524D014833977D87B04CA9FA3F56AD7 + auto key = parse_hex("3c01b3458d2b2a4b86a5699d11682d791b5c3136692c5594f7a8ca7f3967e7ae"); + Proto::SigningInput input; + + input.mutable_op_nftoken_accept_offer()->set_sell_offer("000b013a95f14b0044f78a264e41713c64b5f89242540ee208c3098e00000d65"); + input.set_fee(10); + input.set_sequence(22857743); + input.set_last_ledger_sequence(22857764); + input.set_account("rPa2KsEuSuZnmjosds99nhgsoiKtw85j6Z"); + input.set_private_key(key.data(), key.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeXRP); + + EXPECT_EQ(hex(output.encoded()), "12001d220000000024015cc80f201b015cc824501d000b013a95f14b0044f78a264e41713c64b5f89242540ee208c3098e00000d6568400000000000000a73210331c298cb86428b9126bd4af6a952870cfe3fe5065dc093cf97f3edbb27e9dd15744630440220797922caaa593c4e91fa6b63a38c92ef9f5e2183128918dda166f4292882e137022057702b668d7463ef1d01dad5ee6633bd36f0aa358dacc90d6b68d248672a400f8114f260a758132d3ed27e52d7f55ef0481606f090d4"); +} + +TEST(TWAnySignerRipple, SignNfTokenCancelOffer) { + // https://devnet.xrpl.org/transactions/CBA148308A0D1561E5E8CDF1F2E8D5562C320C221AC4053AA5F495CEF4B5D5D4 + auto key = parse_hex("3e50cc102d8c96abd55f047a536b6425154514ba8abdf5f09335a7c644176c5d"); + Proto::SigningInput input; + + input.mutable_op_nftoken_cancel_offer()->add_token_offers("000b013a95f14b0044f78a264e41713c64b5f89242540ee208c3098e00000d65"); + input.set_fee(10); + input.set_sequence(22857838); + input.set_last_ledger_sequence(22857859); + input.set_account("rPqczdU9bzow966hQKQejsXrMJspM7G4CC"); + input.set_private_key(key.data(), key.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeXRP); + + EXPECT_EQ(hex(output.encoded()), "12001c220000000024015cc86e201b015cc88368400000000000000a7321022250f103fd045edf2e552df2d20aca01a52dc6aedd522d68767f1c744fedb39d74463044022015fff495fc5d61cd71e5815e4d23845ec26f4dc94adb85207feba2c97e19856502207297ec84afc0bb74aa8a20d7254025a82d9b9f177f648845d8c72ee62884ff618114fa84c77f2a5245ef774845d40428d2a6f9603415041320000b013a95f14b0044f78a264e41713c64b5f89242540ee208c3098e00000d65"); +} + } // namespace TW::Ripple::tests diff --git a/tests/chains/XRP/TransactionTests.cpp b/tests/chains/XRP/TransactionTests.cpp index f9015b684da..c2ff41a54b6 100644 --- a/tests/chains/XRP/TransactionTests.cpp +++ b/tests/chains/XRP/TransactionTests.cpp @@ -43,12 +43,14 @@ TEST(RippleTransaction, serialize) { auto account = Address("r9TeThyi5xiuUUrFjtPKZiHcDxs7K9H6Rb"); auto destination = "r4BPgS7DHebQiU31xWELvZawwSG2fSPJ7C"; auto tx1 = Transaction( - /* amount */25000000, /* fee */10, /* flags */0, /* sequence */2, /* last_ledger_sequence */0, - /* account */account, + /* account */account + ); + tx1.createXrpPayment( + /* amount */25000000, /* destination */destination, /* destination_tag*/0 ); @@ -56,12 +58,14 @@ TEST(RippleTransaction, serialize) { ASSERT_EQ(hex(serialized1), "120000220000000024000000026140000000017d784068400000000000000a81145ccb151f6e9d603f394ae778acf10d3bece874f68314e851bbbe79e328e43d68f43445368133df5fba5a"); auto tx2 = Transaction( - /* amount */200000, /* fee */15, /* flags */0, /* sequence */144, /* last_ledger_sequence */0, - /* account */Address("rGWTUVmm1fB5QUjMYn8KfnyrFNgDiD9H9e"), + /* account */Address("rGWTUVmm1fB5QUjMYn8KfnyrFNgDiD9H9e") + ); + tx2.createXrpPayment( + /* amount */200000, /* destination */"rw71Qs1UYQrSQ9hSgRohqNNQcyjCCfffkQ", /* destination_tag*/0 ); @@ -69,12 +73,14 @@ TEST(RippleTransaction, serialize) { ASSERT_EQ(hex(serialized2), "12000022000000002400000090614000000000030d4068400000000000000f8114aa1bd19d9e87be8069fdbf6843653c43837c03c6831467fe6ec28e0464dd24fb2d62a492aac697cfad02"); auto tx3 = Transaction( - /* amount */25000000, /* fee */12, /* flags */0, /* sequence */1, /* last_ledger_sequence */0, - /* account */Address("r4BPgS7DHebQiU31xWELvZawwSG2fSPJ7C"), + /* account */Address("r4BPgS7DHebQiU31xWELvZawwSG2fSPJ7C") + ); + tx3.createXrpPayment( + /* amount */25000000, /* destination */"rBqSFEFg2B6GBMobtxnU1eLA1zbNC9NDGM", /* destination_tag*/4146942154 ); @@ -82,12 +88,14 @@ TEST(RippleTransaction, serialize) { ASSERT_EQ(hex(serialized3), "120000220000000024000000012ef72d50ca6140000000017d784068400000000000000c8114e851bbbe79e328e43d68f43445368133df5fba5a831476dac5e814cd4aa74142c3ab45e69a900e637aa2"); auto tx4 = Transaction( - /* amount */25000000, /* fee */12, /* flags */0, /* sequence */1, /* last_ledger_sequence */0, - /* account */Address("r4BPgS7DHebQiU31xWELvZawwSG2fSPJ7C"), + /* account */Address("r4BPgS7DHebQiU31xWELvZawwSG2fSPJ7C") + ); + tx4.createXrpPayment( + /* amount */25000000, /* destination */"XVhidoXkozM5DTZFdDnJ5nYC8FPrTuJiyGh1VxSGS6RNJJ5", /* ignore destination_tag*/12345 ); @@ -99,12 +107,14 @@ TEST(RippleTransaction, preImage) { auto account = Address("r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ"); auto destination = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; auto tx1 = Transaction( - /* amount */1000, /* fee */10, /* flags */2147483648, /* sequence */1, /* last_ledger_sequence */0, - /* account */account, + /* account */account + ); + tx1.createXrpPayment( + /* amount */1000, /* destination */destination, /* destination_tag*/0 ); From 69b2da9826dfdeb8116be1e5a3747b3e9418592d Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 21 Nov 2022 06:58:46 +0100 Subject: [PATCH 141/497] [Encryption]: add support for aes-256-ctr (#2726) --- .../core/app/utils/TestKeyStore.kt | 11 ++++ include/TrustWalletCore/TWBase.h | 7 ++ include/TrustWalletCore/TWStoredKey.h | 49 +++++++++++++- .../TrustWalletCore/TWStoredKeyEncryption.h | 22 +++++++ src/Keystore/AESParameters.cpp | 41 ++++++++++-- src/Keystore/AESParameters.h | 29 ++++++-- src/Keystore/EncryptionParameters.cpp | 40 +++++++---- src/Keystore/EncryptionParameters.h | 36 +++++----- src/Keystore/StoredKey.cpp | 24 +++---- src/Keystore/StoredKey.h | 13 ++-- src/interface/TWStoredKey.cpp | 27 ++++++-- swift/Sources/KeyStore.swift | 30 ++++----- swift/Tests/Keystore/KeyStoreTests.swift | 24 +++++++ tests/chains/XRP/TWAnySignerTests.cpp | 33 ++++------ tests/common/Keystore/StoredKeyTests.cpp | 51 +++++++++++++- tests/interface/TWStoredKeyTests.cpp | 66 +++++++++++++++++-- wasm/src/keystore/default-impl.ts | 16 +++-- wasm/src/keystore/types.ts | 8 ++- wasm/tests/KeyStore+extension.test.ts | 60 ++++++++++++++++- wasm/tests/KeyStore+fs.test.ts | 62 ++++++++++++++++- 20 files changed, 531 insertions(+), 118 deletions(-) create mode 100644 include/TrustWalletCore/TWStoredKeyEncryption.h diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt index 3832db95139..599d3369216 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt @@ -4,6 +4,7 @@ import org.junit.Assert.* import org.junit.Test import wallet.core.jni.StoredKey import wallet.core.jni.CoinType +import wallet.core.jni.StoredKeyEncryption class TestKeyStore { @@ -21,6 +22,16 @@ class TestKeyStore { assertNotNull(result2) } + @Test + fun testDecryptMnemonicAes256() { + val keyStore = StoredKey("Test Wallet", "password".toByteArray(), StoredKeyEncryption.AES256CTR) + val result = keyStore.decryptMnemonic("wrong".toByteArray()) + val result2 = keyStore.decryptMnemonic("password".toByteArray()) + + assertNull(result) + assertNotNull(result2) + } + @Test fun testRemoveCoins() { val password = "password".toByteArray() diff --git a/include/TrustWalletCore/TWBase.h b/include/TrustWalletCore/TWBase.h index 17e618ace45..de300b6779b 100644 --- a/include/TrustWalletCore/TWBase.h +++ b/include/TrustWalletCore/TWBase.h @@ -55,6 +55,13 @@ #define TW_ASSUME_NONNULL_END #endif +#if defined(__cplusplus) && (__cplusplus >= 201402L) +# define TW_DEPRECATED(since) [[deprecated("Since " #since)]] +# define TW_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]] +#else +# define TW_DEPRECATED(since) +# define TW_DEPRECATED_FOR(since, replacement) +#endif #if !__has_feature(nullability) #ifndef _Nullable diff --git a/include/TrustWalletCore/TWStoredKey.h b/include/TrustWalletCore/TWStoredKey.h index 02bd0ae4dad..7d916be9e91 100644 --- a/include/TrustWalletCore/TWStoredKey.h +++ b/include/TrustWalletCore/TWStoredKey.h @@ -13,6 +13,7 @@ #include "TWHDWallet.h" #include "TWPrivateKey.h" #include "TWStoredKeyEncryptionLevel.h" +#include "TWStoredKeyEncryption.h" #include "TWString.h" TW_EXTERN_C_BEGIN @@ -40,6 +41,18 @@ struct TWStoredKey* _Nullable TWStoredKeyLoad(TWString* _Nonnull path); TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKey(TWData* _Nonnull privateKey, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin); +/// Imports a private key. +/// +/// \param privateKey Non-null Block of data private key +/// \param name The name of the stored key to import as a non-null string +/// \param password Non-null block of data, password of the stored key +/// \param coin the coin type +/// \param encryption cipher encryption mode +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return Nullptr if the key can't be imported, the stored key otherwise +TW_EXPORT_STATIC_METHOD +struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKeyWithEncryption(TWData* _Nonnull privateKey, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin, enum TWStoredKeyEncryption encryption); + /// Imports an HD wallet. /// /// \param mnemonic Non-null bip39 mnemonic @@ -51,6 +64,18 @@ struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKey(TWData* _Nonnull priva TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nullable TWStoredKeyImportHDWallet(TWString* _Nonnull mnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin); +/// Imports an HD wallet. +/// +/// \param mnemonic Non-null bip39 mnemonic +/// \param name The name of the stored key to import as a non-null string +/// \param password Non-null block of data, password of the stored key +/// \param coin the coin type +/// \param encryption cipher encryption mode +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return Nullptr if the key can't be imported, the stored key otherwise +TW_EXPORT_STATIC_METHOD +struct TWStoredKey* _Nullable TWStoredKeyImportHDWalletWithEncryption(TWString* _Nonnull mnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin, enum TWStoredKeyEncryption encryption); + /// Imports a key from JSON. /// /// \param json Json stored key import format as a non-null block of data @@ -59,16 +84,28 @@ struct TWStoredKey* _Nullable TWStoredKeyImportHDWallet(TWString* _Nonnull mnemo TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nullable TWStoredKeyImportJSON(TWData* _Nonnull json); -/// Creates a new key, with given encryption strength level. Returned object needs to be deleted. +/// Creates a new key, with given encryption strength level. Returned object needs to be deleted. /// /// \param name The name of the key to be stored /// \param password Non-null block of data, password of the stored key /// \param encryptionLevel The level of encryption, see \TWStoredKeyEncryptionLevel /// \note Returned object needs to be deleted with \TWStoredKeyDelete /// \return The stored key as a non-null pointer +TW_DEPRECATED_FOR("3.1.1", "TWStoredKeyCreateLevelAndEncryption") TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nonnull TWStoredKeyCreateLevel(TWString* _Nonnull name, TWData* _Nonnull password, enum TWStoredKeyEncryptionLevel encryptionLevel); +/// Creates a new key, with given encryption strength level. Returned object needs to be deleted. +/// +/// \param name The name of the key to be stored +/// \param password Non-null block of data, password of the stored key +/// \param encryptionLevel The level of encryption, see \TWStoredKeyEncryptionLevel +/// \param encryption cipher encryption mode +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return The stored key as a non-null pointer +TW_EXPORT_STATIC_METHOD +struct TWStoredKey* _Nonnull TWStoredKeyCreateLevelAndEncryption(TWString* _Nonnull name, TWData* _Nonnull password, enum TWStoredKeyEncryptionLevel encryptionLevel, enum TWStoredKeyEncryption encryption); + /// Creates a new key. /// /// \deprecated use TWStoredKeyCreateLevel. @@ -78,6 +115,16 @@ struct TWStoredKey* _Nonnull TWStoredKeyCreateLevel(TWString* _Nonnull name, TWD /// \return The stored key as a non-null pointer TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nonnull TWStoredKeyCreate(TWString* _Nonnull name, TWData* _Nonnull password); +/// Creates a new key. +/// +/// \deprecated use TWStoredKeyCreateLevel. +/// \param name The name of the key to be stored +/// \param password Non-null block of data, password of the stored key +/// \param encryption cipher encryption mode +/// \note Returned object needs to be deleted with \TWStoredKeyDelete +/// \return The stored key as a non-null pointer +TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nonnull TWStoredKeyCreateEncryption(TWString* _Nonnull name, TWData* _Nonnull password, enum TWStoredKeyEncryption encryption); + /// Delete a stored key /// /// \param key The key to be deleted diff --git a/include/TrustWalletCore/TWStoredKeyEncryption.h b/include/TrustWalletCore/TWStoredKeyEncryption.h new file mode 100644 index 00000000000..b2db9e795e0 --- /dev/null +++ b/include/TrustWalletCore/TWStoredKeyEncryption.h @@ -0,0 +1,22 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" + +TW_EXTERN_C_BEGIN + +/// Preset encryption kind +TW_EXPORT_ENUM(uint32_t) +enum TWStoredKeyEncryption { + TWStoredKeyEncryptionAes128Ctr = 0, + TWStoredKeyEncryptionAes128Cbc = 1, + TWStoredKeyEncryptionAes192Ctr = 2, + TWStoredKeyEncryptionAes256Ctr = 3, +}; + +TW_EXTERN_C_END diff --git a/src/Keystore/AESParameters.cpp b/src/Keystore/AESParameters.cpp index 6aa7bfdc5b0..22f0df40697 100644 --- a/src/Keystore/AESParameters.cpp +++ b/src/Keystore/AESParameters.cpp @@ -12,20 +12,44 @@ using namespace TW; -namespace TW::Keystore { +namespace { -AESParameters::AESParameters() { - iv = Data(blockSize, 0); +Data generateIv(std::size_t blockSize = TW::Keystore::gBlockSize) { + auto iv = Data(blockSize, 0); random_buffer(iv.data(), blockSize); + return iv; +} + +static TWStoredKeyEncryption getCipher(const std::string& cipher) { + if (cipher == Keystore::gAes128Ctr) { + return TWStoredKeyEncryption::TWStoredKeyEncryptionAes128Ctr; + } else if (cipher == Keystore::gAes192Ctr) { + return TWStoredKeyEncryption::TWStoredKeyEncryptionAes192Ctr; + } else if (cipher == Keystore::gAes256Ctr) { + return TWStoredKeyEncryption::TWStoredKeyEncryptionAes256Ctr; + } + return TWStoredKeyEncryptionAes128Ctr; } +const std::unordered_map gEncryptionRegistry{ + {TWStoredKeyEncryptionAes128Ctr, Keystore::AESParameters{.mKeyLength = Keystore::A128, .mCipher = Keystore::gAes128Ctr, .mCipherEncryption = TWStoredKeyEncryptionAes128Ctr}}, + {TWStoredKeyEncryptionAes128Cbc, Keystore::AESParameters{.mKeyLength = Keystore::A128, .mCipher = Keystore::gAes128Cbc, .mCipherEncryption = TWStoredKeyEncryptionAes128Cbc}}, + {TWStoredKeyEncryptionAes192Ctr, Keystore::AESParameters{.mKeyLength = Keystore::A192, .mCipher = Keystore::gAes192Ctr, .mCipherEncryption = TWStoredKeyEncryptionAes192Ctr}}, + {TWStoredKeyEncryptionAes256Ctr, Keystore::AESParameters{.mKeyLength = Keystore::A256, .mCipher = Keystore::gAes256Ctr, .mCipherEncryption = TWStoredKeyEncryptionAes256Ctr}} +}; +} // namespace + +namespace TW::Keystore { + namespace CodingKeys { static const auto iv = "iv"; } // namespace CodingKeys /// Initializes `AESParameters` with a JSON object. -AESParameters::AESParameters(const nlohmann::json& json) { - iv = parse_hex(json[CodingKeys::iv].get()); +AESParameters AESParameters::AESParametersFromJson(const nlohmann::json& json, const std::string& cipher) { + auto parameters = AESParameters::AESParametersFromEncryption(getCipher(cipher)); + parameters.iv = parse_hex(json[CodingKeys::iv].get()); + return parameters; } /// Saves `this` as a JSON object. @@ -35,4 +59,11 @@ nlohmann::json AESParameters::json() const { return j; } +AESParameters AESParameters::AESParametersFromEncryption(TWStoredKeyEncryption encryption) { + auto parameters = gEncryptionRegistry.at(encryption); + // be sure to regenerate an iv. + parameters.iv = generateIv(); + return parameters; +} + } // namespace TW::Keystore diff --git a/src/Keystore/AESParameters.h b/src/Keystore/AESParameters.h index edae9ab9b4f..878700782ee 100644 --- a/src/Keystore/AESParameters.h +++ b/src/Keystore/AESParameters.h @@ -9,20 +9,37 @@ #include "Data.h" #include +#include namespace TW::Keystore { -// AES128 parameters. -struct AESParameters { - static const std::size_t blockSize = 128 / 8; +enum AESKeySize : std::int32_t { + Uninitialized = 0, + A128 = 16, + A192 = 24, + A256 = 32, +}; +inline constexpr std::size_t gBlockSize{16}; +inline constexpr const char* gAes128Ctr{"aes-128-ctr"}; +inline constexpr const char* gAes128Cbc{"aes-128-cbc"}; +inline constexpr const char* gAes192Ctr{"aes-192-ctr"}; +inline constexpr const char* gAes256Ctr{"aes-256-ctr"}; + +// AES128/192/256 parameters. +struct AESParameters { + // For AES, your block length is always going to be 128 bits/16 bytes + std::int32_t mBlockSize{gBlockSize}; + std::int32_t mKeyLength{A128}; + std::string mCipher{gAes128Ctr}; + TWStoredKeyEncryption mCipherEncryption{TWStoredKeyEncryptionAes128Ctr}; Data iv; - /// Initializes `AESParameters` with a random `iv` for AES 128. - AESParameters(); + /// Initializes `AESParameters` with a encryption cipher. + static AESParameters AESParametersFromEncryption(TWStoredKeyEncryption encryption);; /// Initializes `AESParameters` with a JSON object. - AESParameters(const nlohmann::json& json); + static AESParameters AESParametersFromJson(const nlohmann::json& json, const std::string& cipher); /// Saves `this` as a JSON object. nlohmann::json json() const; diff --git a/src/Keystore/EncryptionParameters.cpp b/src/Keystore/EncryptionParameters.cpp index ad7e6ecf348..9ea7a4fa6d1 100644 --- a/src/Keystore/EncryptionParameters.cpp +++ b/src/Keystore/EncryptionParameters.cpp @@ -40,8 +40,8 @@ static const auto mac = "mac"; } // namespace CodingKeys EncryptionParameters::EncryptionParameters(const nlohmann::json& json) { - cipher = json[CodingKeys::cipher].get(); - cipherParams = AESParameters(json[CodingKeys::cipherParams]); + auto cipher = json[CodingKeys::cipher].get(); + cipherParams = AESParameters::AESParametersFromJson(json[CodingKeys::cipherParams], cipher); auto kdf = json[CodingKeys::kdf].get(); if (kdf == "scrypt") { @@ -53,7 +53,7 @@ EncryptionParameters::EncryptionParameters(const nlohmann::json& json) { nlohmann::json EncryptionParameters::json() const { nlohmann::json j; - j[CodingKeys::cipher] = cipher; + j[CodingKeys::cipher] = cipher(); j[CodingKeys::cipherParams] = cipherParams.json(); if (auto* scryptParams = std::get_if(&kdfParams); scryptParams) { @@ -76,14 +76,25 @@ EncryptedPayload::EncryptedPayload(const Data& password, const Data& data, const scryptParams.desiredKeyLength); aes_encrypt_ctx ctx; - auto result = aes_encrypt_key128(derivedKey.data(), &ctx); + auto result = 0; + switch(this->params.cipherParams.mCipherEncryption) { + case TWStoredKeyEncryptionAes128Ctr: + case TWStoredKeyEncryptionAes128Cbc: + result = aes_encrypt_key128(derivedKey.data(), &ctx); + break; + case TWStoredKeyEncryptionAes192Ctr: + result = aes_encrypt_key192(derivedKey.data(), &ctx); + break; + case TWStoredKeyEncryptionAes256Ctr: + result = aes_encrypt_key256(derivedKey.data(), &ctx); + break; + } assert(result == EXIT_SUCCESS); if (result == EXIT_SUCCESS) { Data iv = this->params.cipherParams.iv; encrypted = Data(data.size()); aes_ctr_encrypt(data.data(), encrypted.data(), static_cast(data.size()), iv.data(), aes_ctr_cbuf_inc, &ctx); - - _mac = computeMAC(derivedKey.end() - 16, derivedKey.end(), encrypted); + _mac = computeMAC(derivedKey.end() - params.getKeyBytesSize(), derivedKey.end(), encrypted); } } @@ -101,13 +112,13 @@ Data EncryptedPayload::decrypt(const Data& password) const { scrypt(password.data(), password.size(), scryptParams->salt.data(), scryptParams->salt.size(), scryptParams->n, scryptParams->r, scryptParams->p, derivedKey.data(), scryptParams->defaultDesiredKeyLength); - mac = computeMAC(derivedKey.end() - 16, derivedKey.end(), encrypted); + mac = computeMAC(derivedKey.end() - params.getKeyBytesSize(), derivedKey.end(), encrypted); } else if (auto* pbkdf2Params = std::get_if(¶ms.kdfParams); pbkdf2Params) { derivedKey.resize(pbkdf2Params->defaultDesiredKeyLength); pbkdf2_hmac_sha256(password.data(), static_cast(password.size()), pbkdf2Params->salt.data(), static_cast(pbkdf2Params->salt.size()), pbkdf2Params->iterations, derivedKey.data(), pbkdf2Params->defaultDesiredKeyLength); - mac = computeMAC(derivedKey.end() - 16, derivedKey.end(), encrypted); + mac = computeMAC(derivedKey.end() - params.getKeyBytesSize(), derivedKey.end(), encrypted); } else { throw DecryptionError::unsupportedKDF; } @@ -118,20 +129,21 @@ Data EncryptedPayload::decrypt(const Data& password) const { Data decrypted(encrypted.size()); Data iv = params.cipherParams.iv; - if (params.cipher == "aes-128-ctr") { + const auto encryption = params.cipherParams.mCipherEncryption; + if (encryption == TWStoredKeyEncryptionAes128Ctr || encryption == TWStoredKeyEncryptionAes256Ctr) { aes_encrypt_ctx ctx; - auto __attribute__((unused)) result = aes_encrypt_key(derivedKey.data(), 16, &ctx); + [[maybe_unused]] auto result = aes_encrypt_key(derivedKey.data(), params.getKeyBytesSize(), &ctx); assert(result != EXIT_FAILURE); aes_ctr_decrypt(encrypted.data(), decrypted.data(), static_cast(encrypted.size()), iv.data(), aes_ctr_cbuf_inc, &ctx); - } else if (params.cipher == "aes-128-cbc") { + } else if (encryption == TWStoredKeyEncryptionAes128Cbc) { aes_decrypt_ctx ctx; - auto __attribute__((unused)) result = aes_decrypt_key(derivedKey.data(), 16, &ctx); + [[maybe_unused]] auto result = aes_decrypt_key(derivedKey.data(), params.getKeyBytesSize(), &ctx); assert(result != EXIT_FAILURE); - for (auto i = 0ul; i < encrypted.size(); i += 16) { - aes_cbc_decrypt(encrypted.data() + i, decrypted.data() + i, 16, iv.data(), &ctx); + for (auto i = 0ul; i < encrypted.size(); i += params.getKeyBytesSize()) { + aes_cbc_decrypt(encrypted.data() + i, decrypted.data() + i, params.getKeyBytesSize(), iv.data(), &ctx); } } else { throw DecryptionError::unsupportedCipher; diff --git a/src/Keystore/EncryptionParameters.h b/src/Keystore/EncryptionParameters.h index 6592b9756cd..a3e3ac59750 100644 --- a/src/Keystore/EncryptionParameters.h +++ b/src/Keystore/EncryptionParameters.h @@ -7,34 +7,40 @@ #pragma once #include "AESParameters.h" +#include "Data.h" #include "PBKDF2Parameters.h" #include "ScryptParameters.h" -#include "Data.h" +#include #include -#include #include #include +#include namespace TW::Keystore { /// Set of parameters used when encoding struct EncryptionParameters { - static EncryptionParameters getPreset(enum TWStoredKeyEncryptionLevel preset) { + static EncryptionParameters getPreset(enum TWStoredKeyEncryptionLevel preset, enum TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr) { switch (preset) { - case TWStoredKeyEncryptionLevelMinimal: - return EncryptionParameters(AESParameters(), ScryptParameters::Minimal); - case TWStoredKeyEncryptionLevelWeak: - case TWStoredKeyEncryptionLevelDefault: - default: - return EncryptionParameters(AESParameters(), ScryptParameters::Weak); - case TWStoredKeyEncryptionLevelStandard: - return EncryptionParameters(AESParameters(), ScryptParameters::Standard); + case TWStoredKeyEncryptionLevelMinimal: + return EncryptionParameters(AESParameters::AESParametersFromEncryption(encryption), ScryptParameters::Minimal); + case TWStoredKeyEncryptionLevelWeak: + case TWStoredKeyEncryptionLevelDefault: + default: + return EncryptionParameters(AESParameters::AESParametersFromEncryption(encryption), ScryptParameters::Weak); + case TWStoredKeyEncryptionLevelStandard: + return EncryptionParameters(AESParameters::AESParametersFromEncryption(encryption), ScryptParameters::Standard); } } - /// Cipher algorithm. - std::string cipher = "aes-128-ctr"; + std::int32_t getKeyBytesSize() const noexcept { + return cipherParams.mKeyLength; + } + + std::string cipher() const noexcept { + return cipherParams.mCipher; + } /// Cipher parameters. AESParameters cipherParams = AESParameters(); @@ -46,8 +52,8 @@ struct EncryptionParameters { /// Initializes with standard values. EncryptionParameters(AESParameters cipherParams, std::variant kdfParams) - : cipherParams(std::move(cipherParams)) - , kdfParams(std::move(kdfParams)) {} + : cipherParams(std::move(cipherParams)), kdfParams(std::move(kdfParams)) { + } /// Initializes with a JSON object. EncryptionParameters(const nlohmann::json& json); diff --git a/src/Keystore/StoredKey.cpp b/src/Keystore/StoredKey.cpp index add26c2ca26..9b761186ce4 100644 --- a/src/Keystore/StoredKey.cpp +++ b/src/Keystore/StoredKey.cpp @@ -26,41 +26,41 @@ using namespace TW; namespace TW::Keystore { -StoredKey StoredKey::createWithMnemonic(const std::string& name, const Data& password, const std::string& mnemonic, TWStoredKeyEncryptionLevel encryptionLevel) { +StoredKey StoredKey::createWithMnemonic(const std::string& name, const Data& password, const std::string& mnemonic, TWStoredKeyEncryptionLevel encryptionLevel, TWStoredKeyEncryption encryption) { if (!Mnemonic::isValid(mnemonic)) { throw std::invalid_argument("Invalid mnemonic"); } Data mnemonicData = TW::Data(mnemonic.begin(), mnemonic.end()); - return StoredKey(StoredKeyType::mnemonicPhrase, name, password, mnemonicData, encryptionLevel); + return StoredKey(StoredKeyType::mnemonicPhrase, name, password, mnemonicData, encryptionLevel, encryption); } -StoredKey StoredKey::createWithMnemonicRandom(const std::string& name, const Data& password, TWStoredKeyEncryptionLevel encryptionLevel) { +StoredKey StoredKey::createWithMnemonicRandom(const std::string& name, const Data& password, TWStoredKeyEncryptionLevel encryptionLevel, TWStoredKeyEncryption encryption) { const auto wallet = TW::HDWallet(128, ""); const auto& mnemonic = wallet.getMnemonic(); assert(Mnemonic::isValid(mnemonic)); Data mnemonicData = TW::Data(mnemonic.begin(), mnemonic.end()); - return StoredKey(StoredKeyType::mnemonicPhrase, name, password, mnemonicData, encryptionLevel); + return StoredKey(StoredKeyType::mnemonicPhrase, name, password, mnemonicData, encryptionLevel, encryption); } -StoredKey StoredKey::createWithMnemonicAddDefaultAddress(const std::string& name, const Data& password, const std::string& mnemonic, TWCoinType coin) { - StoredKey key = createWithMnemonic(name, password, mnemonic, TWStoredKeyEncryptionLevelDefault); +StoredKey StoredKey::createWithMnemonicAddDefaultAddress(const std::string& name, const Data& password, const std::string& mnemonic, TWCoinType coin, TWStoredKeyEncryption encryption) { + StoredKey key = createWithMnemonic(name, password, mnemonic, TWStoredKeyEncryptionLevelDefault, encryption); const auto wallet = key.wallet(password); key.account(coin, &wallet); return key; } -StoredKey StoredKey::createWithPrivateKey(const std::string& name, const Data& password, const Data& privateKeyData) { - return StoredKey(StoredKeyType::privateKey, name, password, privateKeyData, TWStoredKeyEncryptionLevelDefault); +StoredKey StoredKey::createWithPrivateKey(const std::string& name, const Data& password, const Data& privateKeyData, TWStoredKeyEncryption encryption) { + return StoredKey(StoredKeyType::privateKey, name, password, privateKeyData, TWStoredKeyEncryptionLevelDefault, encryption); } -StoredKey StoredKey::createWithPrivateKeyAddDefaultAddress(const std::string& name, const Data& password, TWCoinType coin, const Data& privateKeyData) { +StoredKey StoredKey::createWithPrivateKeyAddDefaultAddress(const std::string& name, const Data& password, TWCoinType coin, const Data& privateKeyData, TWStoredKeyEncryption encryption) { const auto curve = TW::curve(coin); if (!PrivateKey::isValid(privateKeyData, curve)) { throw std::invalid_argument("Invalid private key data"); } - StoredKey key = createWithPrivateKey(name, password, privateKeyData); + StoredKey key = createWithPrivateKey(name, password, privateKeyData, encryption); const auto derivationPath = TW::derivationPath(coin); const auto pubKeyType = TW::publicKeyType(coin); const auto pubKey = PrivateKey(privateKeyData).getPublicKey(pubKeyType); @@ -69,9 +69,9 @@ StoredKey StoredKey::createWithPrivateKeyAddDefaultAddress(const std::string& na return key; } -StoredKey::StoredKey(StoredKeyType type, std::string name, const Data& password, const Data& data, TWStoredKeyEncryptionLevel encryptionLevel) +StoredKey::StoredKey(StoredKeyType type, std::string name, const Data& password, const Data& data, TWStoredKeyEncryptionLevel encryptionLevel, TWStoredKeyEncryption encryption) : type(type), id(), name(std::move(name)), accounts() { - const auto encryptionParams = EncryptionParameters::getPreset(encryptionLevel); + const auto encryptionParams = EncryptionParameters::getPreset(encryptionLevel, encryption); payload = EncryptedPayload(password, data, encryptionParams); boost::uuids::random_generator gen; id = boost::lexical_cast(gen()); diff --git a/src/Keystore/StoredKey.h b/src/Keystore/StoredKey.h index 96d3010064b..58a5dca3f77 100644 --- a/src/Keystore/StoredKey.h +++ b/src/Keystore/StoredKey.h @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -45,23 +46,23 @@ class StoredKey { /// Create a new StoredKey, with the given name, mnemonic and password. /// @throws std::invalid_argument if mnemonic is invalid - static StoredKey createWithMnemonic(const std::string& name, const Data& password, const std::string& mnemonic, TWStoredKeyEncryptionLevel encryptionLevel); + static StoredKey createWithMnemonic(const std::string& name, const Data& password, const std::string& mnemonic, TWStoredKeyEncryptionLevel encryptionLevel, TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr); /// Create a new StoredKey, with the given name, mnemonic and password. /// @throws std::invalid_argument if mnemonic is invalid - static StoredKey createWithMnemonicRandom(const std::string& name, const Data& password, TWStoredKeyEncryptionLevel encryptionLevel); + static StoredKey createWithMnemonicRandom(const std::string& name, const Data& password, TWStoredKeyEncryptionLevel encryptionLevel, TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr); /// Create a new StoredKey, with the given name, mnemonic and password, and also add the default address for the given coin.. /// @throws std::invalid_argument if mnemonic is invalid - static StoredKey createWithMnemonicAddDefaultAddress(const std::string& name, const Data& password, const std::string& mnemonic, TWCoinType coin); + static StoredKey createWithMnemonicAddDefaultAddress(const std::string& name, const Data& password, const std::string& mnemonic, TWCoinType coin, TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr); /// Create a new StoredKey, with the given name and private key. /// @throws std::invalid_argument if privateKeyData is not a valid private key - static StoredKey createWithPrivateKey(const std::string& name, const Data& password, const Data& privateKeyData); + static StoredKey createWithPrivateKey(const std::string& name, const Data& password, const Data& privateKeyData, TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr); /// Create a new StoredKey, with the given name and private key, and also add the default address for the given coin.. /// @throws std::invalid_argument if privateKeyData is not a valid private key - static StoredKey createWithPrivateKeyAddDefaultAddress(const std::string& name, const Data& password, TWCoinType coin, const Data& privateKeyData); + static StoredKey createWithPrivateKeyAddDefaultAddress(const std::string& name, const Data& password, TWCoinType coin, const Data& privateKeyData, TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr); /// Create a StoredKey from a JSON object. static StoredKey createWithJson(const nlohmann::json& json); @@ -152,7 +153,7 @@ class StoredKey { /// Initializes a `StoredKey` with a type, an encryption password, and unencrypted data. /// This constructor will encrypt the provided data with default encryption /// parameters. - StoredKey(StoredKeyType type, std::string name, const Data& password, const Data& data, TWStoredKeyEncryptionLevel encryptionLevel); + StoredKey(StoredKeyType type, std::string name, const Data& password, const Data& data, TWStoredKeyEncryptionLevel encryptionLevel, TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr); /// Find default account for coin, if exists. If multiple exist, default is returned. /// Optional wallet is needed to derive default address diff --git a/src/interface/TWStoredKey.cpp b/src/interface/TWStoredKey.cpp index bccd49a9a03..d07378fb9e4 100644 --- a/src/interface/TWStoredKey.cpp +++ b/src/interface/TWStoredKey.cpp @@ -25,33 +25,50 @@ struct TWStoredKey* _Nullable TWStoredKeyLoad(TWString* _Nonnull path) { } } -struct TWStoredKey* _Nonnull TWStoredKeyCreateLevel(TWString* _Nonnull name, TWData* _Nonnull password, enum TWStoredKeyEncryptionLevel encryptionLevel) { +struct TWStoredKey* _Nonnull TWStoredKeyCreateLevelAndEncryption(TWString* _Nonnull name, TWData* _Nonnull password, enum TWStoredKeyEncryptionLevel encryptionLevel, enum TWStoredKeyEncryption encryption) { const auto& nameString = *reinterpret_cast(name); const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password)); - return new TWStoredKey{ KeyStore::StoredKey::createWithMnemonicRandom(nameString, passwordData, encryptionLevel) }; + return new TWStoredKey{ KeyStore::StoredKey::createWithMnemonicRandom(nameString, passwordData, encryptionLevel, encryption) }; +} + +struct TWStoredKey* _Nonnull TWStoredKeyCreateLevel(TWString* _Nonnull name, TWData* _Nonnull password, enum TWStoredKeyEncryptionLevel encryptionLevel) { + return TWStoredKeyCreateLevelAndEncryption(name, password, encryptionLevel, TWStoredKeyEncryptionAes128Ctr); +} + +struct TWStoredKey* _Nonnull TWStoredKeyCreateEncryption(TWString* _Nonnull name, TWData* _Nonnull password, enum TWStoredKeyEncryption encryption) { + return TWStoredKeyCreateLevelAndEncryption(name, password, TWStoredKeyEncryptionLevelDefault, encryption); } struct TWStoredKey* _Nonnull TWStoredKeyCreate(TWString* _Nonnull name, TWData* _Nonnull password) { - return TWStoredKeyCreateLevel(name, password, TWStoredKeyEncryptionLevelDefault); + return TWStoredKeyCreateLevelAndEncryption(name, password, TWStoredKeyEncryptionLevelDefault, TWStoredKeyEncryptionAes128Ctr); } struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKey(TWData* _Nonnull privateKey, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin) { + return TWStoredKeyImportPrivateKeyWithEncryption(privateKey, name, password, coin, TWStoredKeyEncryptionAes128Ctr); +} + +struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKeyWithEncryption(TWData* _Nonnull privateKey, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin, enum TWStoredKeyEncryption encryption) { try { const auto& privateKeyData = *reinterpret_cast(privateKey); const auto& nameString = *reinterpret_cast(name); const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password)); - return new TWStoredKey{ KeyStore::StoredKey::createWithPrivateKeyAddDefaultAddress(nameString, passwordData, coin, privateKeyData) }; + return new TWStoredKey{ KeyStore::StoredKey::createWithPrivateKeyAddDefaultAddress(nameString, passwordData, coin, privateKeyData, encryption) }; } catch (...) { return nullptr; } } struct TWStoredKey* _Nullable TWStoredKeyImportHDWallet(TWString* _Nonnull mnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin) { + return TWStoredKeyImportHDWalletWithEncryption(mnemonic, name, password, coin, TWStoredKeyEncryptionAes128Ctr); +} + + +struct TWStoredKey* _Nullable TWStoredKeyImportHDWalletWithEncryption(TWString* _Nonnull mnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin, enum TWStoredKeyEncryption encryption) { try { const auto& mnemonicString = *reinterpret_cast(mnemonic); const auto& nameString = *reinterpret_cast(name); const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password)); - return new TWStoredKey{ KeyStore::StoredKey::createWithMnemonicAddDefaultAddress(nameString, passwordData, mnemonicString, coin) }; + return new TWStoredKey{ KeyStore::StoredKey::createWithMnemonicAddDefaultAddress(nameString, passwordData, mnemonicString, coin, encryption) }; } catch (...) { return nullptr; } diff --git a/swift/Sources/KeyStore.swift b/swift/Sources/KeyStore.swift index 815843c87de..0b6c3368d77 100644 --- a/swift/Sources/KeyStore.swift +++ b/swift/Sources/KeyStore.swift @@ -74,8 +74,8 @@ public final class KeyStore { } /// Creates a new wallet. HD default by default - public func createWallet(name: String, password: String, coins: [CoinType]) throws -> Wallet { - let key = StoredKey(name: name, password: Data(password.utf8)) + public func createWallet(name: String, password: String, coins: [CoinType], encryption: StoredKeyEncryption = .aes128Ctr) throws -> Wallet { + let key = StoredKey(name: name, password: Data(password.utf8), encryption: encryption) return try saveCreatedWallet(for: key, password: password, coins: coins) } @@ -158,8 +158,8 @@ public final class KeyStore { /// - password: password to use for the imported private key /// - coin: coin to use for this wallet /// - Returns: new wallet - public func `import`(privateKey: PrivateKey, name: String, password: String, coin: CoinType) throws -> Wallet { - guard let newKey = StoredKey.importPrivateKey(privateKey: privateKey.data, name: name, password: Data(password.utf8), coin: coin) else { + public func `import`(privateKey: PrivateKey, name: String, password: String, coin: CoinType, encryption: StoredKeyEncryption = .aes128Ctr) throws -> Wallet { + guard let newKey = StoredKey.importPrivateKeyWithEncryption(privateKey: privateKey.data, name: name, password: Data(password.utf8), coin: coin, encryption: encryption) else { throw Error.invalidKey } let url = makeAccountURL() @@ -179,8 +179,8 @@ public final class KeyStore { /// - encryptPassword: password to use for encrypting /// - coins: coins to add /// - Returns: new account - public func `import`(mnemonic: String, name: String, encryptPassword: String, coins: [CoinType]) throws -> Wallet { - guard let key = StoredKey.importHDWallet(mnemonic: mnemonic, name: name, password: Data(encryptPassword.utf8), coin: coins.first ?? .ethereum) else { + public func `import`(mnemonic: String, name: String, encryptPassword: String, coins: [CoinType], encryption: StoredKeyEncryption = .aes128Ctr) throws -> Wallet { + guard let key = StoredKey.importHDWalletWithEncryption(mnemonic: mnemonic, name: name, password: Data(encryptPassword.utf8), coin: coins.first ?? .ethereum, encryption: encryption) else { throw Error.invalidMnemonic } let url = makeAccountURL() @@ -201,7 +201,7 @@ public final class KeyStore { /// - password: account password /// - newPassword: password to use for exported key /// - Returns: encrypted JSON key - public func export(wallet: Wallet, password: String, newPassword: String) throws -> Data { + public func export(wallet: Wallet, password: String, newPassword: String, encryption: StoredKeyEncryption = .aes128Ctr) throws -> Data { var privateKeyData = try exportPrivateKey(wallet: wallet, password: password) defer { privateKeyData.resetBytes(in: 0 ..< privateKeyData.count) @@ -211,12 +211,12 @@ public final class KeyStore { throw Error.accountNotFound } - if let mnemonic = checkMnemonic(privateKeyData), let newKey = StoredKey.importHDWallet(mnemonic: mnemonic, name: "", password: Data(newPassword.utf8), coin: coin) { + if let mnemonic = checkMnemonic(privateKeyData), let newKey = StoredKey.importHDWalletWithEncryption(mnemonic: mnemonic, name: "", password: Data(newPassword.utf8), coin: coin, encryption: encryption) { guard let json = newKey.exportJSON() else { throw Error.invalidKey } return json - } else if let newKey = StoredKey.importPrivateKey(privateKey: privateKeyData, name: "", password: Data(newPassword.utf8), coin: coin) { + } else if let newKey = StoredKey.importPrivateKeyWithEncryption(privateKey: privateKeyData, name: "", password: Data(newPassword.utf8), coin: coin, encryption: encryption) { guard let json = newKey.exportJSON() else { throw Error.invalidKey } @@ -269,11 +269,11 @@ public final class KeyStore { /// - wallet: wallet to update /// - password: current password /// - newName: new name - public func update(wallet: Wallet, password: String, newName: String) throws { - try update(wallet: wallet, password: password, newPassword: password, newName: newName) + public func update(wallet: Wallet, password: String, newName: String, encryption: StoredKeyEncryption = .aes128Ctr) throws { + try update(wallet: wallet, password: password, newPassword: password, newName: newName, encryption: encryption) } - private func update(wallet: Wallet, password: String, newPassword: String, newName: String) throws { + private func update(wallet: Wallet, password: String, newPassword: String, newName: String, encryption: StoredKeyEncryption = .aes128Ctr) throws { guard let index = wallets.firstIndex(of: wallet) else { fatalError("Missing wallet") } @@ -291,10 +291,10 @@ public final class KeyStore { } if let mnemonic = checkMnemonic(privateKeyData), - let key = StoredKey.importHDWallet(mnemonic: mnemonic, name: newName, password: Data(newPassword.utf8), coin: coins[0]) { + let key = StoredKey.importHDWalletWithEncryption(mnemonic: mnemonic, name: newName, password: Data(newPassword.utf8), coin: coins[0], encryption: encryption) { wallets[index].key = key - } else if let key = StoredKey.importPrivateKey( - privateKey: privateKeyData, name: newName, password: Data(newPassword.utf8), coin: coins[0]) { + } else if let key = StoredKey.importPrivateKeyWithEncryption( + privateKey: privateKeyData, name: newName, password: Data(newPassword.utf8), coin: coins[0], encryption: encryption) { wallets[index].key = key } else { throw Error.invalidKey diff --git a/swift/Tests/Keystore/KeyStoreTests.swift b/swift/Tests/Keystore/KeyStoreTests.swift index 3ae5529e79e..62d907ccfaf 100755 --- a/swift/Tests/Keystore/KeyStoreTests.swift +++ b/swift/Tests/Keystore/KeyStoreTests.swift @@ -183,6 +183,20 @@ class KeyStoreTests: XCTestCase { XCTAssertNotNil(storedData) XCTAssertNotNil(PrivateKey(data: storedData!)) } + + func testImportPrivateKeyAES256() throws { + let keyStore = try KeyStore(keyDirectory: keyDirectory) + let privateKeyData = Data(hexString: "9cdb5cab19aec3bd0fcd614c5f185e7a1d97634d4225730eba22497dc89a716c")! + let key = StoredKey.importPrivateKeyWithEncryption(privateKey: privateKeyData, name: "name", password: Data("password".utf8), coin: .ethereum, encryption: StoredKeyEncryption.aes256Ctr)! + let json = key.exportJSON()! + + let wallet = try keyStore.import(json: json, name: "name", password: "password", newPassword: "newPassword", coins: [.ethereum]) + let storedData = wallet.key.decryptPrivateKey(password: Data("newPassword".utf8)) + + XCTAssertNotNil(keyStore.keyWallet) + XCTAssertNotNil(storedData) + XCTAssertNotNil(PrivateKey(data: storedData!)) + } func testImportPrivateKey() throws { let keyStore = try KeyStore(keyDirectory: keyDirectory) @@ -208,6 +222,16 @@ class KeyStoreTests: XCTestCase { XCTAssertEqual(wallet.accounts.count, 1) XCTAssertNotNil(keyStore.hdWallet) } + + func testImportWalletAES256() throws { + let keyStore = try KeyStore(keyDirectory: keyDirectory) + let wallet = try keyStore.import(mnemonic: mnemonic, name: "name", encryptPassword: "newPassword", coins: [.ethereum], encryption: .aes256Ctr) + let storedData = wallet.key.decryptMnemonic(password: Data("newPassword".utf8)) + + XCTAssertNotNil(storedData) + XCTAssertEqual(wallet.accounts.count, 1) + XCTAssertNotNil(keyStore.hdWallet) + } func testImportJSON() throws { diff --git a/tests/chains/XRP/TWAnySignerTests.cpp b/tests/chains/XRP/TWAnySignerTests.cpp index 47fcbd9d232..184c8a21137 100644 --- a/tests/chains/XRP/TWAnySignerTests.cpp +++ b/tests/chains/XRP/TWAnySignerTests.cpp @@ -84,25 +84,20 @@ TEST(TWAnySignerRipple, SignTrustSetPayment) { TEST(TWAnySignerRipple, SignTokenPayment0) { // https://testnet.xrpl.org/transactions/8F7820892294598B58CFA2E1101D15ED98C179B25A2BA6DAEB4F5B727CB00D4E - for (auto value : std::vector({"10", "10e0", "10.0", "10.0e0", "1e1", ".1e2", "0.1e2", "100e-1", "10000000000000000e-15", "0.0000000000000001e17"})) { - auto key = parse_hex("4ba5fd2ebf0f5d7e579b3c354c263ebb39cda4093845125786a280301af14e21"); - Proto::SigningInput input; - - input.mutable_op_payment()->mutable_currency_amount()->set_currency("USD"); - input.mutable_op_payment()->mutable_currency_amount()->set_value("10"); - input.mutable_op_payment()->mutable_currency_amount()->set_issuer("rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"); - input.set_fee(10); - input.set_sequence(32268645); - input.set_last_ledger_sequence(32268666); - input.set_account("raPAA61ca99bdwNiZs5JJukR5rvkHWvkBX"); - input.mutable_op_payment()->set_destination("rU893viamSnsfP3zjzM2KPxjqZjXSXK6VF"); - input.set_private_key(key.data(), key.size()); - - Proto::SigningOutput output; - ANY_SIGN(input, TWCoinTypeXRP); - - EXPECT_EQ(hex(output.encoded()), "12000022000000002401ec6165201b01ec617a61d4c38d7ea4c6800000000000000000000000000055534400000000004b4e9c06f24296074f7bc48f92a97916c6dc5ea968400000000000000a7321020652a477b0cca8b74d6e68a6a386a836b226101617481b95180eaffbe841b3227446304402203e925caeb05006afb135254e9ae4e46de2019db6c6f68614ef969885063a777602206af110fc29775256fcad8b14974c6a838141d82193192d3b57324fe1079afa1781143b2fa4f36553e5b7a4f54ff9e6883e44b4b0dbb383148132e4e20aecf29090ac428a9c43f230a829220d"); - } + auto key = parse_hex("4ba5fd2ebf0f5d7e579b3c354c263ebb39cda4093845125786a280301af14e21"); + Proto::SigningInput input; + input.mutable_op_payment()->mutable_currency_amount()->set_currency("USD"); + input.mutable_op_payment()->mutable_currency_amount()->set_value("10"); + input.mutable_op_payment()->mutable_currency_amount()->set_issuer("rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"); + input.set_fee(10); + input.set_sequence(32268645); + input.set_last_ledger_sequence(32268666); + input.set_account("raPAA61ca99bdwNiZs5JJukR5rvkHWvkBX"); + input.mutable_op_payment()->set_destination("rU893viamSnsfP3zjzM2KPxjqZjXSXK6VF"); + input.set_private_key(key.data(), key.size()); + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeXRP); + EXPECT_EQ(hex(output.encoded()), "12000022000000002401ec6165201b01ec617a61d4c38d7ea4c6800000000000000000000000000055534400000000004b4e9c06f24296074f7bc48f92a97916c6dc5ea968400000000000000a7321020652a477b0cca8b74d6e68a6a386a836b226101617481b95180eaffbe841b3227446304402203e925caeb05006afb135254e9ae4e46de2019db6c6f68614ef969885063a777602206af110fc29775256fcad8b14974c6a838141d82193192d3b57324fe1079afa1781143b2fa4f36553e5b7a4f54ff9e6883e44b4b0dbb383148132e4e20aecf29090ac428a9c43f230a829220d"); } TEST(TWAnySignerRipple, SignTokenPayment1) { diff --git a/tests/common/Keystore/StoredKeyTests.cpp b/tests/common/Keystore/StoredKeyTests.cpp index 51cc959968d..677ce21a0e2 100644 --- a/tests/common/Keystore/StoredKeyTests.cpp +++ b/tests/common/Keystore/StoredKeyTests.cpp @@ -84,6 +84,22 @@ TEST(StoredKey, CreateWithMnemonicAddDefaultAddress) { EXPECT_EQ(hex(key.privateKey(coinTypeBc, gPassword).bytes), "d2568511baea8dc347f14c4e0479eb8ebe29eb5f664ed796e755896250ffd11f"); } +TEST(StoredKey, CreateWithMnemonicAddDefaultAddressAes256) { + auto key = StoredKey::createWithMnemonicAddDefaultAddress("name", gPassword, gMnemonic, coinTypeBc, TWStoredKeyEncryptionAes256Ctr); + EXPECT_EQ(key.type, StoredKeyType::mnemonicPhrase); + auto header = key.payload; + EXPECT_EQ(header.params.cipher(), "aes-256-ctr"); + const Data& mnemo2Data = key.payload.decrypt(gPassword); + + EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(gMnemonic)); + EXPECT_EQ(key.accounts.size(), 1ul); + EXPECT_EQ(key.accounts[0].coin, coinTypeBc); + EXPECT_EQ(key.accounts[0].address, "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"); + EXPECT_EQ(key.accounts[0].publicKey, "02df6fc590ab3101bbe0bb5765cbaeab9b5dcfe09ac9315d707047cbd13bc7e006"); + EXPECT_EQ(key.accounts[0].extendedPublicKey, "zpub6qbsWdbcKW9sC6shTKK4VEhfWvDCoWpfLnnVfYKHLHt31wKYUwH3aFDz4WLjZvjHZ5W4qVEyk37cRwzTbfrrT1Gnu8SgXawASnkdQ994atn"); + EXPECT_EQ(hex(key.privateKey(coinTypeBc, gPassword).bytes), "d2568511baea8dc347f14c4e0479eb8ebe29eb5f664ed796e755896250ffd11f"); +} + TEST(StoredKey, CreateWithPrivateKeyAddDefaultAddress) { const auto privateKey = parse_hex("3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"); auto key = StoredKey::createWithPrivateKeyAddDefaultAddress("name", gPassword, coinTypeBc, privateKey); @@ -99,6 +115,23 @@ TEST(StoredKey, CreateWithPrivateKeyAddDefaultAddress) { EXPECT_EQ(json["version"], 3); } +TEST(StoredKey, CreateWithPrivateKeyAddDefaultAddressAes256) { + const auto privateKey = parse_hex("3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"); + auto key = StoredKey::createWithPrivateKeyAddDefaultAddress("name", gPassword, coinTypeBc, privateKey, TWStoredKeyEncryptionAes256Ctr); + auto header = key.payload; + EXPECT_EQ(header.params.cipher(), "aes-256-ctr"); + EXPECT_EQ(key.type, StoredKeyType::privateKey); + EXPECT_EQ(key.accounts.size(), 1ul); + EXPECT_EQ(key.accounts[0].coin, coinTypeBc); + EXPECT_EQ(key.accounts[0].address, "bc1q375sq4kl2nv0mlmup3vm8znn4eqwu7mt6hkwhr"); + EXPECT_EQ(hex(key.privateKey(coinTypeBc, gPassword).bytes), hex(privateKey)); + + const auto json = key.json(); + EXPECT_EQ(json["name"], "name"); + EXPECT_EQ(json["type"], "private-key"); + EXPECT_EQ(json["version"], 3); +} + TEST(StoredKey, CreateWithPrivateKeyAddDefaultAddressInvalid) { try { const auto privateKeyInvalid = parse_hex("0001020304"); @@ -345,7 +378,7 @@ TEST(StoredKey, ReadWallet) { const auto header = key.payload; - EXPECT_EQ(header.params.cipher, "aes-128-ctr"); + EXPECT_EQ(header.params.cipher(), "aes-128-ctr"); EXPECT_EQ(hex(header.encrypted), "d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c"); EXPECT_EQ(hex(header._mac), "2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097"); EXPECT_EQ(hex(header.params.cipherParams.iv), "83dbcc02d8ccb40e466191a123791e0e"); @@ -403,6 +436,22 @@ TEST(StoredKey, CreateAccounts) { EXPECT_EQ(key.account(coinTypeBc, &wallet)->extendedPublicKey, "zpub6qbsWdbcKW9sC6shTKK4VEhfWvDCoWpfLnnVfYKHLHt31wKYUwH3aFDz4WLjZvjHZ5W4qVEyk37cRwzTbfrrT1Gnu8SgXawASnkdQ994atn"); } +TEST(StoredKey, CreateAccountsAes256) { + string mnemonicPhrase = "team engine square letter hero song dizzy scrub tornado fabric divert saddle"; + auto key = StoredKey::createWithMnemonic("name", gPassword, mnemonicPhrase, TWStoredKeyEncryptionLevelDefault, TWStoredKeyEncryptionAes256Ctr); + auto header = key.payload; + const auto wallet = key.wallet(gPassword); + + EXPECT_EQ(header.params.cipher(), "aes-256-ctr"); + EXPECT_EQ(key.account(TWCoinTypeEthereum, &wallet)->address, "0x494f60cb6Ac2c8F5E1393aD9FdBdF4Ad589507F7"); + EXPECT_EQ(key.account(TWCoinTypeEthereum, &wallet)->publicKey, "04cc32a479080d83fdcf69966713f0aad1bc1dc3ecf873b034894e84259841bc1c9b122717803e68905220ff54952d3f5ea2ab2698ca31f843addf94ae73fae9fd"); + EXPECT_EQ(key.account(TWCoinTypeEthereum, &wallet)->extendedPublicKey, ""); + + EXPECT_EQ(key.account(coinTypeBc, &wallet)->address, "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"); + EXPECT_EQ(key.account(coinTypeBc, &wallet)->publicKey, "02df6fc590ab3101bbe0bb5765cbaeab9b5dcfe09ac9315d707047cbd13bc7e006"); + EXPECT_EQ(key.account(coinTypeBc, &wallet)->extendedPublicKey, "zpub6qbsWdbcKW9sC6shTKK4VEhfWvDCoWpfLnnVfYKHLHt31wKYUwH3aFDz4WLjZvjHZ5W4qVEyk37cRwzTbfrrT1Gnu8SgXawASnkdQ994atn"); +} + TEST(StoredKey, DecodingEthereumAddress) { const auto key = StoredKey::load(testDataPath("key.json")); diff --git a/tests/interface/TWStoredKeyTests.cpp b/tests/interface/TWStoredKeyTests.cpp index 6cfa96c04c8..99f2df1ab54 100644 --- a/tests/interface/TWStoredKeyTests.cpp +++ b/tests/interface/TWStoredKeyTests.cpp @@ -25,19 +25,19 @@ using namespace std; /// Return a StoredKey instance that can be used for further tests. Needs to be deleted at the end. -struct std::shared_ptr createAStoredKey(TWCoinType coin, TWData* password) { +struct std::shared_ptr createAStoredKey(TWCoinType coin, TWData* password, TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr) { const auto mnemonic = WRAPS(TWStringCreateWithUTF8Bytes("team engine square letter hero song dizzy scrub tornado fabric divert saddle")); const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name")); - const auto key = WRAP(TWStoredKey, TWStoredKeyImportHDWallet(mnemonic.get(), name.get(), password, coin)); + const auto key = WRAP(TWStoredKey, TWStoredKeyImportHDWalletWithEncryption(mnemonic.get(), name.get(), password, coin, encryption)); return key; } /// Return a StoredKey instance that can be used for further tests. Needs to be deleted at the end. -struct std::shared_ptr createDefaultStoredKey() { +struct std::shared_ptr createDefaultStoredKey(TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr) { const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); - return createAStoredKey(TWCoinTypeBitcoin, password.get()); + return createAStoredKey(TWCoinTypeBitcoin, password.get(), encryption); } TEST(TWStoredKey, loadPBKDF2Key) { @@ -57,7 +57,7 @@ TEST(TWStoredKey, createWallet) { const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name")); const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); - const auto key = WRAP(TWStoredKey, TWStoredKeyCreateLevel(name.get(), password.get(), TWStoredKeyEncryptionLevelDefault)); + const auto key = WRAP(TWStoredKey, TWStoredKeyCreateLevelAndEncryption(name.get(), password.get(), TWStoredKeyEncryptionLevelDefault, TWStoredKeyEncryptionAes128Ctr)); const auto name2 = WRAPS(TWStoredKeyName(key.get())); EXPECT_EQ(string(TWStringUTF8Bytes(name2.get())), "name"); const auto mnemonic = WRAPS(TWStoredKeyDecryptMnemonic(key.get(), password.get())); @@ -82,6 +82,23 @@ TEST(TWStoredKey, importPrivateKey) { TWPrivateKeyDelete(privateKey3); } +TEST(TWStoredKey, importPrivateKeyAes256) { + const auto privateKeyHex = "3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"; + const auto privateKey = WRAPD(TWDataCreateWithHexString(WRAPS(TWStringCreateWithUTF8Bytes(privateKeyHex)).get())); + const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name")); + const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); + const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); + const auto coin = TWCoinTypeBitcoin; + const auto key = WRAP(TWStoredKey, TWStoredKeyImportPrivateKeyWithEncryption(privateKey.get(), name.get(), password.get(), coin, TWStoredKeyEncryptionAes256Ctr)); + const auto privateKey2 = WRAPD(TWStoredKeyDecryptPrivateKey(key.get(), password.get())); + EXPECT_EQ(hex(data(TWDataBytes(privateKey2.get()), TWDataSize(privateKey2.get()))), privateKeyHex); + + const auto privateKey3 = TWStoredKeyPrivateKey(key.get(), coin, password.get()); + const auto pkData3 = WRAPD(TWPrivateKeyData(privateKey3)); + EXPECT_EQ(hex(data(TWDataBytes(pkData3.get()), TWDataSize(pkData3.get()))), privateKeyHex); + TWPrivateKeyDelete(privateKey3); +} + TEST(TWStoredKey, importHDWallet) { const auto mnemonic = WRAPS(TWStringCreateWithUTF8Bytes("team engine square letter hero song dizzy scrub tornado fabric divert saddle")); const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name")); @@ -97,6 +114,21 @@ TEST(TWStoredKey, importHDWallet) { EXPECT_EQ(nokey.get(), nullptr); } +TEST(TWStoredKey, importHDWalletAES256) { + const auto mnemonic = WRAPS(TWStringCreateWithUTF8Bytes("team engine square letter hero song dizzy scrub tornado fabric divert saddle")); + const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name")); + const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); + const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); + const auto coin = TWCoinTypeBitcoin; + const auto key = WRAP(TWStoredKey, TWStoredKeyImportHDWalletWithEncryption(mnemonic.get(), name.get(), password.get(), coin, TWStoredKeyEncryptionAes256Ctr)); + EXPECT_TRUE(TWStoredKeyIsMnemonic(key.get())); + + // invalid mnemonic + const auto mnemonicInvalid = WRAPS(TWStringCreateWithUTF8Bytes("_THIS_IS_AN_INVALID_MNEMONIC_")); + const auto nokey = WRAP(TWStoredKey, TWStoredKeyImportHDWalletWithEncryption(mnemonicInvalid.get(), name.get(), password.get(), coin, TWStoredKeyEncryptionAes256Ctr)); + EXPECT_EQ(nokey.get(), nullptr); +} + TEST(TWStoredKey, addressAddRemove) { const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); @@ -184,6 +216,30 @@ TEST(TWStoredKey, exportJSON) { EXPECT_EQ(TWDataGet(json.get(), 0), '{'); } +TEST(TWStoredKey, storeAndImportJSONAES256) { + const auto key = createDefaultStoredKey(TWStoredKeyEncryptionAes256Ctr); + const auto outFileName = string(getTestTempDir() + "/TWStoredKey_store.json"); + const auto outFileNameStr = WRAPS(TWStringCreateWithUTF8Bytes(outFileName.c_str())); + EXPECT_TRUE(TWStoredKeyStore(key.get(), outFileNameStr.get())); + + // read contents of file + ifstream ifs(outFileName); + // get length of file: + ifs.seekg (0, ifs.end); + auto length = ifs.tellg(); + ifs.seekg (0, ifs.beg); + EXPECT_TRUE(length > 20); + + Data json(length); + size_t idx = 0; + // read the slow way, ifs.read gave some false warnings with codacy + while (!ifs.eof() && idx < static_cast(length)) { char c = ifs.get(); json[idx++] = (uint8_t)c; } + + const auto key2 = WRAP(TWStoredKey, TWStoredKeyImportJSON(WRAPD(TWDataCreateWithData(&json)).get())); + const auto name2 = WRAPS(TWStoredKeyName(key2.get())); + EXPECT_EQ(string(TWStringUTF8Bytes(name2.get())), "name"); +} + TEST(TWStoredKey, storeAndImportJSON) { const auto key = createDefaultStoredKey(); const auto outFileName = string(getTestTempDir() + "/TWStoredKey_store.json"); diff --git a/wasm/src/keystore/default-impl.ts b/wasm/src/keystore/default-impl.ts index 91da9b40f16..528b63e5554 100644 --- a/wasm/src/keystore/default-impl.ts +++ b/wasm/src/keystore/default-impl.ts @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -import { WalletCore, CoinType, PrivateKey, StoredKey } from "../wallet-core"; +import {WalletCore, CoinType, PrivateKey, StoredKey, StoredKeyEncryption} from "../wallet-core"; import * as Types from "./types"; export class Default implements Types.IKeyStore { @@ -53,16 +53,17 @@ export class Default implements Types.IKeyStore { mnemonic: string, name: string, password: string, - coins: CoinType[] + coins: CoinType[], + encryption: StoredKeyEncryption ): Promise { return new Promise((resolve, reject) => { - const { Mnemonic, StoredKey, HDWallet } = this.core; + const { Mnemonic, StoredKey, HDWallet, StoredKeyEncryption } = this.core; if (!Mnemonic.isValid(mnemonic)) { throw Types.Error.InvalidMnemonic; } let pass = Buffer.from(password); - let storedKey = StoredKey.importHDWallet(mnemonic, name, pass, coins[0]); + let storedKey = StoredKey.importHDWalletWithEncryption(mnemonic, name, pass, coins[0], encryption); let hdWallet = HDWallet.createWithMnemonic(mnemonic, ""); coins.forEach((coin) => { storedKey.accountForCoin(coin, hdWallet); @@ -82,10 +83,11 @@ export class Default implements Types.IKeyStore { key: Uint8Array, name: string, password: string, - coin: CoinType + coin: CoinType, + encryption: StoredKeyEncryption ): Promise { return new Promise((resolve, reject) => { - const { StoredKey, PrivateKey, Curve } = this.core; + const { StoredKey, PrivateKey, Curve, StoredKeyEncryption } = this.core; // FIXME: get curve from coin if ( @@ -95,7 +97,7 @@ export class Default implements Types.IKeyStore { throw Types.Error.InvalidKey; } let pass = Buffer.from(password); - let storedKey = StoredKey.importPrivateKey(key, name, pass, coin); + let storedKey = StoredKey.importPrivateKeyWithEncryption(key, name, pass, coin, encryption); let wallet = this.mapWallet(storedKey); storedKey.delete(); this.importWallet(wallet) diff --git a/wasm/src/keystore/types.ts b/wasm/src/keystore/types.ts index cc0ce8a21fd..aea0ee3b4ae 100644 --- a/wasm/src/keystore/types.ts +++ b/wasm/src/keystore/types.ts @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -import { CoinType, PrivateKey } from "../wallet-core"; +import { CoinType, PrivateKey, StoredKeyEncryption } from "../wallet-core"; export enum WalletType { Mnemonic = "mnemonic", @@ -54,7 +54,8 @@ export interface IKeyStore { mnemonic: string, name: string, password: string, - coins: CoinType[] + coins: CoinType[], + encryption: StoredKeyEncryption ): Promise; // Import a wallet by private key, name and password @@ -62,7 +63,8 @@ export interface IKeyStore { key: Uint8Array, name: string, password: string, - coin: CoinType + coin: CoinType, + encryption: StoredKeyEncryption ): Promise; // Import a Wallet object directly diff --git a/wasm/tests/KeyStore+extension.test.ts b/wasm/tests/KeyStore+extension.test.ts index fe22c5b7091..cf876dcc448 100644 --- a/wasm/tests/KeyStore+extension.test.ts +++ b/wasm/tests/KeyStore+extension.test.ts @@ -11,7 +11,7 @@ import { ChromeStorageMock } from "./mock"; describe("KeyStore", async () => { it("test ExtensionStorage", async () => { - const { CoinType, HexCoding } = globalThis.core; + const { CoinType, HexCoding, StoredKeyEncryption } = globalThis.core; const mnemonic = globalThis.mnemonic as string; const password = globalThis.password as string; @@ -24,7 +24,7 @@ describe("KeyStore", async () => { var wallet = await keystore.import(mnemonic, "Coolw", password, [ CoinType.bitcoin, - ]); + ], StoredKeyEncryption.aes128Ctr); assert.equal(wallet.name, "Coolw"); assert.equal(wallet.type, "mnemonic"); @@ -65,4 +65,60 @@ describe("KeyStore", async () => { keystore.delete(w.id, password); }); }).timeout(10000); + + it("test ExtensionStorage AES256", async () => { + const { CoinType, HexCoding, StoredKeyEncryption } = globalThis.core; + const mnemonic = globalThis.mnemonic as string; + const password = globalThis.password as string; + + const walletIdsKey = "all-wallet-ids"; + const storage = new KeyStore.ExtensionStorage( + walletIdsKey, + new ChromeStorageMock() + ); + const keystore = new KeyStore.Default(globalThis.core, storage); + + var wallet = await keystore.import(mnemonic, "Coolw", password, [ + CoinType.bitcoin, + ], StoredKeyEncryption.aes256Ctr); + + assert.equal(wallet.name, "Coolw"); + assert.equal(wallet.type, "mnemonic"); + assert.equal(wallet.version, 3); + + const account = wallet.activeAccounts[0]; + const key = await keystore.getKey(wallet.id, password, account); + + assert.equal( + HexCoding.encode(key.data()), + "0xd2568511baea8dc347f14c4e0479eb8ebe29eb5f664ed796e755896250ffd11f" + ); + assert.equal(account.address, "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"); + assert.equal( + account.extendedPublicKey, + "zpub6qbsWdbcKW9sC6shTKK4VEhfWvDCoWpfLnnVfYKHLHt31wKYUwH3aFDz4WLjZvjHZ5W4qVEyk37cRwzTbfrrT1Gnu8SgXawASnkdQ994atn" + ); + assert.equal( + account.publicKey, + "02df6fc590ab3101bbe0bb5765cbaeab9b5dcfe09ac9315d707047cbd13bc7e006" + ); + + wallet = await keystore.addAccounts(wallet.id, password, [ + CoinType.ethereum, + CoinType.binance, + ]); + + assert.equal(wallet.activeAccounts.length, 3); + assert.isTrue(await keystore.hasWallet(wallet.id)); + assert.isFalse(await keystore.hasWallet("invalid-id")); + + const exported = await keystore.export(wallet.id, password); + assert.equal(exported, mnemonic); + + const wallets = await keystore.loadAll(); + + await wallets.forEach((w) => { + keystore.delete(w.id, password); + }); + }).timeout(10000); }); diff --git a/wasm/tests/KeyStore+fs.test.ts b/wasm/tests/KeyStore+fs.test.ts index 743a9a8e4b4..cdadb92940a 100644 --- a/wasm/tests/KeyStore+fs.test.ts +++ b/wasm/tests/KeyStore+fs.test.ts @@ -11,7 +11,7 @@ import { KeyStore } from "../dist"; describe("KeyStore", async () => { it("test FileSystemStorage", async () => { - const { CoinType, HexCoding } = globalThis.core; + const { CoinType, HexCoding, StoredKeyEncryption } = globalThis.core; const mnemonic = globalThis.mnemonic as string; const password = globalThis.password as string; const testDir = "/tmp/wasm-test"; @@ -23,7 +23,7 @@ describe("KeyStore", async () => { var wallet = await keystore.import(mnemonic, "Coolw", password, [ CoinType.bitcoin, - ]); + ], StoredKeyEncryption.aes128Ctr); const stats = fs.statSync(storage.getFilename(wallet.id)); assert.isTrue(stats.isFile()); @@ -67,4 +67,62 @@ describe("KeyStore", async () => { keystore.delete(w.id, password); }); }).timeout(10000); + + it("test FileSystemStorage AES256", async () => { + const { CoinType, HexCoding, StoredKeyEncryption } = globalThis.core; + const mnemonic = globalThis.mnemonic as string; + const password = globalThis.password as string; + const testDir = "/tmp/wasm-test"; + + fs.mkdirSync(testDir, { recursive: true }); + + const storage = new KeyStore.FileSystemStorage(testDir); + const keystore = new KeyStore.Default(globalThis.core, storage); + + var wallet = await keystore.import(mnemonic, "Coolw", password, [ + CoinType.bitcoin, + ], StoredKeyEncryption.aes256Ctr); + const stats = fs.statSync(storage.getFilename(wallet.id)); + + assert.isTrue(stats.isFile()); + assert.isTrue(stats.size > 0); + assert.equal(wallet.name, "Coolw"); + assert.equal(wallet.type, "mnemonic"); + assert.equal(wallet.version, 3); + + const account = wallet.activeAccounts[0]; + const key = await keystore.getKey(wallet.id, password, account); + + assert.equal( + HexCoding.encode(key.data()), + "0xd2568511baea8dc347f14c4e0479eb8ebe29eb5f664ed796e755896250ffd11f" + ); + assert.equal(account.address, "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny"); + assert.equal( + account.extendedPublicKey, + "zpub6qbsWdbcKW9sC6shTKK4VEhfWvDCoWpfLnnVfYKHLHt31wKYUwH3aFDz4WLjZvjHZ5W4qVEyk37cRwzTbfrrT1Gnu8SgXawASnkdQ994atn" + ); + assert.equal( + account.publicKey, + "02df6fc590ab3101bbe0bb5765cbaeab9b5dcfe09ac9315d707047cbd13bc7e006" + ); + + wallet = await keystore.addAccounts(wallet.id, password, [ + CoinType.ethereum, + CoinType.binance, + ]); + + assert.equal(wallet.activeAccounts.length, 3); + assert.isTrue(await keystore.hasWallet(wallet.id)); + assert.isFalse(await keystore.hasWallet("invalid-id")); + + const exported = await keystore.export(wallet.id, password); + assert.equal(exported, mnemonic); + + const wallets = await keystore.loadAll(); + + await wallets.forEach((w) => { + keystore.delete(w.id, password); + }); + }).timeout(10000); }); From d3c2eee16b154cbb69e8959b01e5e71fbabb1212 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 21 Nov 2022 16:16:14 +0100 Subject: [PATCH 142/497] [emscripten]: use javascript for random generation (#2750) * feat(wasm): use javascript for random generation * feat(wasm): fix per review * add link to libsodium --- wasm/src/Random.cpp | 76 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/wasm/src/Random.cpp b/wasm/src/Random.cpp index d0ea0b2557f..81b5674c4af 100644 --- a/wasm/src/Random.cpp +++ b/wasm/src/Random.cpp @@ -5,20 +5,84 @@ // file LICENSE at the root of the source code distribution tree. // -#include #include #include -#include +#include + +// clang-format off +static uint32_t +javascript_random(void) +{ + return EM_ASM_INT_V({ + return Module.getRandomValue(); + }); +} + +// https://github.com/jedisct1/libsodium/blob/master/src/libsodium/randombytes/randombytes.c#L53 +static void +javascript_stir(void) +{ + EM_ASM({ + if (Module.getRandomValue === undefined) { + try { + var window_ = 'object' === typeof window ? window : self; + var crypto_ = typeof window_.crypto !== 'undefined' ? window_.crypto : window_.msCrypto; + var randomValuesStandard = function() { + var buf = new Uint32Array(1); + crypto_.getRandomValues(buf); + return buf[0] >>> 0; + }; + randomValuesStandard(); + Module.getRandomValue = randomValuesStandard; + } catch (e) { + try { + var crypto = require('crypto'); + var randomValueNodeJS = function() { + var buf = crypto['randomBytes'](4); + return (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]) >>> 0; + }; + randomValueNodeJS(); + Module.getRandomValue = randomValueNodeJS; + } catch (e) { + throw 'No secure random number generator found'; + } + } + } + }); +} + + +static void +randombytes_init_if_needed(void) +{ + static bool initialized = false; + if (!initialized) { + javascript_stir(); + initialized = true; + } +} + +static void +javascript_buf(void * const buf, const size_t size) +{ + unsigned char *p = (unsigned char *) buf; + size_t i; + + for (i = (size_t) 0U; i < size; i++) { + p[i] = (unsigned char) javascript_random(); + } +} +// clang-format on extern "C" { uint32_t random32(void) { - std::mt19937 rng(std::random_device{}()); - return rng(); + randombytes_init_if_needed(); + return javascript_random(); } void random_buffer(uint8_t* buf, size_t len) { - std::mt19937 rng(std::random_device{}()); - std::generate_n(buf, len, [&rng]() -> uint8_t { return rng() & 0x000000ff; }); + randombytes_init_if_needed(); + javascript_buf(buf, len); return; } From c61e8663a2cb98aa645fc7d54e28a26d5e60a9ae Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Tue, 22 Nov 2022 14:59:39 +0100 Subject: [PATCH 143/497] [Bitcoin Op_Return/ThorSwap] Proper handling for len 76-80 bytes in two chunks (#2753) --- src/Bitcoin/OpCodes.h | 1 + src/Bitcoin/Script.cpp | 30 ++++++++++++++++----- src/Bitcoin/Script.h | 6 +++++ tests/chains/Bitcoin/BitcoinScriptTests.cpp | 24 +++++++++++++++++ tests/chains/THORChain/SwapTests.cpp | 6 ++--- 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/Bitcoin/OpCodes.h b/src/Bitcoin/OpCodes.h index fa797be4b19..dd68248bf1d 100644 --- a/src/Bitcoin/OpCodes.h +++ b/src/Bitcoin/OpCodes.h @@ -10,6 +10,7 @@ enum OpCode { // push value OP_0 = 0x00, OP_FALSE [[maybe_unused]] = OP_0, + // Note: values 0x01 -- 0x4b (1--75) mean that the next N bytes are interpreted as data pushed into the stack OP_PUSHDATA1 = 0x4c, OP_PUSHDATA2 = 0x4d, OP_PUSHDATA4 = 0x4e, diff --git a/src/Bitcoin/Script.cpp b/src/Bitcoin/Script.cpp index 7c8b8da75f4..ac8e7a0b4c7 100644 --- a/src/Bitcoin/Script.cpp +++ b/src/Bitcoin/Script.cpp @@ -228,11 +228,18 @@ Script Script::buildPayToScriptHash(const Data& scriptHash) { return script; } +// Append to the buffer the length for the upcoming data (push). Supported length range: 0-75 bytes +void pushDataLength(Data& buffer, byte len) { + // Caller contexts make sure len is in the range, not returning error from here + assert(len <= Script::MaxDataPushLength); + buffer.push_back(len); +} + Script Script::buildPayToV0WitnessProgram(const Data& program) { assert(program.size() == 20 || program.size() == 32); Script script; script.bytes.push_back(OP_0); - script.bytes.push_back(static_cast(program.size())); + pushDataLength(script.bytes, static_cast(program.size())); append(script.bytes, program); assert(script.bytes.size() == 22 || script.bytes.size() == 34); return script; @@ -252,23 +259,34 @@ Script Script::buildPayToV1WitnessProgram(const Data& publicKey) { assert(publicKey.size() == 32); Script script; script.bytes.push_back(OP_1); - script.bytes.push_back(static_cast(publicKey.size())); + pushDataLength(script.bytes, static_cast(publicKey.size())); append(script.bytes, publicKey); assert(script.bytes.size() == 34); return script; } Script Script::buildOpReturnScript(const Data& data) { - static const size_t MaxOpReturnLength = 80; if (data.size() > MaxOpReturnLength) { // data too long, cannot fit, fail (do not truncate) - return Script(); + return {}; } assert(data.size() <= MaxOpReturnLength); Script script; script.bytes.push_back(OP_RETURN); - script.bytes.push_back(static_cast(data.size())); - script.bytes.insert(script.bytes.end(), data.begin(), data.begin() + data.size()); + if (data.size() <= MaxDataPushLength) { + // can fit in one push + pushDataLength(script.bytes, static_cast(data.size())); + script.bytes.insert(script.bytes.end(), data.begin(), data.begin() + data.size()); + } else { + // This is the special case of 76-80 bytes, must be put in two data pushes. Use 75 bytes for the first, rest for the 2nd. + const byte push1len = MaxDataPushLength; + const byte push2len = static_cast(data.size()) - push1len; + pushDataLength(script.bytes, push1len); + script.bytes.insert(script.bytes.end(), data.begin(), data.begin() + push1len); + pushDataLength(script.bytes, push2len); + script.bytes.insert(script.bytes.end(), data.begin() + push1len, data.begin() + push1len + push2len); + } + assert(script.bytes.size() <= 83); // max script length, must always hold return script; } diff --git a/src/Bitcoin/Script.h b/src/Bitcoin/Script.h index f4c27c32517..05f973b1020 100644 --- a/src/Bitcoin/Script.h +++ b/src/Bitcoin/Script.h @@ -20,6 +20,12 @@ namespace TW::Bitcoin { class Script { public: + // Maximum length of data constant in one push + static const size_t MaxDataPushLength = 75; + + // Maximum length for OP_RETURN data + static const size_t MaxOpReturnLength = 80; + /// Script raw bytes. Data bytes; diff --git a/tests/chains/Bitcoin/BitcoinScriptTests.cpp b/tests/chains/Bitcoin/BitcoinScriptTests.cpp index 0bdc3d92768..210bd4d4ae7 100644 --- a/tests/chains/Bitcoin/BitcoinScriptTests.cpp +++ b/tests/chains/Bitcoin/BitcoinScriptTests.cpp @@ -306,19 +306,43 @@ TEST(BitcoinScript, OpReturn) { { Data data = parse_hex("00010203"); Script script = Script::buildOpReturnScript(data); + EXPECT_EQ(script.bytes.size(), 2 + data.size()); EXPECT_EQ(hex(script.bytes), "6a0400010203"); } { Data data = parse_hex("535741503a54484f522e52554e453a74686f72317470657263616d6b6b7865633071306a6b366c74646e6c7176737732396775617038776d636c3a"); Script script = Script::buildOpReturnScript(data); + EXPECT_EQ(script.bytes.size(), 2 + data.size()); EXPECT_EQ(hex(script.bytes), "6a3b535741503a54484f522e52554e453a74686f72317470657263616d6b6b7865633071306a6b366c74646e6c7176737732396775617038776d636c3a"); } { Data data = Data(69); data.push_back(0xab); Script script = Script::buildOpReturnScript(data); + EXPECT_EQ(script.bytes.size(), 2 + data.size()); EXPECT_EQ(hex(script.bytes), "6a46000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab"); } + { + Data data = Data(74); + data.push_back(0xab); + Script script = Script::buildOpReturnScript(data); + EXPECT_EQ(script.bytes.size(), 2 + data.size()); + EXPECT_EQ(hex(script.bytes), + "6a4b" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab"); + } + { + // >75 bytes, in 2 data pushes + Data data = Data(79); + data.push_back(0xab); + Script script = Script::buildOpReturnScript(data); + EXPECT_EQ(script.bytes.size(), 3 + data.size()); // 1 more byte for the extra data push + EXPECT_EQ(hex(script.bytes), + "6a4b" + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "05" + "00000000ab"); + } } TEST(BitcoinScript, OpReturnTooLong) { diff --git a/tests/chains/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp index 1f2e5fc5a37..2ca87ecbe1f 100644 --- a/tests/chains/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -408,11 +408,11 @@ TEST(THORChainSwap, SwapBtcEthWithAffFee) { "1234000000000000000000000000000000000000000000000000000000005678" "00000000" "00" "" "ffffffff" "03" // outputs "40420f0000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" - "209ceb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" - "0000000000000000" "52" "6a503d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7468726e6d3a3130" + "0c9ceb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" + "0000000000000000" "53" "6a4b3d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a746872056e6d3a3130" // witness "02" - "48" "3045022100801dc46b14eb1b630050d48db27557b66254c3b9439909d864747eafbb12f7e902201fdf5433eaf4968a5596989330bc56513b5769c5c9fd77c41f9bdb55cf8202cd01" + "48" "3045022100ded612f58466e3f5b3d489befef16204750d9a225cca43ffe1808a7dc76bdcd70220750876c848d706a130408f4340449412408843b9b29acf208b6303af6228979501" "21" "021e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" "00000000" // nLockTime ); From d9f73cb4eff52858eb5f78d23e1007cf6f191f16 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Wed, 23 Nov 2022 11:19:43 +0100 Subject: [PATCH 144/497] Bitcoin Op_Return/ThorSwap: Proper handling for len 76-80 bytes with OP_PUSHDATA1 (#2757) Bitcoin Op_Return: Proper handling for len 76-80 bytes with OP_PUSHDATA1 --- src/Bitcoin/Script.cpp | 29 +++++++++------------ src/Bitcoin/Script.h | 3 --- tests/chains/Bitcoin/BitcoinScriptTests.cpp | 15 ++++++----- tests/chains/THORChain/SwapTests.cpp | 4 +-- 4 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/Bitcoin/Script.cpp b/src/Bitcoin/Script.cpp index ac8e7a0b4c7..fcd8f383268 100644 --- a/src/Bitcoin/Script.cpp +++ b/src/Bitcoin/Script.cpp @@ -229,10 +229,16 @@ Script Script::buildPayToScriptHash(const Data& scriptHash) { } // Append to the buffer the length for the upcoming data (push). Supported length range: 0-75 bytes -void pushDataLength(Data& buffer, byte len) { - // Caller contexts make sure len is in the range, not returning error from here - assert(len <= Script::MaxDataPushLength); - buffer.push_back(len); +void pushDataLength(Data& buffer, size_t len) { + assert(len <= 255); + if (len < static_cast(OP_PUSHDATA1)) { + // up to 75 bytes, simple OP_PUSHBYTES with len + buffer.push_back(static_cast(len)); + return; + } + // 75 < len < 256, OP_PUSHDATA with 1-byte len + buffer.push_back(OP_PUSHDATA1); + buffer.push_back(static_cast(len)); } Script Script::buildPayToV0WitnessProgram(const Data& program) { @@ -273,19 +279,8 @@ Script Script::buildOpReturnScript(const Data& data) { assert(data.size() <= MaxOpReturnLength); Script script; script.bytes.push_back(OP_RETURN); - if (data.size() <= MaxDataPushLength) { - // can fit in one push - pushDataLength(script.bytes, static_cast(data.size())); - script.bytes.insert(script.bytes.end(), data.begin(), data.begin() + data.size()); - } else { - // This is the special case of 76-80 bytes, must be put in two data pushes. Use 75 bytes for the first, rest for the 2nd. - const byte push1len = MaxDataPushLength; - const byte push2len = static_cast(data.size()) - push1len; - pushDataLength(script.bytes, push1len); - script.bytes.insert(script.bytes.end(), data.begin(), data.begin() + push1len); - pushDataLength(script.bytes, push2len); - script.bytes.insert(script.bytes.end(), data.begin() + push1len, data.begin() + push1len + push2len); - } + pushDataLength(script.bytes, data.size()); + script.bytes.insert(script.bytes.end(), data.begin(), data.begin() + data.size()); assert(script.bytes.size() <= 83); // max script length, must always hold return script; } diff --git a/src/Bitcoin/Script.h b/src/Bitcoin/Script.h index 05f973b1020..6befe4f79b1 100644 --- a/src/Bitcoin/Script.h +++ b/src/Bitcoin/Script.h @@ -20,9 +20,6 @@ namespace TW::Bitcoin { class Script { public: - // Maximum length of data constant in one push - static const size_t MaxDataPushLength = 75; - // Maximum length for OP_RETURN data static const size_t MaxOpReturnLength = 80; diff --git a/tests/chains/Bitcoin/BitcoinScriptTests.cpp b/tests/chains/Bitcoin/BitcoinScriptTests.cpp index 210bd4d4ae7..599a0ea44b8 100644 --- a/tests/chains/Bitcoin/BitcoinScriptTests.cpp +++ b/tests/chains/Bitcoin/BitcoinScriptTests.cpp @@ -332,16 +332,19 @@ TEST(BitcoinScript, OpReturn) { "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab"); } { - // >75 bytes, in 2 data pushes + // >75 bytes, with OP_PUSHDATA1 Data data = Data(79); data.push_back(0xab); Script script = Script::buildOpReturnScript(data); - EXPECT_EQ(script.bytes.size(), 3 + data.size()); // 1 more byte for the extra data push + EXPECT_EQ(script.bytes.size(), 3 + data.size()); EXPECT_EQ(hex(script.bytes), - "6a4b" - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "05" - "00000000ab"); + "6a4c50" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab"); + } + { + // >80 bytes, fails + EXPECT_EQ(hex(Script::buildOpReturnScript(Data(81)).bytes), ""); + EXPECT_EQ(hex(Script::buildOpReturnScript(Data(255)).bytes), ""); } } diff --git a/tests/chains/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp index 2ca87ecbe1f..12926d5f58a 100644 --- a/tests/chains/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -409,10 +409,10 @@ TEST(THORChainSwap, SwapBtcEthWithAffFee) { "03" // outputs "40420f0000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" "0c9ceb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" - "0000000000000000" "53" "6a4b3d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a746872056e6d3a3130" + "0000000000000000" "53" "6a4c503d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7468726e6d3a3130" // witness "02" - "48" "3045022100ded612f58466e3f5b3d489befef16204750d9a225cca43ffe1808a7dc76bdcd70220750876c848d706a130408f4340449412408843b9b29acf208b6303af6228979501" + "47" "3044022056e918d8dea9431057b7b8b7f7c990ff72d653aef296eda9a85e546537e1eaa4022050b64766ea4ce56ecd3325f184d67b20924fd4539cb40bbad916ede1cc26017f01" "21" "021e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" "00000000" // nLockTime ); From a9970744f3df5296f4e4837942ef27b858317a94 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 24 Nov 2022 13:29:04 +0100 Subject: [PATCH 145/497] [ThorSwap]: Memo shortened + bep2 tokens support (#2754) --- .../thorchain/TestTHORSwapSigning.kt | 8 +- src/THORChain/Swap.cpp | 288 +++++---- src/THORChain/Swap.h | 132 +++- src/THORChain/TWSwap.cpp | 36 +- src/proto/THORChainSwap.proto | 2 +- .../Blockchains/THORChainSwapTests.swift | 18 +- tests/chains/THORChain/SwapTests.cpp | 563 +++++++++++++----- tests/chains/THORChain/TWSwapTests.cpp | 24 +- 8 files changed, 704 insertions(+), 367 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt index e65151148a7..fcc0dd64986 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt @@ -24,7 +24,9 @@ class TestTHORChainSwap { // prepare swap input val input = THORChainSwap.SwapInput.newBuilder() input.apply { - fromChain = THORChainSwap.Chain.ETH + fromAsset = THORChainSwap.Asset.newBuilder().apply { + chain = THORChainSwap.Chain.ETH + }.build() fromAddress = "0xb9f5771c27664bf2282d98e09d7f50cec7cb01a7" toAsset = THORChainSwap.Asset.newBuilder().apply { chain = THORChainSwap.Chain.BNB @@ -42,7 +44,7 @@ class TestTHORChainSwap { // serialize input val inputSerialized = input.build().toByteArray() - assertEquals(Numeric.toHexString(inputSerialized), "0x0802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a11353030303030303030303030303030303042063630303030334a2f7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c327463717952023130") + assertEquals(Numeric.toHexString(inputSerialized), "0x0a020802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a11353030303030303030303030303030303042063630303030334a2f7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c327463717952023130") // invoke swap val outputData = buildSwap(inputSerialized) @@ -68,6 +70,6 @@ class TestTHORChainSwap { // sign and encode resulting input val output = AnySigner.sign(txInputFull, ETHEREUM, SigningOutput.parser()) - assertEquals(Numeric.toHexString(output.encoded.toByteArray()), "0xf90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000071535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000026a027da86e94739f39e8b493f240eb043888a0dd6962a657963ff7fb26f10291ca8a03fed75d6703d5036402be4d0197432725e17fe6a5d3059abdcca74bd7a789cc8") + assertEquals(Numeric.toHexString(output.encoded.toByteArray()), "0xf90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000000000026a0ee68bd41da9a9b1ad87fd547e83e4b8022460de024839f4f5f528abc6aecf2aea0402205812d62a075138743f6048ba2a1c073f4a3a14224009a34ee74d3dccef1") } } diff --git a/src/THORChain/Swap.cpp b/src/THORChain/Swap.cpp index b799b645023..3be886ab9a8 100644 --- a/src/THORChain/Swap.cpp +++ b/src/THORChain/Swap.cpp @@ -6,17 +6,17 @@ #include "Swap.h" -#include #include "Coin.h" -#include "proto/THORChainSwap.pb.h" +#include + // BTC #include "Bitcoin/SigHashType.h" #include "../proto/Bitcoin.pb.h" // ETH -#include "Ethereum/Address.h" #include "Ethereum/ABI/Function.h" -#include "Ethereum/ABI/ParamBase.h" #include "Ethereum/ABI/ParamAddress.h" +#include "Ethereum/ABI/ParamBase.h" +#include "Ethereum/Address.h" #include "uint256.h" #include "../proto/Ethereum.pb.h" // BNB @@ -32,117 +32,108 @@ namespace TW::THORChainSwap { +static Data ethAddressStringToData(const std::string& asString) { + Data asData(20); + if (asString.empty() || !Ethereum::Address::isValid(asString)) { + return asData; + } + auto address = Ethereum::Address(asString); + std::copy(address.bytes.begin(), address.bytes.end(), asData.data()); + return asData; +} + TWCoinType chainCoinType(Chain chain) { switch (chain) { - case Chain::ETH: return TWCoinTypeEthereum; - case Chain::BNB: return TWCoinTypeBinance; - case Chain::BTC: return TWCoinTypeBitcoin; - case Chain::THOR: - default: - return TWCoinTypeTHORChain; + case Chain::ETH: + return TWCoinTypeEthereum; + case Chain::BNB: + return TWCoinTypeBinance; + case Chain::BTC: + return TWCoinTypeBitcoin; + case Chain::THOR: + default: + return TWCoinTypeTHORChain; } } std::string chainName(Chain chain) { switch (chain) { - case Chain::ETH: return "ETH"; - case Chain::BNB: return "BNB"; - case Chain::BTC: return "BTC"; - case Chain::THOR: - default: - return "THOR"; + case Chain::ETH: + return "ETH"; + case Chain::BNB: + return "BNB"; + case Chain::BTC: + return "BTC"; + case Chain::THOR: + default: + return "THOR"; } } -std::string Swap::buildMemo(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& toAddress, uint64_t limit, const std::string& feeAddress, std::optional feeRate, const std::string& extra) { - std::string prefix = "SWAP"; - if (toChain == Chain::ETH) { - prefix = "="; - } - const auto toCoinToken = (!toTokenId.empty() && toTokenId != "0x0000000000000000000000000000000000000000") ? toTokenId : toSymbol; - std::stringstream memo; - memo << prefix + ":" + chainName(toChain) + "." + toCoinToken + ":" + toAddress + ":" + std::to_string(limit); - - if (!feeAddress.empty() || feeRate.has_value() || !extra.empty()) { - memo << ":"; - if (!feeAddress.empty()) { - memo << feeAddress; - } - if (feeRate.has_value() || !extra.empty()) { - memo << ":"; - if (feeRate.has_value()) { - memo << std::to_string(feeRate.value()); - } - if (!extra.empty()) { - memo << ":"; - memo << extra; - } - } - } - - return memo.str(); -} - bool validateAddress(Chain chain, const std::string& address) { return TW::validateAddress(chainCoinType(chain), address); } -std::tuple Swap::build( - Chain fromChain, - Chain toChain, - const std::string& fromAddress, - const std::string& toSymbol, - const std::string& toTokenId, - const std::string& toAddress, - const std::string& vaultAddress, - const std::string& routerAddress, - const std::string& fromAmount, - const std::string& toAmountLimit, - const std::string& affFeeAddress, - const std::string& affFeeRate, - const std::string& extraMemo -) { - if (!validateAddress(fromChain, fromAddress)) { - return std::make_tuple({}, static_cast(Proto::ErrorCode::Error_Invalid_from_address), "Invalid from address"); +SwapBundled SwapBuilder::build(bool shortened) { + auto fromChain = static_cast(mFromAsset.chain()); + auto toChain = static_cast(mToAsset.chain()); + + if (!validateAddress(fromChain, mFromAddress)) { + return {.status_code = static_cast(Proto::ErrorCode::Error_Invalid_from_address), .error = "Invalid from address"}; } - if (!validateAddress(toChain, toAddress)) { - return std::make_tuple({}, static_cast(Proto::ErrorCode::Error_Invalid_to_address), "Invalid to address"); + if (!validateAddress(toChain, mToAddress)) { + return {.status_code = static_cast(Proto::ErrorCode::Error_Invalid_to_address), .error = "Invalid to address"}; } - uint64_t fromAmountNum = std::atoll(fromAmount.c_str()); - uint64_t toAmountLimitNum = std::atoll(toAmountLimit.c_str()); - std::optional feeRateNum = affFeeRate.empty() ? std::nullopt : std::optional(std::atoll(affFeeRate.c_str())); - - const auto memo = buildMemo(toChain, toSymbol, toTokenId, toAddress, toAmountLimitNum, affFeeAddress, feeRateNum, extraMemo); + uint64_t fromAmountNum = std::stoull(mFromAmount); + const auto memo = this->buildMemo(shortened); switch (fromChain) { - case Chain::BTC: { - Data out; - auto res = buildBitcoin(toChain, toSymbol, toTokenId, fromAddress, toAddress, vaultAddress, fromAmountNum, memo, out); - return std::make_tuple(std::move(out), std::move(std::get<0>(res)), std::move(std::get<1>(res))); - } + case Chain::BTC: { + return buildBitcoin(fromAmountNum, memo); + case Chain::BNB: + return buildBinance(mFromAsset, fromAmountNum, memo); + case Chain::ETH: + return buildEth(fromAmountNum, memo); + } + default: + return {.status_code = static_cast(Proto::ErrorCode::Error_Unsupported_from_chain), .error = "Unsupported from chain: " + std::to_string(fromChain)}; + } +} +std::string SwapBuilder::buildMemo(bool shortened) noexcept { + uint64_t toAmountLimitNum = std::stoull(mToAmountLimit); + + // Memo: 'SWAP', or shortened '='; see https://dev.thorchain.org/thorchain-dev/concepts/memos + std::string prefix = shortened ? "=" : "SWAP"; + const auto& toChain = static_cast(mToAsset.chain()); + const auto& toTokenId = mToAsset.token_id(); + const auto& toSymbol = mToAsset.symbol(); + const auto toCoinToken = (!toTokenId.empty() && toTokenId != "0x0000000000000000000000000000000000000000") ? toTokenId : toSymbol; + std::stringstream memo; + memo << prefix + ":" + chainName(toChain) + "." + toCoinToken + ":" + mToAddress + ":" + std::to_string(toAmountLimitNum); - case Chain::ETH: { - Data out; - auto res = buildEthereum(toChain, toSymbol, toTokenId, fromAddress, toAddress, vaultAddress, routerAddress, fromAmountNum, memo, out); - return std::make_tuple(std::move(out), std::move(std::get<0>(res)), std::move(std::get<1>(res))); + if (mAffFeeAddress.has_value() || mAffFeeRate.has_value() || mExtraMemo.has_value()) { + memo << ":"; + if (mAffFeeAddress.has_value()) { + memo << mAffFeeAddress.value(); } - - case Chain::BNB: { - Data out; - auto res = buildBinance(toChain, toSymbol, toTokenId, fromAddress, toAddress, vaultAddress, fromAmountNum, memo, out); - return std::make_tuple(std::move(out), std::move(std::get<0>(res)), std::move(std::get<1>(res))); + if (mAffFeeRate.has_value() || mExtraMemo.has_value()) { + memo << ":"; + if (mAffFeeRate.has_value()) { + memo << mAffFeeRate.value(); + } + if (mExtraMemo.has_value()) { + memo << ":" << mExtraMemo.value(); + } } - - case Chain::THOR: - default: - return std::make_tuple({}, static_cast(Proto::ErrorCode::Error_Unsupported_from_chain), "Unsupported from chain: " + std::to_string(toChain)); } + + return memo.str(); } -std::pair Swap::buildBitcoin([[maybe_unused]] Chain toChain, [[maybe_unused]] const std::string& toSymbol, [[maybe_unused]] const std::string& toTokenId, const std::string& fromAddress, [[maybe_unused]] const std::string& toAddress, const std::string& vaultAddress, uint64_t amount, const std::string& memo, Data& out) { +SwapBundled SwapBuilder::buildBitcoin(uint64_t amount, const std::string& memo) { auto input = Bitcoin::Proto::SigningInput(); - + Data out; // Following fields must be set afterwards, before signing ... input.set_hash_type(TWBitcoinSigHashTypeAll); input.set_byte_fee(1); @@ -152,73 +143,19 @@ std::pair Swap::buildBitcoin([[maybe_unused]] Chain toChain, [ // scripts[] // ... end - input.set_amount(amount); - input.set_to_address(vaultAddress); - input.set_change_address(fromAddress); + input.set_amount(static_cast(amount)); + input.set_to_address(mVaultAddress); + input.set_change_address(mFromAddress); input.set_coin_type(TWCoinTypeBitcoin); input.set_output_op_return(memo); auto serialized = input.SerializeAsString(); out.insert(out.end(), serialized.begin(), serialized.end()); - return std::make_pair(0, ""); -} - -Data ethAddressStringToData(const std::string& asString) { - Data asData(20); - if (asString.empty() || !Ethereum::Address::isValid(asString)) { - return asData; - } - auto address = Ethereum::Address(asString); - std::copy(address.bytes.begin(), address.bytes.end(), asData.data()); - return asData; -} - -std::pair Swap::buildEthereum([[maybe_unused]] Chain toChain, [[maybe_unused]] const std::string& toSymbol, const std::string& toTokenId, [[maybe_unused]] const std::string& fromAddress, [[maybe_unused]] const std::string& toAddress, const std::string& vaultAddress, const std::string& routerAddress, uint64_t amount, const std::string& memo, Data& out) { - auto input = Ethereum::Proto::SigningInput(); - - // some sanity check / address conversion - Data vaultAddressBin = ethAddressStringToData(vaultAddress); - if (!Ethereum::Address::isValid(vaultAddress) || vaultAddressBin.size() != Ethereum::Address::size) { - return std::make_pair(static_cast(Proto::ErrorCode::Error_Invalid_vault_address), "Invalid vault address: " + vaultAddress); - } - if (!Ethereum::Address::isValid(routerAddress)) { - return std::make_pair(static_cast(Proto::ErrorCode::Error_Invalid_router_address), "Invalid router address: " + routerAddress); - } - Data toAssetAddressBin = ethAddressStringToData(toTokenId); - - // Following fields must be set afterwards, before signing ... - const auto chainId = store(uint256_t(0)); - input.set_chain_id(chainId.data(), chainId.size()); - const auto nonce = store(uint256_t(0)); - input.set_nonce(nonce.data(), nonce.size()); - const auto gasPrice = store(uint256_t(0)); - input.set_gas_price(gasPrice.data(), gasPrice.size()); - const auto gasLimit = store(uint256_t(0)); - input.set_gas_limit(gasLimit.data(), gasLimit.size()); - input.set_private_key(""); - // ... end - - input.set_to_address(routerAddress); - auto& transfer = *input.mutable_transaction()->mutable_contract_generic(); - auto func = Ethereum::ABI::Function("deposit", std::vector>{ - std::make_shared(vaultAddressBin), - std::make_shared(toAssetAddressBin), - std::make_shared(uint256_t(amount)), - std::make_shared(memo) - }); - Data payload; - func.encode(payload); - transfer.set_data(payload.data(), payload.size()); - Data amountData = store(uint256_t(amount)); - transfer.set_amount(amountData.data(), amountData.size()); - - auto serialized = input.SerializeAsString(); - out.insert(out.end(), serialized.begin(), serialized.end()); - return std::make_pair(0, ""); + return {.out = std::move(out)}; } - -std::pair Swap::buildBinance([[maybe_unused]] Chain toChain, [[maybe_unused]] const std::string& toSymbol, [[maybe_unused]] const std::string& toTokenId, const std::string& fromAddress, [[maybe_unused]] const std::string& toAddress, const std::string& vaultAddress, uint64_t amount, const std::string& memo, Data& out) { +SwapBundled SwapBuilder::buildBinance(Proto::Asset fromAsset, uint64_t amount, const std::string& memo) { auto input = Binance::Proto::SigningInput(); + Data out; // Following fields must be set afterwards, before signing ... input.set_chain_id(""); @@ -233,18 +170,18 @@ std::pair Swap::buildBinance([[maybe_unused]] Chain toChain, [ auto& order = *input.mutable_send_order(); auto token = Binance::Proto::SendOrder::Token(); - token.set_denom("BNB"); + token.set_denom(fromAsset.token_id().empty() ? "BNB" : fromAsset.token_id()); token.set_amount(amount); { Binance::Address fromAddressBin; - Binance::Address::decode(fromAddress, fromAddressBin); + Binance::Address::decode(mFromAddress, fromAddressBin); auto input_ = order.add_inputs(); input_->set_address(fromAddressBin.getKeyHash().data(), fromAddressBin.getKeyHash().size()); *input_->add_coins() = token; } { Binance::Address vaultAddressBin; - Binance::Address::decode(vaultAddress, vaultAddressBin); + Binance::Address::decode(mVaultAddress, vaultAddressBin); auto output = order.add_outputs(); output->set_address(vaultAddressBin.getKeyHash().data(), vaultAddressBin.getKeyHash().size()); *output->add_coins() = token; @@ -252,7 +189,50 @@ std::pair Swap::buildBinance([[maybe_unused]] Chain toChain, [ auto serialized = input.SerializeAsString(); out.insert(out.end(), serialized.begin(), serialized.end()); - return std::make_pair(0, ""); + return {.out = std::move(out)}; } -} // namespace TW +SwapBundled SwapBuilder::buildEth(uint64_t amount, const std::string& memo) { + Data out; + auto input = Ethereum::Proto::SigningInput(); + const auto& toTokenId = mToAsset.token_id(); + // some sanity check / address conversion + Data vaultAddressBin = ethAddressStringToData(mVaultAddress); + if (!Ethereum::Address::isValid(mVaultAddress) || vaultAddressBin.size() != Ethereum::Address::size) { + return {.status_code = static_cast(Proto::ErrorCode::Error_Invalid_vault_address), .error = "Invalid vault address: " + mVaultAddress}; + } + if (!Ethereum::Address::isValid(*mRouterAddress)) { + return {.status_code = static_cast(Proto::ErrorCode::Error_Invalid_router_address), .error = "Invalid router address: " + *mRouterAddress}; + } + Data toAssetAddressBin = ethAddressStringToData(toTokenId); + + // Following fields must be set afterwards, before signing ... + const auto chainId = store(uint256_t(0)); + input.set_chain_id(chainId.data(), chainId.size()); + const auto nonce = store(uint256_t(0)); + input.set_nonce(nonce.data(), nonce.size()); + const auto gasPrice = store(uint256_t(0)); + input.set_gas_price(gasPrice.data(), gasPrice.size()); + const auto gasLimit = store(uint256_t(0)); + input.set_gas_limit(gasLimit.data(), gasLimit.size()); + input.set_private_key(""); + // ... end + + input.set_to_address(*mRouterAddress); + auto& transfer = *input.mutable_transaction()->mutable_contract_generic(); + auto func = Ethereum::ABI::Function("deposit", std::vector>{ + std::make_shared(vaultAddressBin), + std::make_shared(toAssetAddressBin), + std::make_shared(uint256_t(amount)), + std::make_shared(memo)}); + Data payload; + func.encode(payload); + transfer.set_data(payload.data(), payload.size()); + Data amountData = store(uint256_t(amount)); + transfer.set_amount(amountData.data(), amountData.size()); + + auto serialized = input.SerializeAsString(); + out.insert(out.end(), serialized.begin(), serialized.end()); + return {.out = std::move(out)}; +} +} // namespace TW::THORChainSwap diff --git a/src/THORChain/Swap.h b/src/THORChain/Swap.h index 6f74f047c0e..bd4d253319b 100644 --- a/src/THORChain/Swap.h +++ b/src/THORChain/Swap.h @@ -7,10 +7,11 @@ #pragma once #include "Data.h" +#include "proto/THORChainSwap.pb.h" +#include #include #include -#include namespace TW::THORChainSwap { @@ -22,35 +23,108 @@ enum Chain { BNB = 3, }; -/// Building THORChain cross-chain transactions -class Swap { -public: - /// Logic to build a native transaction on the source chain for a swap - /// Returns serialized SigningInput proto message, on the source chain, - /// and an optional error code + message - static std::tuple build( - Chain fromChain, - Chain toChain, - const std::string& fromAddress, // source address, on source chain, string format - const std::string& toSymbol, // destination coin symbol - const std::string& toTokenId, // destination token ID, on the destination chain, in case destination is a token, empty otherwise - const std::string& toAddress, // destination address, on destination chain, string format - const std::string& vaultAddress, // ThorChainSwap vault, on the source chain. Should be queried afresh, as it may change - const std::string& routerAddress, // ThorChain router, only in case of Ethereum source network - const std::string& fromAmount, // The source amount, as integer in the smallest native unit of the chain - const std::string& toAmountLimit, // The minimum accepted destination amount. Actual destination amount will depend on current rates, limit amount can be used to prevent using very unfavorable rates. - const std::string& affFeeAddress = "", // Optional affiliate fee destination address. A Rune address. - const std::string& affFeeRate = "", // Optional affiliate fee, percentage base points, e.g. 100 means 1%, 0 - 1000, as string. - const std::string& extraMemo = "" // Optional extra custom memo, reserved for later use. - ); - -protected: - static std::pair buildBitcoin(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& fromAddress, const std::string& toAddress, const std::string& vaultAddress, uint64_t amount, const std::string& memo, Data& out); - static std::pair buildEthereum(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& fromAddress, const std::string& toAddress, const std::string& vaultAddress, const std::string& routerAddress, uint64_t amount, const std::string& memo, Data& out); - static std::pair buildBinance(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& fromAddress, const std::string& toAddress, const std::string& vaultAddress, uint64_t amount, const std::string& memo, Data& out); +using SwapErrorCode = int; + +struct SwapBundled { + Data out{}; + SwapErrorCode status_code{0}; + std::string error{""}; +}; + +class SwapBuilder { + Proto::Asset mFromAsset; + Proto::Asset mToAsset; + std::string mFromAddress; + std::string mToAddress; + std::string mVaultAddress; + std::optional mRouterAddress{std::nullopt}; + std::string mFromAmount; + std::string mToAmountLimit{"0"}; + std::optional mAffFeeAddress{std::nullopt}; + std::optional mAffFeeRate{std::nullopt}; + std::optional mExtraMemo{std::nullopt}; + + SwapBundled buildBitcoin(uint64_t amount, const std::string& memo); + SwapBundled buildBinance(Proto::Asset fromAsset, uint64_t amount, const std::string& memo); + SwapBundled buildEth(uint64_t amount, const std::string& memo); public: - static std::string buildMemo(Chain toChain, const std::string& toSymbol, const std::string& toTokenId, const std::string& toAddress, uint64_t limit, const std::string& feeAddress, std::optional feeRate, const std::string& extra); + SwapBuilder() noexcept = default; + + static SwapBuilder builder() noexcept { return {}; } + + SwapBuilder& from(Proto::Asset fromAsset) noexcept { + mFromAsset = std::move(fromAsset); + return *this; + } + + SwapBuilder& fromAddress(std::string fromAddress) noexcept { + mFromAddress = std::move(fromAddress); + return *this; + } + + SwapBuilder& to(Proto::Asset toAsset) noexcept { + mToAsset = std::move(toAsset); + return *this; + } + + SwapBuilder& toAddress(std::string toAddress) noexcept { + mToAddress = std::move(toAddress); + return *this; + } + + SwapBuilder& vault(std::string vaultAddress) noexcept { + mVaultAddress = std::move(vaultAddress); + return *this; + } + + SwapBuilder& router(std::string router) noexcept { + if (!router.empty()) { + mRouterAddress = std::move(router); + } + return *this; + } + + SwapBuilder& affFeeAddress(std::string affFeeAddress) noexcept { + if (!affFeeAddress.empty()) { + mAffFeeAddress = std::move(affFeeAddress); + } else { + mAffFeeAddress = std::nullopt; + } + return *this; + } + + SwapBuilder& affFeeRate(std::string affFeeRate) noexcept { + if (!affFeeRate.empty()) { + mAffFeeRate = std::move(affFeeRate); + } else { + mAffFeeRate = std::nullopt; + } + return *this; + } + + SwapBuilder& extraMemo(std::string extraMemo) noexcept { + if (!extraMemo.empty()) { + mExtraMemo = std::move(extraMemo); + } else { + mExtraMemo = std::nullopt; + } + return *this; + } + + SwapBuilder& fromAmount(std::string fromAmount) noexcept { + mFromAmount = std::move(fromAmount); + return *this; + } + + SwapBuilder& toAmountLimit(std::string toAmountLimit) noexcept { + mToAmountLimit = std::move(toAmountLimit); + return *this; + } + + std::string buildMemo(bool shortened = true) noexcept; + + SwapBundled build(bool shortened = true); }; -} // namespace TW +} // namespace TW::THORChainSwap diff --git a/src/THORChain/TWSwap.cpp b/src/THORChain/TWSwap.cpp index 2b9c70c567a..cad48c53aa6 100644 --- a/src/THORChain/TWSwap.cpp +++ b/src/THORChain/TWSwap.cpp @@ -22,35 +22,33 @@ TWData* _Nonnull TWTHORChainSwapBuildSwap(TWData* _Nonnull input) { return TWDataCreateWithBytes(outputData.data(), outputData.size()); } - const auto fromChain = inputProto.from_chain(); + const auto fromChain = inputProto.from_asset().chain(); const auto toChain = inputProto.to_asset().chain(); - auto res = THORChainSwap::Swap::build( - static_cast(static_cast(fromChain)), - static_cast(static_cast(toChain)), - inputProto.from_address(), - inputProto.to_asset().symbol(), - inputProto.to_asset().token_id(), - inputProto.to_address(), - inputProto.vault_address(), - inputProto.router_address(), - inputProto.from_amount(), - inputProto.to_amount_limit(), - inputProto.affiliate_fee_address(), - inputProto.affiliate_fee_rate_bp(), - inputProto.extra_memo()); + auto&& [txInput, errorCode, error] = THORChainSwap::SwapBuilder::builder() + .from(inputProto.from_asset()) + .to(inputProto.to_asset()) + .fromAddress(inputProto.from_address()) + .toAddress(inputProto.to_address()) + .vault(inputProto.vault_address()) + .router(inputProto.router_address()) + .fromAmount(inputProto.from_amount()) + .toAmountLimit(inputProto.to_amount_limit()) + .affFeeAddress(inputProto.affiliate_fee_address()) + .affFeeRate(inputProto.affiliate_fee_rate_bp()) + .extraMemo(inputProto.extra_memo()) + .build(); outputProto.set_from_chain(fromChain); outputProto.set_to_chain(toChain); - if (std::get<1>(res) != 0) { + if (errorCode != 0) { // error - outputProto.mutable_error()->set_code(static_cast(std::get<1>(res))); - outputProto.mutable_error()->set_message(std::get<2>(res)); + outputProto.mutable_error()->set_code(static_cast(errorCode)); + outputProto.mutable_error()->set_message(error); } else { // no error outputProto.mutable_error()->set_code(THORChainSwap::Proto::ErrorCode::OK); outputProto.mutable_error()->set_message(""); - const Data& txInput = std::get<0>(res); switch (fromChain) { case THORChainSwap::Proto::BTC: { Bitcoin::Proto::SigningInput btcInput; diff --git a/src/proto/THORChainSwap.proto b/src/proto/THORChainSwap.proto index 90ef10fcb19..0d5d2c248b6 100644 --- a/src/proto/THORChainSwap.proto +++ b/src/proto/THORChainSwap.proto @@ -53,7 +53,7 @@ message Asset { // Input for a swap between source and destination chains; for creating a TX on the source chain. message SwapInput { // Source chain - Chain from_chain = 1; + Asset from_asset = 1; // Source address, on source chain string from_address = 2; diff --git a/swift/Tests/Blockchains/THORChainSwapTests.swift b/swift/Tests/Blockchains/THORChainSwapTests.swift index 56a1d6a851d..73500bd9e25 100644 --- a/swift/Tests/Blockchains/THORChainSwapTests.swift +++ b/swift/Tests/Blockchains/THORChainSwapTests.swift @@ -12,7 +12,9 @@ class THORSwapTests: XCTestCase { func testSignerEthBnbWithFee() throws { // prepare swap input let input = THORChainSwapSwapInput.with { - $0.fromChain = .eth + $0.fromAsset = THORChainSwapAsset.with { + $0.chain = .eth + } $0.fromAddress = "0xb9f5771c27664bf2282d98e09d7f50cec7cb01a7" $0.toAsset = THORChainSwapAsset.with { $0.chain = .bnb @@ -30,7 +32,7 @@ class THORSwapTests: XCTestCase { // serialize input let inputSerialized = try input.serializedData() - XCTAssertEqual(inputSerialized.hexString, "0802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a11353030303030303030303030303030303042063630303030334a2f7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c327463717952023130") + XCTAssertEqual(inputSerialized.hexString, "0a020802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a11353030303030303030303030303030303042063630303030334a2f7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c327463717952023130") // invoke swap let outputData = THORChainSwap.buildSwap(input: inputSerialized) @@ -53,13 +55,15 @@ class THORSwapTests: XCTestCase { // sign and encode resulting input let output: EthereumSigningOutput = AnySigner.sign(input: txInput, coin: .ethereum) - XCTAssertEqual(output.encoded.hexString, "f90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000071535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000026a027da86e94739f39e8b493f240eb043888a0dd6962a657963ff7fb26f10291ca8a03fed75d6703d5036402be4d0197432725e17fe6a5d3059abdcca74bd7a789cc8") + XCTAssertEqual(output.encoded.hexString, "f90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000000000026a0ee68bd41da9a9b1ad87fd547e83e4b8022460de024839f4f5f528abc6aecf2aea0402205812d62a075138743f6048ba2a1c073f4a3a14224009a34ee74d3dccef1") } func testSignerBnbBtc() throws { // prepare swap input let input = THORChainSwapSwapInput.with { - $0.fromChain = .bnb + $0.fromAsset = THORChainSwapAsset.with { + $0.chain = .bnb + } $0.fromAddress = "bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx" $0.toAsset = THORChainSwapAsset.with { $0.chain = .btc @@ -75,11 +79,11 @@ class THORSwapTests: XCTestCase { // serialize input let inputSerialized = try input.serializedData() - XCTAssertEqual(inputSerialized.hexString, "0803122a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372781a0708011203425443222a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070382a2a626e62316e396573787577386361377473386c367736366b64683830307330396d7376756c36766c73653a08313030303030303042083130303030303030") + XCTAssertEqual(inputSerialized.hexString, "0a020803122a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372781a0708011203425443222a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070382a2a626e62316e396573787577386361377473386c367736366b64683830307330396d7376756c36766c73653a08313030303030303042083130303030303030") // invoke swap let outputData = THORChainSwap.buildSwap(input: inputSerialized) - XCTAssertEqual(outputData.count, 149) + XCTAssertEqual(outputData.count, 146) // parse result in proto let outputProto = try THORChainSwapSwapOutput(serializedData: outputData) @@ -96,6 +100,6 @@ class THORSwapTests: XCTestCase { // sign and encode resulting input let output: BinanceSigningOutput = AnySigner.sign(input: txInput, coin: .binance) - XCTAssertEqual(output.encoded.hexString, "8002f0625dee0a4c2a2c87fa0a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e421080ade204126a0a26eb5ae9872103ea4b4bc12dc6f36a28d2c9775e01eef44def32cc70fb54f0e4177b659dbc0e1912404836ee8659caa86771281d3f104424d95977bdedf644ec8585f1674796fde525669a6d446f72da89ee90fb0e064473b0a2159a79630e081592c52948d03d67071a40535741503a4254432e4254433a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070383a3130303030303030") + XCTAssertEqual(output.encoded.hexString, "fd01f0625dee0a4c2a2c87fa0a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e421080ade204126a0a26eb5ae9872103ea4b4bc12dc6f36a28d2c9775e01eef44def32cc70fb54f0e4177b659dbc0e19124008455a84c90e73981ae098578d2ab2b498fe17b0436723c596501b9236d96697514467ed4c22ba8f1cb7506172b368a2ca8be0eb82cb93b5320f938209041f2c1a3d3d3a4254432e4254433a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070383a3130303030303030") } } diff --git a/tests/chains/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp index 12926d5f58a..fb23e1f3a32 100644 --- a/tests/chains/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -4,25 +4,25 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "THORChain/Swap.h" +#include "Binance/Address.h" #include "Bitcoin/Script.h" #include "Bitcoin/SegwitAddress.h" -#include "Ethereum/Address.h" #include "Ethereum/ABI/Function.h" -#include "Ethereum/ABI/ParamBase.h" #include "Ethereum/ABI/ParamAddress.h" -#include "Binance/Address.h" -#include "proto/THORChainSwap.pb.h" +#include "Ethereum/ABI/ParamBase.h" +#include "Ethereum/Address.h" +#include "THORChain/Swap.h" +#include "proto/Binance.pb.h" #include "proto/Bitcoin.pb.h" #include "proto/Ethereum.pb.h" -#include "proto/Binance.pb.h" +#include "proto/THORChainSwap.pb.h" -#include "HexCoding.h" #include "Coin.h" -#include -#include -#include "uint256.h" +#include "HexCoding.h" #include "TestUtilities.h" +#include "uint256.h" +#include +#include #include @@ -41,15 +41,27 @@ const auto VaultEth = "0x1091c4De6a3cF09CdA00AbDAeD42c7c3B69C83EC"; const auto VaultBnb = "bnb1n9esxuw8ca7ts8l6w66kdh800s09msvul6vlse"; const auto RouterEth = "0x42A5Ed456650a09Dc10EBc6361A7480fDd61f27B"; - TEST(THORChainSwap, SwapBtcEth) { - auto res = Swap::build(Chain::BTC, Chain::ETH, Address1Btc, "ETH", "", Address1Eth, VaultBtc, "", "1000000", "140000000000000000"); - ASSERT_EQ(std::get<1>(res), 0); - ASSERT_EQ(std::get<2>(res), ""); - EXPECT_EQ(hex(std::get<0>(res)), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a473d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a313430303030303030303030303030303030"); + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::BTC)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::ETH)); + toAsset.set_symbol("ETH"); + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Btc) + .toAddress(Address1Eth) + .vault(VaultBtc) + .fromAmount("1000000") + .toAmountLimit("140000000000000000") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a473d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a313430303030303030303030303030303030"); auto tx = Bitcoin::Proto::SigningInput(); - ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields EXPECT_EQ(tx.amount(), 1000000); @@ -96,19 +108,33 @@ TEST(THORChainSwap, SwapBtcEth) { } TEST(THORChainSwap, SwapBtcBnb) { - auto res = Swap::build(Chain::BTC, Chain::BNB, Address1Btc, "BNB", "", Address1Bnb, VaultBtc, "", "200000", "140000000"); - ASSERT_EQ(std::get<1>(res), 0); - ASSERT_EQ(std::get<2>(res), ""); - EXPECT_EQ(hex(std::get<0>(res)), "080110c09a0c1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a41535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a313430303030303030"); + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::BTC)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BNB)); + toAsset.set_symbol("BNB"); + + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Btc) + .toAddress(Address1Bnb) + .vault(VaultBtc) + .fromAmount("200000") + .toAmountLimit("140000000") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "080110c09a0c1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a3e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a313430303030303030"); auto tx = Bitcoin::Proto::SigningInput(); - ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields EXPECT_EQ(tx.amount(), 200000); EXPECT_EQ(tx.to_address(), VaultBtc); EXPECT_EQ(tx.change_address(), Address1Btc); - EXPECT_EQ(tx.output_op_return(), "SWAP:BNB.BNB:bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx:140000000"); + EXPECT_EQ(tx.output_op_return(), "=:BNB.BNB:bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx:140000000"); EXPECT_EQ(tx.coin_type(), 0ul); EXPECT_EQ(tx.private_key_size(), 0); EXPECT_FALSE(tx.has_plan()); @@ -139,11 +165,11 @@ TEST(THORChainSwap, SwapBtcBnb) { "eb48da786cbd9430bf5ef3d1d3bc7206a4182fd7d5ac3f4e8d05754c3a5cae8e" "00000000" "00" "" "fcffffff" "03" // outputs "400d030000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" - "c08c030000000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" - "0000000000000000" "43" "6a41535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a313430303030303030" + "b08d030000000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" + "0000000000000000" "40" "6a3e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a313430303030303030" // witness "02" - "47" "3044022071616db5a7fc9e01307ed90eb9a0a30f1441b528ba7631dc8cc8d37448369eed02202e338a0bf857c8dd096173f921fbe0d7d5f154197ab2ca7800079432f6ba486301210" + "48" "3045022100e17d8cf207c79edfb7afa16102842b434e1f908bd9858553fd54970f1a8b4334022059583f89c3a126df0da46d92947bcbe7c265a1bb838b696c0e7ea7fc8761c2bf01210" "21" "e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" "00000000" // nLockTime ); @@ -166,13 +192,27 @@ Data SwapTest_ethAddressStringToData(const std::string& asString) { } TEST(THORChainSwap, SwapEthBnb) { - auto res = Swap::build(Chain::ETH, Chain::BNB, Address1Eth, "BNB", "", Address1Bnb, VaultEth, RouterEth, "50000000000000000", "600003"); - ASSERT_EQ(std::get<1>(res), 0); - ASSERT_EQ(std::get<2>(res), ""); - EXPECT_EQ(hex(std::get<0>(res)), "0a01001201002201002a0100422a30783432413545643435363635306130394463313045426336333631413734383066446436316632374252f30132f0010a07b1a2bc2ec5000012e4011fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003e535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030330000"); + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::ETH)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BNB)); + toAsset.set_symbol("BNB"); + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Eth) + .toAddress(Address1Bnb) + .vault(VaultEth) + .router(RouterEth) + .fromAmount("50000000000000000") + .toAmountLimit("600003") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "0a01001201002201002a0100422a30783432413545643435363635306130394463313045426336333631413734383066446436316632374252f30132f0010a07b1a2bc2ec5000012e4011fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003b3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030330000000000"); auto tx = Ethereum::Proto::SigningInput(); - ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields EXPECT_EQ(tx.to_address(), RouterEth); @@ -181,21 +221,20 @@ TEST(THORChainSwap, SwapEthBnb) { Data vaultAddressBin = SwapTest_ethAddressStringToData(VaultEth); EXPECT_EQ(hex(vaultAddressBin), "1091c4de6a3cf09cda00abdaed42c7c3b69c83ec"); auto func = Ethereum::ABI::Function("deposit", std::vector>{ - std::make_shared(vaultAddressBin), - std::make_shared(parse_hex("0000000000000000000000000000000000000000")), - std::make_shared(uint256_t(50000000000000000)), - std::make_shared("SWAP:BNB.BNB:bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx:600003") - }); + std::make_shared(vaultAddressBin), + std::make_shared(parse_hex("0000000000000000000000000000000000000000")), + std::make_shared(uint256_t(50000000000000000)), + std::make_shared("=:BNB.BNB:bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx:600003")}); Data payload; func.encode(payload); EXPECT_EQ(hex(payload), "1fece7b4" - "0000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec" - "0000000000000000000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000b1a2bc2ec50000" - "0000000000000000000000000000000000000000000000000000000000000080" - "000000000000000000000000000000000000000000000000000000000000003e" - "535741503a424e422e424e423a626e6231757334377764686678303863683937" - "7a6475656833783375356d757266727833306a656372783a3630303030330000"); + "0000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec" + "0000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000b1a2bc2ec50000" + "0000000000000000000000000000000000000000000000000000000000000080" + "000000000000000000000000000000000000000000000000000000000000003b" + "3d3a424e422e424e423a626e62317573343777646866783038636839377a6475" + "656833783375356d757266727833306a656372783a3630303030330000000000"); EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().amount())), "b1a2bc2ec50000"); EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().data())), hex(payload)); @@ -216,20 +255,33 @@ TEST(THORChainSwap, SwapEthBnb) { // sign and encode resulting input Ethereum::Proto::SigningOutput output; ANY_SIGN(tx, TWCoinTypeEthereum); - EXPECT_EQ(hex(output.encoded()), "f90151038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b8e41fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003e535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a363030303033000025a06ae104be3201baca38315352f81fac70ca4dd47339981914e64e91149813e780a066a3f0b2c44ddf5a96a38481274f623f552a593d723237d6742185f4885c0064"); + EXPECT_EQ(hex(output.encoded()), "f90151038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b8e41fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003b3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a363030303033000000000026a0669563be8a0022fcd32fdf82ccca7dc66012ea28c57e95a2d9348dbf37afc377a03505f5eb041038c565d2f2888207c9dbcad8ca12f10ce5c5bd2ca41de01a9e89"); } TEST(THORChainSwap, SwapBnbBtc) { - auto res = Swap::build(Chain::BNB, Chain::BTC, Address1Bnb, "BTC", "", Address1Btc, VaultBnb, "", "10000000", "10000000"); - ASSERT_EQ(std::get<1>(res), 0); - ASSERT_EQ(std::get<2>(res), ""); - EXPECT_EQ(hex(std::get<0>(res)), "2a40535741503a4254432e4254433a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070383a313030303030303052480a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e421080ade204"); + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::BNB)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BTC)); + toAsset.set_symbol("BTC"); + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Bnb) + .toAddress(Address1Btc) + .vault(VaultBnb) + .fromAmount("10000000") + .toAmountLimit("10000000") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "2a3d3d3a4254432e4254433a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070383a313030303030303052480a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e421080ade204"); auto tx = Binance::Proto::SigningInput(); - ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields - EXPECT_EQ(tx.memo(), "SWAP:BTC.BTC:bc1qpjult34k9spjfym8hss2jrwjgf0xjf40ze0pp8:10000000"); + EXPECT_EQ(tx.memo(), "=:BTC.BTC:bc1qpjult34k9spjfym8hss2jrwjgf0xjf40ze0pp8:10000000"); ASSERT_TRUE(tx.has_send_order()); ASSERT_EQ(tx.send_order().inputs_size(), 1); ASSERT_EQ(tx.send_order().outputs_size(), 1); @@ -244,17 +296,30 @@ TEST(THORChainSwap, SwapBnbBtc) { // sign and encode resulting input Binance::Proto::SigningOutput output; ANY_SIGN(tx, TWCoinTypeBinance); - EXPECT_EQ(hex(output.encoded()), "8002f0625dee0a4c2a2c87fa0a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e421080ade204126a0a26eb5ae9872103ea4b4bc12dc6f36a28d2c9775e01eef44def32cc70fb54f0e4177b659dbc0e191240af2117ebd42e31a9562738e9f8933b3b54b59e6305b5675956525e4edb6a6ac65abea614e90959ae388664e2b36bf720024879b6047e174e3cff95f8f364a4e71a40535741503a4254432e4254433a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070383a3130303030303030"); + EXPECT_EQ(hex(output.encoded()), "fd01f0625dee0a4c2a2c87fa0a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e421080ade204126a0a26eb5ae9872103ea4b4bc12dc6f36a28d2c9775e01eef44def32cc70fb54f0e4177b659dbc0e19124086d43e9bdf12508a9a1415f5f970dfa5ff5930dee01d922f99779b63190735ba1d69694bda203b6678939a5c1eab0a52ed32bb67864ec7864de37b333533ae0c1a3d3d3a4254432e4254433a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070383a3130303030303030"); } TEST(THORChainSwap, SwapBnbEth) { - auto res = Swap::build(Chain::BNB, Chain::ETH, Address1Bnb, "ETH", "", Address1Eth, VaultBnb, "", "27000000", "123456"); - ASSERT_EQ(std::get<1>(res), 0); - ASSERT_EQ(std::get<2>(res), ""); - EXPECT_EQ(hex(std::get<0>(res)), "2a3b3d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a31323334353652480a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e4210c0f9ef0c12220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e4210c0f9ef0c"); + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::BNB)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::ETH)); + toAsset.set_symbol("ETH"); + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Bnb) + .toAddress(Address1Eth) + .vault(VaultBnb) + .fromAmount("27000000") + .toAmountLimit("123456") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "2a3b3d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a31323334353652480a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e4210c0f9ef0c12220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e4210c0f9ef0c"); auto tx = Binance::Proto::SigningInput(); - ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields EXPECT_EQ(tx.memo(), "=:ETH.ETH:0xb9f5771c27664bf2282d98e09d7f50cec7cb01a7:123456"); @@ -283,16 +348,29 @@ TEST(THORChainSwap, SwapBnbEth) { } TEST(THORChainSwap, SwapBnbRune) { - auto res = Swap::build(Chain::BNB, Chain::THOR, Address1Bnb, "RUNE", "", Address1Thor, VaultBnb, "", "4000000", "121065076"); - ASSERT_EQ(std::get<1>(res), 0); - ASSERT_EQ(std::get<2>(res), ""); - EXPECT_EQ(hex(std::get<0>(res)), "2a44535741503a54484f522e52554e453a74686f72317a3533777765376d64366365777a39737177717a6e306161767061756e3067773065786e32723a31323130363530373652480a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e42108092f40112220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e42108092f401"); + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::BNB)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::THOR)); + toAsset.set_symbol("RUNE"); + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Bnb) + .toAddress(Address1Thor) + .vault(VaultBnb) + .fromAmount("4000000") + .toAmountLimit("121065076") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "2a413d3a54484f522e52554e453a74686f72317a3533777765376d64366365777a39737177717a6e306161767061756e3067773065786e32723a31323130363530373652480a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e42108092f40112220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e42108092f401"); auto tx = Binance::Proto::SigningInput(); - ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields - EXPECT_EQ(tx.memo(), "SWAP:THOR.RUNE:thor1z53wwe7md6cewz9sqwqzn0aavpaun0gw0exn2r:121065076"); + EXPECT_EQ(tx.memo(), "=:THOR.RUNE:thor1z53wwe7md6cewz9sqwqzn0aavpaun0gw0exn2r:121065076"); ASSERT_TRUE(tx.has_send_order()); ASSERT_EQ(tx.send_order().inputs_size(), 1); ASSERT_EQ(tx.send_order().outputs_size(), 1); @@ -309,35 +387,91 @@ TEST(THORChainSwap, SwapBnbRune) { // sign and encode resulting input Binance::Proto::SigningOutput output; ANY_SIGN(tx, TWCoinTypeBinance); - EXPECT_EQ(hex(output.encoded()), "8a02f0625dee0a4c2a2c87fa0a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e42108092f40112220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e42108092f40112700a26eb5ae9872103ea4b4bc12dc6f36a28d2c9775e01eef44def32cc70fb54f0e4177b659dbc0e191240d91b6655ea4ade62a90cc9b28e43ccd2887dcf1c563e42bbd0d6ae4e825c2c6a1ba7784866810f36b6e098b0c877d1daa48016d0558f7b796b3f0b410107ba2f18ea8f7420041a44535741503a54484f522e52554e453a74686f72317a3533777765376d64366365777a39737177717a6e306161767061756e3067773065786e32723a313231303635303736"); + EXPECT_EQ(hex(output.encoded()), "8702f0625dee0a4c2a2c87fa0a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e42108092f40112220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e42108092f40112700a26eb5ae9872103ea4b4bc12dc6f36a28d2c9775e01eef44def32cc70fb54f0e4177b659dbc0e191240f0bd5a0b4936ce73b1564f737a22cb7cfa3c171a3598b1fe42f6c926c516777042673f3b30148d54b591dcfcb88c2aa04bb87b4b492e8d17c72e4d263f57159018ea8f7420041a413d3a54484f522e52554e453a74686f72317a3533777765376d64366365777a39737177717a6e306161767061756e3067773065786e32723a313231303635303736"); // real transaction: // https://explorer.binance.org/tx/84EE429B35945F0568097527A084532A9DE7BBAB0E6A5562E511CEEFB188DE69 // https://viewblock.io/thorchain/tx/D582E1473FE229F02F162055833C64F49FB4FF515989A4785ED7898560A448FC } +TEST(THORChainSwap, SwapBusdTokenBnb) { + Proto::Asset fromAsset; + fromAsset.set_symbol("BNB"); + fromAsset.set_token_id("BUSD-BD1"); + fromAsset.set_chain(static_cast(Chain::BNB)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BNB)); + toAsset.set_symbol("BNB"); + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress("bnb1gddl87crh47wzynjx3c6pmcclzk7txlkm74x28") + .toAddress("bnb1gddl87crh47wzynjx3c6pmcclzk7txlkm74x28") + .vault("bnb17e9qd0ffrkxsy9pehx7q6hjer730pzq5z4tv82") + .fromAmount("500000000") + .toAmountLimit("719019") + .affFeeAddress("t") + .affFeeRate("0") + .build(false); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "2a42535741503a424e422e424e423a626e62316764646c38376372683437777a796e6a78336336706d63636c7a6b3774786c6b6d37347832383a3731393031393a743a3052540a280a14435bf3fb03bd7ce112723471a0ef18f8ade59bf612100a08425553442d4244311080cab5ee0112280a14f64a06bd291d8d021439b9bc0d5e591fa2f0881412100a08425553442d4244311080cab5ee01"); + + auto tx = Binance::Proto::SigningInput(); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); + + // check fields + EXPECT_EQ(tx.memo(), "SWAP:BNB.BNB:bnb1gddl87crh47wzynjx3c6pmcclzk7txlkm74x28:719019:t:0"); + ASSERT_TRUE(tx.has_send_order()); + ASSERT_EQ(tx.send_order().inputs_size(), 1); + ASSERT_EQ(tx.send_order().outputs_size(), 1); + EXPECT_EQ(hex(tx.send_order().inputs(0).address()), "435bf3fb03bd7ce112723471a0ef18f8ade59bf6"); + EXPECT_EQ(hex(tx.send_order().outputs(0).address()), "f64a06bd291d8d021439b9bc0d5e591fa2f08814"); + EXPECT_EQ(hex(TW::data(tx.private_key())), ""); + + // set private key and few other fields + const Data privateKey = parse_hex("412c379cccf9d792238f0a8bd923604e00c2be11ea1de715945f6a849796362a"); + EXPECT_EQ(Binance::Address(PrivateKey(privateKey).getPublicKey(TWPublicKeyTypeSECP256k1)).string(), "bnb1gddl87crh47wzynjx3c6pmcclzk7txlkm74x28"); + tx.set_private_key(privateKey.data(), privateKey.size()); + tx.set_chain_id("Binance-Chain-Tigris"); + tx.set_account_number(7320332); + tx.set_sequence(2); + + // sign and encode resulting input + Binance::Proto::SigningOutput output; + ANY_SIGN(tx, TWCoinTypeBinance); + EXPECT_EQ(hex(output.encoded()), "9502f0625dee0a582a2c87fa0a280a14435bf3fb03bd7ce112723471a0ef18f8ade59bf612100a08425553442d4244311080cab5ee0112280a14f64a06bd291d8d021439b9bc0d5e591fa2f0881412100a08425553442d4244311080cab5ee0112710a26eb5ae98721039aa92707d6789692628099f288de219c9c9a0dd179df4e8b1b717191c75fbbfb1240fb41cf3eaaf1286de4be633682c120886b39dcc41690b583f4f08561d660a1677ebda2323e0f22c440c6fe8855d21f1153557b94066ce956363f0a82d1ab3c92188ce6be0320021a42535741503a424e422e424e423a626e62316764646c38376372683437777a796e6a78336336706d63636c7a6b3774786c6b6d37347832383a3731393031393a743a30"); + + // https://viewblock.io/thorchain/tx/1B7E472C7C8D60176FCFD83CAD7DA970EB12B45145C553CD37BD34CABE276C59 + // https://explorer.bnbchain.org/tx/1B7E472C7C8D60176FCFD83CAD7DA970EB12B45145C553CD37BD34CABE276C59 + // https://explorer.bnbchain.org/tx/79D2194584F498CA2D4C391FBD7B158FC94B670703B629CA6F46852BB24234A6 +} + TEST(THORChainSwap, SwapBnbBnbToken) { - auto res = Swap::build( - Chain::BNB, - Chain::BNB, - "bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx", - "BNB", - "TWT-8C2", - "bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx", - "bnb1qefsjm654cdw94ejj8g4s49w7z8te75veslusz", - "", - "10000000", // 0.1 bnb - "5400000000" // 54.0 twt - ); - ASSERT_EQ(std::get<1>(res), 0); - ASSERT_EQ(std::get<2>(res), ""); - EXPECT_EQ(hex(std::get<0>(res)), "2a46535741503a424e422e5457542d3843323a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3534303030303030303052480a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a140653096f54ae1ae2d73291d15854aef08ebcfa8c120a0a03424e421080ade204"); + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::BNB)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BNB)); + toAsset.set_symbol("BNB"); + toAsset.set_token_id("TWT-8C2"); + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress("bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx") + .toAddress("bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx") + .vault("bnb1qefsjm654cdw94ejj8g4s49w7z8te75veslusz") + .fromAmount("10000000") + .toAmountLimit("5400000000") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "2a433d3a424e422e5457542d3843323a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3534303030303030303052480a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a140653096f54ae1ae2d73291d15854aef08ebcfa8c120a0a03424e421080ade204"); auto tx = Binance::Proto::SigningInput(); - ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields - EXPECT_EQ(tx.memo(), "SWAP:BNB.TWT-8C2:bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx:5400000000"); + EXPECT_EQ(tx.memo(), "=:BNB.TWT-8C2:bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx:5400000000"); ASSERT_TRUE(tx.has_send_order()); ASSERT_EQ(tx.send_order().inputs_size(), 1); ASSERT_EQ(tx.send_order().outputs_size(), 1); @@ -356,7 +490,7 @@ TEST(THORChainSwap, SwapBnbBnbToken) { // sign and encode resulting input Binance::Proto::SigningOutput output; ANY_SIGN(tx, TWCoinTypeBinance); - EXPECT_EQ(hex(output.encoded()), "8c02f0625dee0a4c2a2c87fa0a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a140653096f54ae1ae2d73291d15854aef08ebcfa8c120a0a03424e421080ade20412700a26eb5ae9872103ea4b4bc12dc6f36a28d2c9775e01eef44def32cc70fb54f0e4177b659dbc0e1912405fd64a0ed5777f5ea4556624bd096f8b20b6d2b510655e4c928db1ec967e6c7025453882ce7e10138ac92f5d6a949acc5382a5539f81347856c67c4bb678d3c418ea8f7420121a46535741503a424e422e5457542d3843323a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a35343030303030303030"); + EXPECT_EQ(hex(output.encoded()), "8902f0625dee0a4c2a2c87fa0a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a140653096f54ae1ae2d73291d15854aef08ebcfa8c120a0a03424e421080ade20412700a26eb5ae9872103ea4b4bc12dc6f36a28d2c9775e01eef44def32cc70fb54f0e4177b659dbc0e191240918963970aedc528e3a9ba34f37fb544ec18e7d2caade2ebf7b8371928c93e6e0eca072313ddfda393c1340766d5fef00e6b0cb7147ef3382b6303f3a6ca01a318ea8f7420121a433d3a424e422e5457542d3843323a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a35343030303030303030"); // real transaction: // curl -X GET "http://dataseed1.binance.org/broadcast_tx_sync?tx=0x8c02...3030" @@ -366,13 +500,28 @@ TEST(THORChainSwap, SwapBnbBnbToken) { } TEST(THORChainSwap, SwapBtcEthWithAffFee) { - auto res = Swap::build(Chain::BTC, Chain::ETH, Address1Btc, "ETH", "", Address1Eth, VaultBtc, "", "1000000", "140000000000000000", "thrnm", "10"); - ASSERT_EQ(std::get<1>(res), 0); - ASSERT_EQ(std::get<2>(res), ""); - EXPECT_EQ(hex(std::get<0>(res)), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a503d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7468726e6d3a3130"); + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::BTC)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::ETH)); + toAsset.set_symbol("ETH"); + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Btc) + .toAddress(Address1Eth) + .vault(VaultBtc) + .fromAmount("1000000") + .toAmountLimit("140000000000000000") + .affFeeAddress("thrnm") + .affFeeRate("10") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a503d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7468726e6d3a3130"); auto tx = Bitcoin::Proto::SigningInput(); - ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields EXPECT_EQ(tx.amount(), 1000000); @@ -419,13 +568,29 @@ TEST(THORChainSwap, SwapBtcEthWithAffFee) { } TEST(THORChainSwap, SwapEthBnbWithAffFee) { - auto res = Swap::build(Chain::ETH, Chain::BNB, Address1Eth, "BNB", "", Address1Bnb, VaultEth, RouterEth, "50000000000000000", "600003", "tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy", "10"); - ASSERT_EQ(std::get<1>(res), 0); - ASSERT_EQ(std::get<2>(res), ""); - EXPECT_EQ(hex(std::get<0>(res)), "0a01001201002201002a0100422a30783432413545643435363635306130394463313045426336333631413734383066446436316632374252b30232b0020a07b1a2bc2ec5000012a4021fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000071535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a3130000000000000000000000000000000"); + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::ETH)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BNB)); + toAsset.set_symbol("BNB"); + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Eth) + .toAddress(Address1Bnb) + .vault(VaultEth) + .router(RouterEth) + .fromAmount("50000000000000000") + .toAmountLimit("600003") + .affFeeAddress("tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy") + .affFeeRate("10") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "0a01001201002201002a0100422a30783432413545643435363635306130394463313045426336333631413734383066446436316632374252b30232b0020a07b1a2bc2ec5000012a4021fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a3130000000000000000000000000000000000000"); auto tx = Ethereum::Proto::SigningInput(); - ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields EXPECT_EQ(tx.to_address(), RouterEth); @@ -434,23 +599,22 @@ TEST(THORChainSwap, SwapEthBnbWithAffFee) { Data vaultAddressBin = SwapTest_ethAddressStringToData(VaultEth); EXPECT_EQ(hex(vaultAddressBin), "1091c4de6a3cf09cda00abdaed42c7c3b69c83ec"); auto func = Ethereum::ABI::Function("deposit", std::vector>{ - std::make_shared(vaultAddressBin), - std::make_shared(parse_hex("0000000000000000000000000000000000000000")), - std::make_shared(uint256_t(50000000000000000)), - std::make_shared("SWAP:BNB.BNB:bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx:600003:tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy:10") - }); + std::make_shared(vaultAddressBin), + std::make_shared(parse_hex("0000000000000000000000000000000000000000")), + std::make_shared(uint256_t(50000000000000000)), + std::make_shared("=:BNB.BNB:bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx:600003:tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy:10")}); Data payload; func.encode(payload); EXPECT_EQ(hex(payload), "1fece7b4" - "0000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec" - "0000000000000000000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000b1a2bc2ec50000" - "0000000000000000000000000000000000000000000000000000000000000080" - "0000000000000000000000000000000000000000000000000000000000000071" - "535741503a424e422e424e423a626e6231757334377764686678303863683937" - "7a6475656833783375356d757266727833306a656372783a3630303030333a74" - "74686f7231716c3274637179727173676e716c32746371796a326e386b66646d" - "74396c6830797a716c32746371793a3130000000000000000000000000000000"); + "0000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec" + "0000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000b1a2bc2ec50000" + "0000000000000000000000000000000000000000000000000000000000000080" + "000000000000000000000000000000000000000000000000000000000000006e" + "3d3a424e422e424e423a626e62317573343777646866783038636839377a6475" + "656833783375356d757266727833306a656372783a3630303030333a7474686f" + "7231716c3274637179727173676e716c32746371796a326e386b66646d74396c" + "6830797a716c32746371793a3130000000000000000000000000000000000000"); EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().amount())), "b1a2bc2ec50000"); EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().data())), hex(payload)); @@ -472,17 +636,33 @@ TEST(THORChainSwap, SwapEthBnbWithAffFee) { // sign and encode resulting input Ethereum::Proto::SigningOutput output; ANY_SIGN(tx, TWCoinTypeEthereum); - EXPECT_EQ(hex(output.encoded()), "f90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000071535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000026a027da86e94739f39e8b493f240eb043888a0dd6962a657963ff7fb26f10291ca8a03fed75d6703d5036402be4d0197432725e17fe6a5d3059abdcca74bd7a789cc8"); + EXPECT_EQ(hex(output.encoded()), "f90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000000000026a0ee68bd41da9a9b1ad87fd547e83e4b8022460de024839f4f5f528abc6aecf2aea0402205812d62a075138743f6048ba2a1c073f4a3a14224009a34ee74d3dccef1"); } TEST(THORChainSwap, SwapBtcNegativeMemoTooLong) { - auto res = Swap::build(Chain::BTC, Chain::ETH, Address1Btc, "ETH", "", Address1Eth, VaultBtc, "", "1000000", "140000000000000000", "affiliate_address", "10", "extra_memo_very_loooooooooooooong"); - ASSERT_EQ(std::get<1>(res), 0); - ASSERT_EQ(std::get<2>(res), ""); - EXPECT_EQ(hex(std::get<0>(res)), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a7e3d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a616666696c696174655f616464726573733a31303a65787472615f6d656d6f5f766572795f6c6f6f6f6f6f6f6f6f6f6f6f6f6f6f6e67"); + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::BTC)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::ETH)); + toAsset.set_symbol("ETH"); + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Btc) + .toAddress(Address1Eth) + .vault(VaultBtc) + .fromAmount("1000000") + .toAmountLimit("140000000000000000") + .affFeeAddress("affiliate_address") + .affFeeRate("10") + .extraMemo("extra_memo_very_loooooooooooooong") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a7e3d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a616666696c696174655f616464726573733a31303a65787472615f6d656d6f5f766572795f6c6f6f6f6f6f6f6f6f6f6f6f6f6f6f6e67"); auto tx = Bitcoin::Proto::SigningInput(); - ASSERT_TRUE(tx.ParseFromArray(std::get<0>(res).data(), (int)std::get<0>(res).size())); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields EXPECT_EQ(tx.amount(), 1000000); @@ -516,64 +696,157 @@ TEST(THORChainSwap, SwapBtcNegativeMemoTooLong) { } TEST(THORChainSwap, Memo) { - EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "", std::nullopt, ""), "SWAP:BTC.BTC:btc123:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::BNB, "BNB", "", "bnb123", 1234, "", std::nullopt, ""), "SWAP:BNB.BNB:bnb123:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::ETH, "ETH", "", "0xaabbccdd", 1234, "", std::nullopt, ""), "=:ETH.ETH:0xaabbccdd:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::ETH, "ETH", "", "0xaabbccdd", 1234, "", std::nullopt, ""), "=:ETH.ETH:0xaabbccdd:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::ETH, "ETH", "0x0000000000000000000000000000000000000000", "0xaabbccdd", 1234, "", std::nullopt, ""), "=:ETH.ETH:0xaabbccdd:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::ETH, "ETH", "0x4B0F1812e5Df2A09796481Ff14017e6005508003", "0xaabbccdd", 1234, "", std::nullopt, ""), "=:ETH.0x4B0F1812e5Df2A09796481Ff14017e6005508003:0xaabbccdd:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::BNB, "BNB", "TWT-8C2", "bnb123", 1234, "", std::nullopt, ""), "SWAP:BNB.TWT-8C2:bnb123:1234"); - EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "feeaddr", std::nullopt, ""), "SWAP:BTC.BTC:btc123:1234:feeaddr"); - EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "feeaddr", 10, ""), "SWAP:BTC.BTC:btc123:1234:feeaddr:10"); - EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "feeaddr", 10, "extramemo"), "SWAP:BTC.BTC:btc123:1234:feeaddr:10:extramemo"); - EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "feeaddr", 0, ""), "SWAP:BTC.BTC:btc123:1234:feeaddr:0"); - EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "", 10, ""), "SWAP:BTC.BTC:btc123:1234::10"); - EXPECT_EQ(Swap::buildMemo(Chain::BTC, "BTC", "", "btc123", 1234, "", std::nullopt, "extramemo"), "SWAP:BTC.BTC:btc123:1234:::extramemo"); + Proto::Asset toAssetBTC; + toAssetBTC.set_chain(static_cast(Chain::BTC)); + toAssetBTC.set_symbol("BTC"); + auto builder = SwapBuilder::builder().to(toAssetBTC).toAddress("btc123").toAmountLimit("1234"); + EXPECT_EQ(builder.buildMemo(), "=:BTC.BTC:btc123:1234"); + EXPECT_EQ(builder.affFeeAddress("feeaddr").buildMemo(), "=:BTC.BTC:btc123:1234:feeaddr"); + EXPECT_EQ(builder.affFeeRate("10").buildMemo(), "=:BTC.BTC:btc123:1234:feeaddr:10"); + EXPECT_EQ(builder.extraMemo("extramemo").buildMemo(), "=:BTC.BTC:btc123:1234:feeaddr:10:extramemo"); + EXPECT_EQ(builder.extraMemo("").affFeeRate("0").buildMemo(), "=:BTC.BTC:btc123:1234:feeaddr:0"); + EXPECT_EQ(builder.affFeeAddress("").affFeeRate("10").buildMemo(), "=:BTC.BTC:btc123:1234::10"); + EXPECT_EQ(builder.extraMemo("extramemo").affFeeRate("").buildMemo(), "=:BTC.BTC:btc123:1234:::extramemo"); + + Proto::Asset toAssetETH; + toAssetETH.set_chain(static_cast(Chain::ETH)); + toAssetETH.set_symbol("ETH"); + builder = SwapBuilder::builder().to(toAssetETH).toAddress("0xaabbccdd").toAmountLimit("1234"); + EXPECT_EQ(builder.buildMemo(), "=:ETH.ETH:0xaabbccdd:1234"); + toAssetETH.set_token_id("0x0000000000000000000000000000000000000000"); + EXPECT_EQ(builder.to(toAssetETH).buildMemo(), "=:ETH.ETH:0xaabbccdd:1234"); + toAssetETH.set_token_id("0x4B0F1812e5Df2A09796481Ff14017e6005508003"); + EXPECT_EQ(builder.to(toAssetETH).buildMemo(), "=:ETH.0x4B0F1812e5Df2A09796481Ff14017e6005508003:0xaabbccdd:1234"); + + builder = SwapBuilder::builder().to(toAssetETH).toAddress("bnb123").toAmountLimit("1234"); + Proto::Asset toAssetBNB; + toAssetBNB.set_chain(static_cast(Chain::BNB)); + toAssetBNB.set_symbol("BNB"); + EXPECT_EQ(builder.to(toAssetBNB).buildMemo(), "=:BNB.BNB:bnb123:1234"); + toAssetBNB.set_token_id("TWT-8C2"); + EXPECT_EQ(builder.to(toAssetBNB).buildMemo(), "=:BNB.TWT-8C2:bnb123:1234"); } TEST(THORChainSwap, WrongFromAddress) { + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::BNB)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::ETH)); + toAsset.set_symbol("ETH"); { - auto res = Swap::build(Chain::BNB, Chain::ETH, "DummyAddress", "ETH", "", Address1Eth, VaultEth, "", "100000", "100000"); - EXPECT_EQ(std::get<1>(res), Proto::ErrorCode::Error_Invalid_from_address); - EXPECT_EQ(std::get<2>(res), "Invalid from address"); + auto && [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress("DummyAddress") + .toAddress(Address1Eth) + .vault(VaultEth) + .fromAmount("1000000") + .toAmountLimit("100000") + .build(); + EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Invalid_from_address); + EXPECT_EQ(error, "Invalid from address"); } { - auto res = Swap::build(Chain::BNB, Chain::ETH, Address1Btc, "ETH", "", Address1Eth, VaultEth, "", "100000", "100000"); - EXPECT_EQ(std::get<1>(res), Proto::ErrorCode::Error_Invalid_from_address); - EXPECT_EQ(std::get<2>(res), "Invalid from address"); + auto && [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Btc) + .toAddress(Address1Eth) + .vault(VaultEth) + .fromAmount("1000000") + .toAmountLimit("100000") + .build(); + EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Invalid_from_address); + EXPECT_EQ(error, "Invalid from address"); } } TEST(THORChainSwap, WrongToAddress) { + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::BNB)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::ETH)); + toAsset.set_symbol("ETH"); { - auto res = Swap::build(Chain::BNB, Chain::ETH, Address1Bnb, "ETH", "", "DummyAddress", VaultEth, "", "100000", "100000"); - EXPECT_EQ(std::get<1>(res), Proto::ErrorCode::Error_Invalid_to_address); - EXPECT_EQ(std::get<2>(res), "Invalid to address"); + auto && [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Bnb) + .toAddress("DummyAddress") + .vault(VaultEth) + .fromAmount("100000") + .toAmountLimit("100000") + .build(); + EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Invalid_to_address); + EXPECT_EQ(error, "Invalid to address"); } { - auto res = Swap::build(Chain::BNB, Chain::ETH, Address1Bnb, "ETH", "", Address1Btc, VaultEth, "", "100000", "100000"); - EXPECT_EQ(std::get<1>(res), Proto::ErrorCode::Error_Invalid_to_address); - EXPECT_EQ(std::get<2>(res), "Invalid to address"); + auto && [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Bnb) + .toAddress(Address1Btc) + .vault(VaultEth) + .fromAmount("100000") + .toAmountLimit("100000") + .build(); + EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Invalid_to_address); + EXPECT_EQ(error, "Invalid to address"); } } TEST(THORChainSwap, FromRuneNotSupported) { - auto res = Swap::build(Chain::THOR, Chain::BNB, Address1Thor, "BNB", "", Address1Bnb, "", "", "1000", "1000"); - EXPECT_EQ(std::get<1>(res), Proto::ErrorCode::Error_Unsupported_from_chain); - EXPECT_EQ(std::get<2>(res), "Unsupported from chain: 3"); + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::THOR)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BNB)); + toAsset.set_symbol("BNB"); + auto && [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Thor) + .toAddress(Address1Bnb) + .fromAmount("1000") + .toAmountLimit("1000") + .build(); + EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Unsupported_from_chain); + EXPECT_EQ(error, "Unsupported from chain: 0"); } TEST(THORChainSwap, EthInvalidVault) { + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::ETH)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BNB)); + toAsset.set_symbol("BNB"); { - auto res = Swap::build(Chain::ETH, Chain::BNB, Address1Eth, "BNB", "", Address1Bnb, "_INVALID_ADDRESS_", RouterEth, "50000000000000000", "600003"); - EXPECT_EQ(std::get<1>(res), Proto::ErrorCode::Error_Invalid_vault_address); - EXPECT_EQ(std::get<2>(res), "Invalid vault address: _INVALID_ADDRESS_"); + auto && [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Eth) + .toAddress(Address1Bnb) + .vault("_INVALID_ADDRESS_") + .router(RouterEth) + .fromAmount("50000000000000000") + .toAmountLimit("600003") + .build(); + EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Invalid_vault_address); + EXPECT_EQ(error, "Invalid vault address: _INVALID_ADDRESS_"); } { - auto res = Swap::build(Chain::ETH, Chain::BNB, Address1Eth, "BNB", "", Address1Bnb, VaultEth, "_INVALID_ADDRESS_", "50000000000000000", "600003"); - EXPECT_EQ(std::get<1>(res), Proto::ErrorCode::Error_Invalid_router_address); - EXPECT_EQ(std::get<2>(res), "Invalid router address: _INVALID_ADDRESS_"); + auto && [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Eth) + .toAddress(Address1Bnb) + .vault(VaultEth) + .router("_INVALID_ADDRESS_") + .fromAmount("50000000000000000") + .toAmountLimit("600003") + .build(); + EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Invalid_router_address); + EXPECT_EQ(error, "Invalid router address: _INVALID_ADDRESS_"); } } -} // namespace +} // namespace TW::THORChainSwap diff --git a/tests/chains/THORChain/TWSwapTests.cpp b/tests/chains/THORChain/TWSwapTests.cpp index c82b276e299..3d46e960f03 100644 --- a/tests/chains/THORChain/TWSwapTests.cpp +++ b/tests/chains/THORChain/TWSwapTests.cpp @@ -39,7 +39,9 @@ const Data TestKey1Eth = parse_hex("4f96ed80e9a7555a6f74b3d658afdd9c756b0a40d4ca TEST(TWTHORChainSwap, SwapBtcToEth) { // prepare swap input Proto::SwapInput input; - input.set_from_chain(Proto::BTC); + Proto::Asset fromAsset; + fromAsset.set_chain(Proto::BTC); + *input.mutable_from_asset() = fromAsset; input.set_from_address(Address1Btc); Proto::Asset toAsset; toAsset.set_chain(Proto::ETH); @@ -54,7 +56,7 @@ TEST(TWTHORChainSwap, SwapBtcToEth) { // serialize input const auto inputData_ = input.SerializeAsString(); - EXPECT_EQ(hex(inputData_), "0801122a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070381a0708021203455448222a3078623966353737316332373636346266323238326439386530396437663530636563376362303161372a2a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a373a07313030303030304212313430303030303030303030303030303030"); + EXPECT_EQ(hex(inputData_), "0a020801122a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070381a0708021203455448222a3078623966353737316332373636346266323238326439386530396437663530636563376362303161372a2a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a373a07313030303030304212313430303030303030303030303030303030"); const auto inputTWData_ = WRAPD(TWDataCreateWithBytes((const uint8_t *)inputData_.data(), inputData_.size())); // invoke swap @@ -119,7 +121,9 @@ TEST(TWTHORChainSwap, SwapBtcToEth) { TEST(TWTHORChainSwap, SwapEthBnb) { // prepare swap input Proto::SwapInput input; - input.set_from_chain(Proto::ETH); + Proto::Asset fromAsset; + fromAsset.set_chain(Proto::ETH); + *input.mutable_from_asset() = fromAsset; input.set_from_address(Address1Eth); Proto::Asset toAsset; toAsset.set_chain(Proto::BNB); @@ -134,7 +138,7 @@ TEST(TWTHORChainSwap, SwapEthBnb) { // serialize input const auto inputData_ = input.SerializeAsString(); - EXPECT_EQ(hex(inputData_), "0802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a1135303030303030303030303030303030304206363030303033"); + EXPECT_EQ(hex(inputData_), "0a020802122a3078623966353737316332373636346266323238326439386530396437663530636563376362303161371a0708031203424e42222a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372782a2a307831303931633444653661336346303943644130304162444165443432633763334236394338334543322a3078343241354564343536363530613039446331304542633633363141373438306644643631663237423a1135303030303030303030303030303030304206363030303033"); const auto inputTWData_ = WRAPD(TWDataCreateWithBytes((const uint8_t *)inputData_.data(), inputData_.size())); // invoke swap @@ -167,13 +171,15 @@ TEST(TWTHORChainSwap, SwapEthBnb) { // sign and encode resulting input Ethereum::Proto::SigningOutput output; ANY_SIGN(txInput, TWCoinTypeEthereum); - EXPECT_EQ(hex(output.encoded()), "f90151038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b8e41fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003e535741503a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a363030303033000025a06ae104be3201baca38315352f81fac70ca4dd47339981914e64e91149813e780a066a3f0b2c44ddf5a96a38481274f623f552a593d723237d6742185f4885c0064"); + EXPECT_EQ(hex(output.encoded()), "f90151038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b8e41fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003b3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a363030303033000000000026a0669563be8a0022fcd32fdf82ccca7dc66012ea28c57e95a2d9348dbf37afc377a03505f5eb041038c565d2f2888207c9dbcad8ca12f10ce5c5bd2ca41de01a9e89"); } TEST(TWTHORChainSwap, SwapBnbBtc) { // prepare swap input Proto::SwapInput input; - input.set_from_chain(Proto::BNB); + Proto::Asset fromAsset; + fromAsset.set_chain(Proto::BNB); + *input.mutable_from_asset() = fromAsset; input.set_from_address(Address1Bnb); Proto::Asset toAsset; toAsset.set_chain(Proto::BTC); @@ -188,13 +194,13 @@ TEST(TWTHORChainSwap, SwapBnbBtc) { // serialize input const auto inputData_ = input.SerializeAsString(); - EXPECT_EQ(hex(inputData_), "0803122a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372781a0708011203425443222a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070382a2a626e62316e396573787577386361377473386c367736366b64683830307330396d7376756c36766c73653a08313030303030303042083130303030303030"); + EXPECT_EQ(hex(inputData_), "0a020803122a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372781a0708011203425443222a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070382a2a626e62316e396573787577386361377473386c367736366b64683830307330396d7376756c36766c73653a08313030303030303042083130303030303030"); const auto inputTWData_ = WRAPD(TWDataCreateWithBytes((const uint8_t *)inputData_.data(), inputData_.size())); // invoke swap const auto outputTWData_ = WRAPD(TWTHORChainSwapBuildSwap(inputTWData_.get())); const auto outputData = data(TWDataBytes(outputTWData_.get()), TWDataSize(outputTWData_.get())); - EXPECT_EQ(outputData.size(), 149ul); + EXPECT_EQ(outputData.size(), 146ul); // parse result in proto Proto::SwapOutput outputProto; EXPECT_TRUE(outputProto.ParseFromArray(outputData.data(), static_cast(outputData.size()))); @@ -212,7 +218,7 @@ TEST(TWTHORChainSwap, SwapBnbBtc) { // sign and encode resulting input Ethereum::Proto::SigningOutput output; ANY_SIGN(txInput, TWCoinTypeBinance); - EXPECT_EQ(hex(output.encoded()), "8002f0625dee0a4c2a2c87fa0a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e421080ade204126a0a26eb5ae9872103ea4b4bc12dc6f36a28d2c9775e01eef44def32cc70fb54f0e4177b659dbc0e191240af2117ebd42e31a9562738e9f8933b3b54b59e6305b5675956525e4edb6a6ac65abea614e90959ae388664e2b36bf720024879b6047e174e3cff95f8f364a4e71a40535741503a4254432e4254433a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070383a3130303030303030"); + EXPECT_EQ(hex(output.encoded()), "fd01f0625dee0a4c2a2c87fa0a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e421080ade204126a0a26eb5ae9872103ea4b4bc12dc6f36a28d2c9775e01eef44def32cc70fb54f0e4177b659dbc0e19124086d43e9bdf12508a9a1415f5f970dfa5ff5930dee01d922f99779b63190735ba1d69694bda203b6678939a5c1eab0a52ed32bb67864ec7864de37b333533ae0c1a3d3d3a4254432e4254433a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070383a3130303030303030"); } TEST(TWTHORChainSwap, NegativeInvalidInput) { From b8f7f1591f5ee7360af27ded94606bb6a29341fc Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Fri, 25 Nov 2022 08:56:55 +0000 Subject: [PATCH 146/497] [Staking]: add NEAR staking (#2734) --- src/NEAR/Serialization.cpp | 7 +-- src/proto/NEAR.proto | 8 ++-- tests/chains/NEAR/TWAnySignerTests.cpp | 61 ++++++++++++++++++++++++- tests/common/HDWallet/HDWalletTests.cpp | 12 +++++ 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/src/NEAR/Serialization.cpp b/src/NEAR/Serialization.cpp index 9997fc84128..4fe8b43d7db 100644 --- a/src/NEAR/Serialization.cpp +++ b/src/NEAR/Serialization.cpp @@ -24,6 +24,7 @@ static void writeU64(Data& data, uint64_t number) { } static void writeU128(Data& data, const std::string& numberData) { + assert(numberData.size() == 16 && "U128 number should be 16 bytes long"); data.insert(std::end(data), std::begin(numberData), std::end(numberData)); } @@ -107,12 +108,12 @@ static void writeDeleteAccount(Data& data, const Proto::DeleteAccount& deleteAcc static void writeAction(Data& data, const Proto::Action& action) { writeU8(data, action.payload_case() - Proto::Action::kCreateAccount); switch (action.payload_case()) { - case Proto::Action::kTransfer: - writeTransfer(data, action.transfer()); - return; case Proto::Action::kFunctionCall: writeFunctionCall(data, action.function_call()); return; + case Proto::Action::kTransfer: + writeTransfer(data, action.transfer()); + return; case Proto::Action::kStake: writeStake(data, action.stake()); return; diff --git a/src/proto/NEAR.proto b/src/proto/NEAR.proto index a55a9079f94..c557e93ed21 100644 --- a/src/proto/NEAR.proto +++ b/src/proto/NEAR.proto @@ -14,7 +14,7 @@ message PublicKey { // Permissions for a function call message FunctionCallPermission { - // uint128 / little endian byte order + // uint128 / big endian byte order bytes allowance = 1; string receiver_id = 2; @@ -58,19 +58,19 @@ message FunctionCall { // gas uint64 gas = 3; - // uint128 / little endian byte order + // uint128 / big endian byte order bytes deposit = 4; } // Transfer message Transfer { - // amount; uint128 / little endian byte order + // amount; uint128 / big endian byte order bytes deposit = 1; } // Stake message Stake { - // amount; uint128 / little endian byte order + // amount; uint128 / big endian byte order bytes stake = 1; // owner public key diff --git a/tests/chains/NEAR/TWAnySignerTests.cpp b/tests/chains/NEAR/TWAnySignerTests.cpp index afa81ba9a79..3286c0c8475 100644 --- a/tests/chains/NEAR/TWAnySignerTests.cpp +++ b/tests/chains/NEAR/TWAnySignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,6 +8,8 @@ #include "proto/NEAR.pb.h" #include "TestUtilities.h" #include +#include "Base58.h" +#include "Base64.h" #include namespace TW::NEAR { @@ -68,4 +70,61 @@ TEST(TWAnySignerNEAR, SignStake) { ASSERT_EQ(hex(output.hash()), "c8aedbf75fcaa9b663a3959d27f1deae809e1923460791471e5219eafecc4ba8"); } +TEST(TWAnySignerNEAR, SignStakeMainnetReplication) { + auto privateKey = Base58::bitcoin.decode("3BPZ9Qu7CviWD4CeKy3DYbNc4suyuBJYnjhVT2oTRCrfb4CQPiTK5tFVdg8Z3ijozxWoxxt9Y1kwkwPntrcc3dom"); + auto blockHash = parse_hex("e78680996127b7a0f3f2343502e442f24366cba5f79cb72f8bc6d0debb26ce24"); + + // 0.1 with 24 decimal precision in big endian + auto amount = parse_hex("000080f64ae1c7022d15000000000000"); + + Proto::SigningInput input; + input.set_signer_id("b8d5df25047841365008f30fb6b30dd820e9a84d869f05623d114e96831f2fbf"); + input.set_nonce(77701544000004); + input.set_receiver_id("avado.poolv1.near"); + input.set_private_key(privateKey.data(), 32); + input.set_block_hash(blockHash.data(), blockHash.size()); + + auto& action = *input.add_actions(); + auto& call = *action.mutable_function_call(); + call.set_method_name("deposit_and_stake"); + call.set_args("{}"); + call.set_gas(125000000000000); + call.set_deposit(amount.data(), amount.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeNEAR); + + // https://explorer.near.org/transactions/kd7ajFw1CfXB8LiJXvhz5NDS7QpQXkuQraAbhb5MMMq + ASSERT_EQ(Base58::bitcoin.encode(data(output.hash())), "kd7ajFw1CfXB8LiJXvhz5NDS7QpQXkuQraAbhb5MMMq"); + ASSERT_EQ(Base64::encode(data(output.signed_transaction())), "QAAAAGI4ZDVkZjI1MDQ3ODQxMzY1MDA4ZjMwZmI2YjMwZGQ4MjBlOWE4NGQ4NjlmMDU2MjNkMTE0ZTk2ODMxZjJmYmYAzgCT6NK76nb1mB7pToefgkGUHfUe5BKvvr3gW/nq+MgEuu1Mq0YAABEAAABhdmFkby5wb29sdjEubmVhcueGgJlhJ7eg8/I0NQLkQvJDZsul95y3L4vG0N67Js4kAQAAAAIRAAAAZGVwb3NpdF9hbmRfc3Rha2UCAAAAe30A0JjUr3EAAAAAgPZK4ccCLRUAAAAAAAAALNrorr8qTL6u1nlxLpuPa45nFdYmjU96i7CmJP08mVHVzHUaw/bGN30Z3u3o1F2o2yefCBNqO9Ogn9fM25NGCg=="); +} + +TEST(TWAnySignerNEAR, SignUnstakeMainnetReplication) { + auto privateKey = Base58::bitcoin.decode("3BPZ9Qu7CviWD4CeKy3DYbNc4suyuBJYnjhVT2oTRCrfb4CQPiTK5tFVdg8Z3ijozxWoxxt9Y1kwkwPntrcc3dom"); + auto blockHash = Base58::bitcoin.decode("CehJc9uZhqE2m17ZrkqcAog4mxSz6JSvYv1JEK1iBsX9"); + + auto amount = parse_hex("00000000000000000000000000000000"); + + Proto::SigningInput input; + input.set_signer_id("b8d5df25047841365008f30fb6b30dd820e9a84d869f05623d114e96831f2fbf"); + input.set_nonce(77701544000006); + input.set_receiver_id("avado.poolv1.near"); + input.set_private_key(privateKey.data(), 32); + input.set_block_hash(blockHash.data(), blockHash.size()); + + auto& action = *input.add_actions(); + auto& call = *action.mutable_function_call(); + call.set_method_name("unstake_all"); + call.set_args("{}"); + call.set_gas(125000000000000); + call.set_deposit(amount.data(), amount.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeNEAR); + + // https://explorer.near.org/transactions/DH6QAX3TkY6XtkteorvKBoGT5hA5ADkURZdzrbbKRs8P + ASSERT_EQ(Base58::bitcoin.encode(data(output.hash())), "DH6QAX3TkY6XtkteorvKBoGT5hA5ADkURZdzrbbKRs8P"); + ASSERT_EQ(Base64::encode(data(output.signed_transaction())), "QAAAAGI4ZDVkZjI1MDQ3ODQxMzY1MDA4ZjMwZmI2YjMwZGQ4MjBlOWE4NGQ4NjlmMDU2MjNkMTE0ZTk2ODMxZjJmYmYAzgCT6NK76nb1mB7pToefgkGUHfUe5BKvvr3gW/nq+MgGuu1Mq0YAABEAAABhdmFkby5wb29sdjEubmVhcq0YnhRlt+TTtagkoy0qKn56zAfGhE+jkTJW6PR5k5r8AQAAAAILAAAAdW5zdGFrZV9hbGwCAAAAe30A0JjUr3EAAAAAAAAAAAAAAAAAAAAAAAAABaFP0EkfJU3VQZ4QAiTwq9ebWDJ7jx7TxbA+VGH4hwKX3gWnmDHVve+LK7/UbbffjF/y8vn0KrPxdh3ONAG0Ag=="); +} + } // namespace TW::NEAR diff --git a/tests/common/HDWallet/HDWalletTests.cpp b/tests/common/HDWallet/HDWalletTests.cpp index 7430101c7da..3e70073773f 100644 --- a/tests/common/HDWallet/HDWalletTests.cpp +++ b/tests/common/HDWallet/HDWalletTests.cpp @@ -11,6 +11,7 @@ #include "Bitcoin/SegwitAddress.h" #include "Ethereum/Address.h" #include "Hedera/DER.h" +#include "NEAR/Address.h" #include "HexCoding.h" #include "PublicKey.h" #include "Hash.h" @@ -456,5 +457,16 @@ TEST(HDWallet, HederaKey) { } } +TEST(HDWallet, NearKey) { + const auto derivPath = "m/44'/397'/0'"; + HDWallet wallet = HDWallet("owner erupt swamp room swift final allow unaware hint identify figure cotton", ""); + { + const auto privateKey = wallet.getKey(TWCoinTypeNEAR, DerivationPath(derivPath)); + EXPECT_EQ(hex(privateKey.bytes), "35e0d9631bd538d5569266abf6be7a9a403ebfda92ddd49b3268e35360a6c2dd"); + const auto p = privateKey.getPublicKey(TWPublicKeyTypeED25519); + EXPECT_EQ(hex(p.bytes), "b8d5df25047841365008f30fb6b30dd820e9a84d869f05623d114e96831f2fbf"); + EXPECT_EQ(NEAR::Address(p).string(), "b8d5df25047841365008f30fb6b30dd820e9a84d869f05623d114e96831f2fbf"); + } +} } // namespace From f96c62337b357c193703cd7c257c884d5fd1b2c1 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 29 Nov 2022 03:05:52 +0100 Subject: [PATCH 147/497] fix(swift): warning public key (#2766) --- include/TrustWalletCore/TWCoinType.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index d740aa310f5..9033f4ea806 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -21,6 +21,9 @@ TW_EXTERN_C_BEGIN /// Represents a private key. struct TWPrivateKey; +/// Represents a public key. +struct TWPublicKey; + /// Coin type for Level 2 of BIP44. /// /// \see https://github.com/satoshilabs/slips/blob/master/slip-0044.md From 49fdc0055ceb87629f20993d74ad346d6e18d645 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 30 Nov 2022 11:42:09 +0100 Subject: [PATCH 148/497] [SonarCloud]: run only on org branch (#2772) --- .github/workflows/linux-ci-sonarcloud.yml | 71 ++++++++++++----------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/.github/workflows/linux-ci-sonarcloud.yml b/.github/workflows/linux-ci-sonarcloud.yml index fc69a791607..662c53dde90 100644 --- a/.github/workflows/linux-ci-sonarcloud.yml +++ b/.github/workflows/linux-ci-sonarcloud.yml @@ -8,42 +8,43 @@ on: jobs: build: + if: github.event.pull_request.head.repo.fork == false runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 - - name: Install system dependencies - run: | - # build-essential clang-14 libc++-dev libc++abi-dev ruby-full cmake - sudo apt-get update && sudo apt-get install ninja-build lcov llvm-14 clang-tidy-14 libboost-all-dev --fix-missing - - name: Cache internal dependencies - id: internal_cache - uses: actions/cache@v1.1.2 - with: - path: build/local - key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} - - name: Install internal dependencies - run: | - tools/install-dependencies - env: - CC: /usr/bin/clang - CXX: /usr/bin/clang++ - if: steps.internal_cache.outputs.cache-hit != 'true' - - name: Code generation - run: | - tools/generate-files - env: - CC: /usr/bin/clang - CXX: /usr/bin/clang++ - - name: CMake (coverage/clang-tidy/clang-asan) - run: | - cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DTW_CODE_COVERAGE=ON -DTW_ENABLE_CLANG_TIDY=ON -DTW_CLANG_ASAN=ON -GNinja - cat build/compile_commands.json - env: - CC: /usr/bin/clang - CXX: /usr/bin/clang++ - - name: SonarCloud Scan - run: | - ./tools/sonarcloud-analysis - env: + - uses: actions/checkout@v2 + - name: Install system dependencies + run: | + # build-essential clang-14 libc++-dev libc++abi-dev ruby-full cmake + sudo apt-get update && sudo apt-get install ninja-build lcov llvm-14 clang-tidy-14 libboost-all-dev --fix-missing + - name: Cache internal dependencies + id: internal_cache + uses: actions/cache@v1.1.2 + with: + path: build/local + key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} + - name: Install internal dependencies + run: | + tools/install-dependencies + env: + CC: /usr/bin/clang + CXX: /usr/bin/clang++ + if: steps.internal_cache.outputs.cache-hit != 'true' + - name: Code generation + run: | + tools/generate-files + env: + CC: /usr/bin/clang + CXX: /usr/bin/clang++ + - name: CMake (coverage/clang-tidy/clang-asan) + run: | + cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DTW_CODE_COVERAGE=ON -DTW_ENABLE_CLANG_TIDY=ON -DTW_CLANG_ASAN=ON -GNinja + cat build/compile_commands.json + env: + CC: /usr/bin/clang + CXX: /usr/bin/clang++ + - name: SonarCloud Scan + run: | + ./tools/sonarcloud-analysis + env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From 2601c5fcb0d02db416ed77c13f89c3df588dc0f0 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 2 Dec 2022 18:27:24 +0100 Subject: [PATCH 149/497] [ThorSwap]: ERC20 token transfer (#2765) --- src/THORChain/Swap.cpp | 4 +- tests/chains/THORChain/SwapTests.cpp | 64 ++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/THORChain/Swap.cpp b/src/THORChain/Swap.cpp index 3be886ab9a8..829f104ba69 100644 --- a/src/THORChain/Swap.cpp +++ b/src/THORChain/Swap.cpp @@ -195,7 +195,7 @@ SwapBundled SwapBuilder::buildBinance(Proto::Asset fromAsset, uint64_t amount, c SwapBundled SwapBuilder::buildEth(uint64_t amount, const std::string& memo) { Data out; auto input = Ethereum::Proto::SigningInput(); - const auto& toTokenId = mToAsset.token_id(); + const auto& toTokenId = mFromAsset.token_id(); // some sanity check / address conversion Data vaultAddressBin = ethAddressStringToData(mVaultAddress); if (!Ethereum::Address::isValid(mVaultAddress) || vaultAddressBin.size() != Ethereum::Address::size) { @@ -228,7 +228,7 @@ SwapBundled SwapBuilder::buildEth(uint64_t amount, const std::string& memo) { Data payload; func.encode(payload); transfer.set_data(payload.data(), payload.size()); - Data amountData = store(uint256_t(amount)); + Data amountData = store(toTokenId.empty() ? uint256_t(amount) : uint256_t(0)); transfer.set_amount(amountData.data(), amountData.size()); auto serialized = input.SerializeAsString(); diff --git a/tests/chains/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp index fb23e1f3a32..591ed6b9e07 100644 --- a/tests/chains/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -191,6 +191,70 @@ Data SwapTest_ethAddressStringToData(const std::string& asString) { return asData; } +TEST(THORChainSwap, SwapErc20Rune) { + Proto::Asset fromAsset; + fromAsset.set_token_id("0xdAC17F958D2ee523a2206206994597C13D831ec7"); + fromAsset.set_chain(static_cast(Chain::ETH)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::THOR)); + toAsset.set_symbol("RUNE"); + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress("0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37") + .toAddress("thor1du84c7fj5y7kphq7zfyp8ugwxgrmy6n07xm9yj") + .vault("0x97673DF37E718dF203A834Bd095F69F6b4F314FA") + .router("0xD37BbE5744D730a1d98d8DC97c42F0Ca46aD7146") + .fromAmount("5000000") + .toAmountLimit("418410520") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "0a01001201002201002a0100422a307844333742624535373434443733306131643938643844433937633432463043613436614437313436528d02328a020a01001284021fece7b400000000000000000000000097673df37e718df203a834bd095f69f6b4f314fa000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000413d3a54484f522e52554e453a74686f7231647538346337666a3579376b706871377a667970387567777867726d79366e3037786d39796a3a34313834313035323000000000000000000000000000000000000000000000000000000000000000"); + + auto tx = Ethereum::Proto::SigningInput(); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); + + // check fields + EXPECT_EQ(tx.to_address(), "0xD37BbE5744D730a1d98d8DC97c42F0Ca46aD7146"); + ASSERT_TRUE(tx.transaction().has_contract_generic()); + + Data vaultAddressBin = SwapTest_ethAddressStringToData("0x97673DF37E718dF203A834Bd095F69F6b4F314FA"); + EXPECT_EQ(hex(vaultAddressBin), "97673df37e718df203a834bd095f69f6b4f314fa"); + auto func = Ethereum::ABI::Function("deposit", std::vector>{ + std::make_shared(vaultAddressBin), + std::make_shared(parse_hex("0xdAC17F958D2ee523a2206206994597C13D831ec7")), + std::make_shared(uint256_t(5000000)), + std::make_shared("=:THOR.RUNE:thor1du84c7fj5y7kphq7zfyp8ugwxgrmy6n07xm9yj:418410520")}); + Data payload; + func.encode(payload); + EXPECT_EQ(hex(payload), "1fece7b400000000000000000000000097673df37e718df203a834bd095f69f6b4f314fa000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000413d3a54484f522e52554e453a74686f7231647538346337666a3579376b706871377a667970387567777867726d79366e3037786d39796a3a34313834313035323000000000000000000000000000000000000000000000000000000000000000"); + EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().amount())), "00"); + EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().data())), hex(payload)); + + EXPECT_EQ(hex(TW::data(tx.private_key())), ""); + + // set few fields before signing + auto chainId = store(uint256_t(1)); + tx.set_chain_id(chainId.data(), chainId.size()); + auto nonce = store(uint256_t(7)); + tx.set_nonce(nonce.data(), nonce.size()); + auto gasPrice = store(uint256_t(30000000000)); + tx.set_gas_price(gasPrice.data(), gasPrice.size()); + auto gasLimit = store(uint256_t(80000)); + tx.set_gas_limit(gasLimit.data(), gasLimit.size()); + auto privKey = parse_hex("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d"); + tx.set_private_key(privKey.data(), privKey.size()); + + // sign and encode resulting input + Ethereum::Proto::SigningOutput output; + ANY_SIGN(tx, TWCoinTypeEthereum); + EXPECT_EQ(hex(output.encoded()), "f9016b078506fc23ac008301388094d37bbe5744d730a1d98d8dc97c42f0ca46ad714680b901041fece7b400000000000000000000000097673df37e718df203a834bd095f69f6b4f314fa000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000413d3a54484f522e52554e453a74686f7231647538346337666a3579376b706871377a667970387567777867726d79366e3037786d39796a3a3431383431303532300000000000000000000000000000000000000000000000000000000000000026a03b9082870fda839820dd36d4da3d8985807c799a8cf8e1971374a461da5899a7a0383d9ceaacf6c90205d4381b403687c17c2bbfaac1c1329ac65c0ce22d940451"); + // https://viewblock.io/thorchain/tx/56D2A63608E6EC09FA1D2934457CC09196683013905F69EDFC72B33EC68681AA + // https://etherscan.io/tx/0x56d2a63608e6ec09fa1d2934457cc09196683013905f69edfc72b33ec68681aa + // https://viewblock.io/thorchain/tx/BC1464CF3B56B07E40CF57985511814AEC9EAE2F1329CEE059A21529FDDFDB8C +} + TEST(THORChainSwap, SwapEthBnb) { Proto::Asset fromAsset; fromAsset.set_chain(static_cast(Chain::ETH)); From 537c82e71c59b3ba9f0c2f788014a1cab42feea3 Mon Sep 17 00:00:00 2001 From: Tom Langer Date: Mon, 5 Dec 2022 03:19:46 +0200 Subject: [PATCH 150/497] Support for Secret Network (#2767) * update registry * CoinTypeTests * Update SignerTests.cpp * Update TWAnySignerTests.cpp * Fix tests to match the deterministic signature * fix signature test Co-authored-by: Cashmaney --- .../blockchains/CoinAddressDerivationTests.kt | 1 + .../blockchains/secret/TestSecretAddress.kt | 31 ++++++++ .../blockchains/secret/TestSecretSigner.kt | 77 +++++++++++++++++++ docs/registry.md | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 32 ++++++++ swift/Tests/Blockchains/SecretTests.swift | 63 +++++++++++++++ swift/Tests/CoinAddressDerivationTests.swift | 3 + tests/chains/Secret/AddressTests.cpp | 47 +++++++++++ tests/chains/Secret/SignerTests.cpp | 59 ++++++++++++++ tests/chains/Secret/TWAnyAddressTests.cpp | 28 +++++++ tests/chains/Secret/TWAnySignerTests.cpp | 56 ++++++++++++++ tests/chains/Secret/TWCoinTypeTests.cpp | 37 +++++++++ tests/common/CoinAddressDerivationTests.cpp | 3 + tests/interface/TWHRPTests.cpp | 3 + 15 files changed, 442 insertions(+) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretAddress.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretSigner.kt create mode 100644 swift/Tests/Blockchains/SecretTests.swift create mode 100644 tests/chains/Secret/AddressTests.cpp create mode 100644 tests/chains/Secret/SignerTests.cpp create mode 100644 tests/chains/Secret/TWAnyAddressTests.cpp create mode 100644 tests/chains/Secret/TWAnySignerTests.cpp create mode 100644 tests/chains/Secret/TWCoinTypeTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index ddd2c1dd86c..8d60a752d44 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -107,5 +107,6 @@ class CoinAddressDerivationTests { EVERSCALE -> assertEquals("0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04", address) APTOS -> assertEquals("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", address) HEDERA -> assertEquals("0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5", address) + SECRET -> assertEquals("secret1f69sk5033zcdr2p2yf3xjehn7xvgdeq09d2llh", address) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretAddress.kt new file mode 100644 index 00000000000..26d66ee5883 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretAddress.kt @@ -0,0 +1,31 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.secret + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestSecretAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("87201512d132ef7a1e57f9e24905fbc24300bd73f676b5716182be5f3e39dada".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(true) + val address = AnyAddress(pubkey, CoinType.SECRET) + val expected = AnyAddress("secret18mdrja40gfuftt5yx6tgj0fn5lurplezyp894y", CoinType.SECRET) + + assertEquals(pubkey.data().toHex(), "0x02466ac5d28cb4fab6c349060c6c1619e8d301e7741fb6b33cc1edac25f45d8646") + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretSigner.kt new file mode 100644 index 00000000000..2c25e3601da --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/secret/TestSecretSigner.kt @@ -0,0 +1,77 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.secret + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType.SECRET +import wallet.core.jni.proto.Cosmos +import wallet.core.jni.proto.Cosmos.SigningOutput +import wallet.core.jni.proto.Cosmos.SigningMode +import wallet.core.jni.* + +class TestSecretSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun SecretTransactionSigning() { + val key = PrivateKey("87201512d132ef7a1e57f9e24905fbc24300bd73f676b5716182be5f3e39dada".toHexByteArray()) + val publicKey = key.getPublicKeySecp256k1(true) + val from = AnyAddress(publicKey, SECRET).description() + + val txAmount = Cosmos.Amount.newBuilder().apply { + amount = "100000" + denom = "uscrt" + }.build() + + val sendCoinsMsg = Cosmos.Message.Send.newBuilder().apply { + fromAddress = from + toAddress = "secret1rnq6hjfnalxeef87rmdeya3nu9dhpc7k9pujs3" + addAllAmounts(listOf(txAmount)) + }.build() + + val message = Cosmos.Message.newBuilder().apply { + sendCoinsMessage = sendCoinsMsg + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "2500" + denom = "uscrt" + }.build() + + val secretFee = Cosmos.Fee.newBuilder().apply { + gas = 25000 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = SigningMode.Protobuf + accountNumber = 265538 + chainId = "secret-4" + memo = "" + sequence = 1 + fee = secretFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, SECRET, SigningOutput.parser()) + + assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CpIBCo8BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm8KLXNlY3JldDE4bWRyamE0MGdmdWZ0dDV5eDZ0Z2owZm41bHVycGxlenlwODk0eRItc2VjcmV0MXJucTZoamZuYWx4ZWVmODdybWRleWEzbnU5ZGhwYzdrOXB1anMzGg8KBXVzY3J0EgYxMDAwMDASZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAkZqxdKMtPq2w0kGDGwWGejTAed0H7azPMHtrCX0XYZGEgQKAggBGAESEwoNCgV1c2NydBIEMjUwMBCowwEaQOcHd2gHpa5WKZ/5RRerEtrHlyDlojIEzUGhC9xMFgs7UQMWy+kTTN+NRf7zQ8rx3cPkIKeZhv0u1KRc8uRCc4o=\"}") + assertEquals(output.error, "") + } +} diff --git a/docs/registry.md b/docs/registry.md index a1cecf40e66..b5ca89f1dbe 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -50,6 +50,7 @@ This list is generated from [./registry.json](../registry.json) | 500 | Theta | THETA | | | | 501 | Solana | SOL | | | | 508 | Elrond | eGLD | | | +| 529 | Secret | SCRT | | | | 637 | Aptos | APT | | | | 714 | BNB Beacon Chain | BNB | | | | 818 | VeChain | VET | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 9033f4ea806..aaf37364468 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -125,6 +125,7 @@ enum TWCoinType { TWCoinTypeEverscale = 396, TWCoinTypeAptos = 637, TWCoinTypeHedera = 3030, + TWCoinTypeSecret = 529, }; /// Returns the blockchain for a coin type. diff --git a/registry.json b/registry.json index d2dcc9d2b74..d2279f7144a 100644 --- a/registry.json +++ b/registry.json @@ -2344,6 +2344,38 @@ "clientDocs": "https://eth.wiki/json-rpc/API" } }, + { + "id": "secret", + "name": "Secret", + "displayName": "Secret", + "coinId": 529, + "symbol": "SCRT", + "decimals": 6, + "blockchain": "Cosmos", + "derivation": [ + { + "path": "m/44'/529'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "secret", + "chainId": "secret-4", + "addressHasher": "sha256ripemd", + "explorer": { + "url": "https://mintscan.io/secret", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "026B4886B1D9CE836A99755DDE99D4F8A7748D27B1CE9D298A763B1CFFF62C00", + "sampleAccount": "secret167m3s89ddurjpyr82vsluvvj0t8ylzn95trrqy" + }, + "info": { + "url": "https://scrt.network/", + "source": "https://github.com/scrtlabs/SecretNetwork", + "rpc": "https://scrt-rpc.blockpane.com/", + "documentation": "https://docs.scrt.network/" + } + }, { "id": "osmosis", "name": "Osmosis", diff --git a/swift/Tests/Blockchains/SecretTests.swift b/swift/Tests/Blockchains/SecretTests.swift new file mode 100644 index 00000000000..5abd8ff81b9 --- /dev/null +++ b/swift/Tests/Blockchains/SecretTests.swift @@ -0,0 +1,63 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import WalletCore +import XCTest + +class SecretTests: XCTestCase { + func testAddress() { + let key = PrivateKey(data: Data(hexString: "87201512d132ef7a1e57f9e24905fbc24300bd73f676b5716182be5f3e39dada")!)! + let pubkey = key.getPublicKeySecp256k1(compressed: true) + let address = AnyAddress(publicKey: pubkey, coin: .secret) + let addressFromString = AnyAddress(string: "secret18mdrja40gfuftt5yx6tgj0fn5lurplezyp894y", coin: .secret)! + + XCTAssertEqual(pubkey.data.hexString, "02466ac5d28cb4fab6c349060c6c1619e8d301e7741fb6b33cc1edac25f45d8646") + XCTAssertEqual(address.description, addressFromString.description) + } + + func testSigningTransaction() { + let privateKey = PrivateKey(data: Data(hexString: "87201512d132ef7a1e57f9e24905fbc24300bd73f676b5716182be5f3e39dada")!)! + let publicKey = privateKey.getPublicKeySecp256k1(compressed: true) + let fromAddress = AnyAddress(publicKey: publicKey, coin: .secret) + + let sendCoinsMessage = CosmosMessage.Send.with { + $0.fromAddress = fromAddress.description + $0.toAddress = "secret1rnq6hjfnalxeef87rmdeya3nu9dhpc7k9pujs3" + $0.amounts = [CosmosAmount.with { + $0.amount = "100000" + $0.denom = "uscrt" + }] + } + + let message = CosmosMessage.with { + $0.sendCoinsMessage = sendCoinsMessage + } + + let fee = CosmosFee.with { + $0.gas = 25000 + $0.amounts = [CosmosAmount.with { + $0.amount = "2500" + $0.denom = "uscrt" + }] + } + + let input = CosmosSigningInput.with { + $0.signingMode = .protobuf; + $0.accountNumber = 265538 + $0.chainID = "secret-4" + $0.memo = "" + $0.sequence = 1 + $0.messages = [message] + $0.fee = fee + $0.privateKey = privateKey.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .secret) + + XCTAssertJSONEqual(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CpIBCo8BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm8KLXNlY3JldDE4bWRyamE0MGdmdWZ0dDV5eDZ0Z2owZm41bHVycGxlenlwODk0eRItc2VjcmV0MXJucTZoamZuYWx4ZWVmODdybWRleWEzbnU5ZGhwYzdrOXB1anMzGg8KBXVzY3J0EgYxMDAwMDASZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAkZqxdKMtPq2w0kGDGwWGejTAed0H7azPMHtrCX0XYZGEgQKAggBGAESEwoNCgV1c2NydBIEMjUwMBCowwEaQOcHd2gHpa5WKZ/5RRerEtrHlyDlojIEzUGhC9xMFgs7UQMWy+kTTN+NRf7zQ8rx3cPkIKeZhv0u1KRc8uRCc4o=\"}") + XCTAssertEqual(output.error, "") + } +} diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 83311e02ca9..081a61cae55 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -259,6 +259,9 @@ class CoinAddressDerivationTests: XCTestCase { case .hedera: let expectedResult = "0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5"; assertCoinDerivation(coin, expectedResult, derivedAddress, address) + case .secret: + let expectedResult = "secret1f69sk5033zcdr2p2yf3xjehn7xvgdeq09d2llh" + assertCoinDerivation(coin, expectedResult, derivedAddress, address) @unknown default: fatalError() diff --git a/tests/chains/Secret/AddressTests.cpp b/tests/chains/Secret/AddressTests.cpp new file mode 100644 index 00000000000..0295179e533 --- /dev/null +++ b/tests/chains/Secret/AddressTests.cpp @@ -0,0 +1,47 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "Cosmos/Address.h" +#include "PublicKey.h" +#include "PrivateKey.h" +#include +#include + +namespace TW::Cosmos::tests { + +TEST(SecretAddress, Valid) { + ASSERT_TRUE(Address::isValid(TWCoinTypeSecret, "secret16vw3fp7x35tzmwlkdkyzr8vgscn0zewtduyjuf")); + ASSERT_TRUE(Address::isValid(TWCoinTypeSecret, "secret15rgv8teecnt53h0gdvngzt3am3yuz3rxh4fnle")); + ASSERT_TRUE(Address::isValid(TWCoinTypeSecret, "secret1pjp5dpvrjumn653dycszk3g264zgqusz2xhdq7")); +} + +TEST(SecretAddress, Invalid) { + ASSERT_FALSE(Address::isValid(TWCoinTypeSecret, "secret15rgv8teecnt53h0gdvngzt3am3yuz3rxh4fnla")); + ASSERT_FALSE(Address::isValid(TWCoinTypeSecret, "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02")); // valid cosmos +} + +TEST(SecretAddress, FromPrivateKey) { + auto privateKey = PrivateKey(parse_hex("92ded9fb8b4646b66d0c127fa38523133ce11bdc5dadee2d5fc1c0ccd9fec664")); + auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); + auto address = Address(TWCoinTypeSecret, publicKey); + ASSERT_EQ(address.string(), "secret16vw3fp7x35tzmwlkdkyzr8vgscn0zewtduyjuf"); +} + +TEST(SecretAddress, FromPublicKey) { + auto publicKey = PublicKey(parse_hex("0250bba49f3d5a574b38de891387420877de10fd44de609567d5e6e0c97bfa4bb2"), TWPublicKeyTypeSECP256k1); + auto address = Address(TWCoinTypeSecret, publicKey); + ASSERT_EQ(address.string(), "secret16vw3fp7x35tzmwlkdkyzr8vgscn0zewtduyjuf"); +} + +TEST(SecretAddress, FromString) { + Address address; + EXPECT_TRUE(Address::decode("secret16vw3fp7x35tzmwlkdkyzr8vgscn0zewtduyjuf", address)); + EXPECT_EQ(address.string(), "secret16vw3fp7x35tzmwlkdkyzr8vgscn0zewtduyjuf"); + EXPECT_EQ(hex(address.getKeyHash()), "d31d1487c68d162dbbf66d88219d888626f165cb"); +} + +} // namespace TW::Cosmos::tests diff --git a/tests/chains/Secret/SignerTests.cpp b/tests/chains/Secret/SignerTests.cpp new file mode 100644 index 00000000000..5bb99917be6 --- /dev/null +++ b/tests/chains/Secret/SignerTests.cpp @@ -0,0 +1,59 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Cosmos/Address.h" +#include "Cosmos/Signer.h" +#include "HexCoding.h" +#include "PrivateKey.h" +#include "PublicKey.h" +#include "TestUtilities.h" + +#include + +namespace TW::Cosmos::tests { + +TEST(SecretSigner, Sign) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(265538); + input.set_chain_id("secret-4"); + input.set_memo(""); + input.set_sequence(1); + + Address fromAddress; + Address toAddress; + EXPECT_TRUE(Address::decode("secret18mdrja40gfuftt5yx6tgj0fn5lurplezyp894y", fromAddress)); + EXPECT_TRUE(Address::decode("secret1rnq6hjfnalxeef87rmdeya3nu9dhpc7k9pujs3", toAddress)); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_send_coins_message(); + message.set_from_address(fromAddress.string()); + message.set_to_address(toAddress.string()); + auto amountOfTx = message.add_amounts(); + amountOfTx->set_denom("uscrt"); + amountOfTx->set_amount("100000"); + + auto& fee = *input.mutable_fee(); + fee.set_gas(25000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uscrt"); + amountOfFee->set_amount("2500"); + + auto privateKey = parse_hex("87201512d132ef7a1e57f9e24905fbc24300bd73f676b5716182be5f3e39dada"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeSecret); + + // https://www.mintscan.io/secret/txs/01F4BD2458BF966F287533775C8D67BBC7CA7214CAEB1752D270A90223E9E82F + // curl -H 'Content-Type: application/json' --data-binary "{\"tx_bytes\":\"CpIB...c4o=\",\"mode\":\"BROADCAST_MODE_BLOCK\"}" https://scrt-lcd.blockpane.com/cosmos/tx/v1beta1/txs + + assertJSONEqual(output.serialized(), "{\"tx_bytes\":\"CpIBCo8BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm8KLXNlY3JldDE4bWRyamE0MGdmdWZ0dDV5eDZ0Z2owZm41bHVycGxlenlwODk0eRItc2VjcmV0MXJucTZoamZuYWx4ZWVmODdybWRleWEzbnU5ZGhwYzdrOXB1anMzGg8KBXVzY3J0EgYxMDAwMDASZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAkZqxdKMtPq2w0kGDGwWGejTAed0H7azPMHtrCX0XYZGEgQKAggBGAESEwoNCgV1c2NydBIEMjUwMBCowwEaQOcHd2gHpa5WKZ/5RRerEtrHlyDlojIEzUGhC9xMFgs7UQMWy+kTTN+NRf7zQ8rx3cPkIKeZhv0u1KRc8uRCc4o=\",\"mode\":\"BROADCAST_MODE_BLOCK\"}"); + EXPECT_EQ(hex(output.signature()), "e707776807a5ae56299ff94517ab12dac79720e5a23204cd41a10bdc4c160b3b510316cbe9134cdf8d45fef343caf1ddc3e420a79986fd2ed4a45cf2e442738a"); + EXPECT_EQ(output.error(), ""); + EXPECT_EQ(output.json(), ""); +} + +} // namespace TW::Cosmos::tests diff --git a/tests/chains/Secret/TWAnyAddressTests.cpp b/tests/chains/Secret/TWAnyAddressTests.cpp new file mode 100644 index 00000000000..073fb314437 --- /dev/null +++ b/tests/chains/Secret/TWAnyAddressTests.cpp @@ -0,0 +1,28 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include "HexCoding.h" + +#include "TestUtilities.h" +#include + +using namespace TW; + +TEST(TWSecretAnyAddress, IsValid) { + EXPECT_TRUE(TWAnyAddressIsValid(STRING("secret16vw3fp7x35tzmwlkdkyzr8vgscn0zewtduyjuf").get(), TWCoinTypeSecret)); + EXPECT_TRUE(TWAnyAddressIsValid(STRING("secret15rgv8teecnt53h0gdvngzt3am3yuz3rxh4fnle").get(), TWCoinTypeSecret)); + EXPECT_FALSE(TWAnyAddressIsValid(STRING("cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02").get(), TWCoinTypeSecret)); +} + +TEST(TWSecretAnyAddress, Create) { + auto string = STRING("secret16vw3fp7x35tzmwlkdkyzr8vgscn0zewtduyjuf"); + auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithString(string.get(), TWCoinTypeSecret)); + auto string2 = WRAPS(TWAnyAddressDescription(addr.get())); + EXPECT_TRUE(TWStringEqual(string.get(), string2.get())); + auto keyHash = WRAPD(TWAnyAddressData(addr.get())); + assertHexEqual(keyHash, "d31d1487c68d162dbbf66d88219d888626f165cb"); +} diff --git a/tests/chains/Secret/TWAnySignerTests.cpp b/tests/chains/Secret/TWAnySignerTests.cpp new file mode 100644 index 00000000000..26063c58b5a --- /dev/null +++ b/tests/chains/Secret/TWAnySignerTests.cpp @@ -0,0 +1,56 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Cosmos/Address.h" +#include "HexCoding.h" +#include "proto/Cosmos.pb.h" +#include + +#include "TestUtilities.h" +#include + +namespace TW::Cosmos::tests { + +TEST(TWAnySignerSecret, Sign) { + auto privateKey = parse_hex("87201512d132ef7a1e57f9e24905fbc24300bd73f676b5716182be5f3e39dada"); + Proto::SigningInput input; + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(265538); + input.set_chain_id("secret-4"); + input.set_memo(""); + input.set_sequence(1); + input.set_private_key(privateKey.data(), privateKey.size()); + + Address fromAddress; + Address toAddress; + EXPECT_TRUE(Address::decode("secret18mdrja40gfuftt5yx6tgj0fn5lurplezyp894y", fromAddress)); + EXPECT_TRUE(Address::decode("secret1rnq6hjfnalxeef87rmdeya3nu9dhpc7k9pujs3", toAddress)); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_send_coins_message(); + message.set_from_address(fromAddress.string()); + message.set_to_address(toAddress.string()); + auto amountOfTx = message.add_amounts(); + amountOfTx->set_denom("uscrt"); + amountOfTx->set_amount("100000"); + + auto& fee = *input.mutable_fee(); + fee.set_gas(25000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("uscrt"); + amountOfFee->set_amount("2500"); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeSecret); + + // https://www.mintscan.io/secret/txs/01F4BD2458BF966F287533775C8D67BBC7CA7214CAEB1752D270A90223E9E82F + assertJSONEqual(output.serialized(), "{\"tx_bytes\":\"CpIBCo8BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm8KLXNlY3JldDE4bWRyamE0MGdmdWZ0dDV5eDZ0Z2owZm41bHVycGxlenlwODk0eRItc2VjcmV0MXJucTZoamZuYWx4ZWVmODdybWRleWEzbnU5ZGhwYzdrOXB1anMzGg8KBXVzY3J0EgYxMDAwMDASZwpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAkZqxdKMtPq2w0kGDGwWGejTAed0H7azPMHtrCX0XYZGEgQKAggBGAESEwoNCgV1c2NydBIEMjUwMBCowwEaQOcHd2gHpa5WKZ/5RRerEtrHlyDlojIEzUGhC9xMFgs7UQMWy+kTTN+NRf7zQ8rx3cPkIKeZhv0u1KRc8uRCc4o=\",\"mode\":\"BROADCAST_MODE_BLOCK\"}"); + EXPECT_EQ(hex(output.signature()), "e707776807a5ae56299ff94517ab12dac79720e5a23204cd41a10bdc4c160b3b510316cbe9134cdf8d45fef343caf1ddc3e420a79986fd2ed4a45cf2e442738a"); + EXPECT_EQ(output.json(), ""); + EXPECT_EQ(output.error(), ""); +} + +} // namespace TW::Cosmos::tests diff --git a/tests/chains/Secret/TWCoinTypeTests.cpp b/tests/chains/Secret/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..62401fe8656 --- /dev/null +++ b/tests/chains/Secret/TWCoinTypeTests.cpp @@ -0,0 +1,37 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "TestUtilities.h" +#include +#include + + +TEST(TWSecretCoinType, TWCoinType) { + const auto coin = TWCoinTypeSecret; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto chainId = WRAPS(TWCoinTypeChainId(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("026B4886B1D9CE836A99755DDE99D4F8A7748D27B1CE9D298A763B1CFFF62C00")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("secret167m3s89ddurjpyr82vsluvvj0t8ylzn95trrqy")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "secret"); + assertStringsEqual(name, "Secret"); + assertStringsEqual(symbol, "SCRT"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 6); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainCosmos); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); + assertStringsEqual(chainId, "secret-4"); + assertStringsEqual(txUrl, "https://mintscan.io/secret/txs/026B4886B1D9CE836A99755DDE99D4F8A7748D27B1CE9D298A763B1CFFF62C00"); + assertStringsEqual(accUrl, "https://mintscan.io/secret/account/secret167m3s89ddurjpyr82vsluvvj0t8ylzn95trrqy"); +} diff --git a/tests/common/CoinAddressDerivationTests.cpp b/tests/common/CoinAddressDerivationTests.cpp index eacfaa549e9..be0e69bce0a 100644 --- a/tests/common/CoinAddressDerivationTests.cpp +++ b/tests/common/CoinAddressDerivationTests.cpp @@ -255,6 +255,9 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeHedera: EXPECT_EQ(address, "0.0.302a300506032b6570032100ee93a4f66f8d16b819bb9beb9ffccdfcdc1412e87fee6a324c2a99a1e0e67148"); break; + case TWCoinTypeSecret: + EXPECT_EQ(address, "secret1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0m7t23a"); + break; // no default branch here, intentionally, to better notice any missing coins } } diff --git a/tests/interface/TWHRPTests.cpp b/tests/interface/TWHRPTests.cpp index a24bda956ff..22195dcd3e0 100644 --- a/tests/interface/TWHRPTests.cpp +++ b/tests/interface/TWHRPTests.cpp @@ -35,6 +35,7 @@ TEST(TWHRP, StringForHRP) { ASSERT_STREQ(stringForHRP(TWHRPTHORChain), "thor"); ASSERT_STREQ(stringForHRP(TWHRPCryptoOrg), "cro"); ASSERT_STREQ(stringForHRP(TWHRPOsmosis), "osmo"); + ASSERT_STREQ(stringForHRP(TWHRPSecret), "secret"); } TEST(TWHRP, HRPForString) { @@ -62,6 +63,7 @@ TEST(TWHRP, HRPForString) { ASSERT_EQ(hrpForString("cro"), TWHRPCryptoOrg); ASSERT_EQ(hrpForString("osmo"), TWHRPOsmosis); ASSERT_EQ(hrpForString("ecash"), TWHRPECash); + ASSERT_EQ(hrpForString("secret"), TWHRPSecret); } TEST(TWHPR, HPRByCoinType) { @@ -88,6 +90,7 @@ TEST(TWHPR, HPRByCoinType) { ASSERT_EQ(TWHRPCryptoOrg, TWCoinTypeHRP(TWCoinTypeCryptoOrg)); ASSERT_EQ(TWHRPOsmosis, TWCoinTypeHRP(TWCoinTypeOsmosis)); ASSERT_EQ(TWHRPECash, TWCoinTypeHRP(TWCoinTypeECash)); + ASSERT_EQ(TWHRPSecret, TWCoinTypeHRP(TWCoinTypeSecret)); ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeAion)); ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeCallisto)); From f77d528d17020c97b15f59d9578776d3899220b5 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 5 Dec 2022 13:14:56 +0100 Subject: [PATCH 151/497] [Bindgen]: Add rust wallet core rust library + Aptos blind signing (#2706) --- .github/workflows/android-ci.yml | 4 +- .github/workflows/ios-ci.yml | 3 +- .github/workflows/linux-ci.yml | 4 +- .github/workflows/linux-sampleapp-ci.yml | 3 +- .github/workflows/wasm-ci.yml | 5 +- CMakeLists.txt | 19 +- .../app/blockchains/aptos/TestAptosSigner.kt | 48 + rust/.gitignore | 7 + rust/Cargo.lock | 224 ++++ rust/Cargo.toml | 17 + rust/src/lib.rs | 8 + rust/src/memory/mod.rs | 30 + rust/src/move_parser/mod.rs | 87 ++ samples/cpp/CMakeLists.txt | 2 +- samples/go/core/bitcoin.go | 2 +- samples/go/core/coin.go | 2 +- samples/go/core/datavector.go | 2 +- samples/go/core/mnemonic.go | 2 +- samples/go/core/publicKey.go | 2 +- samples/go/core/transaction.go | 2 +- samples/go/core/transactionHelper.go | 2 +- samples/go/core/wallet.go | 2 +- samples/go/dev-console/native/cgo.go | 2 +- samples/go/dev-console/prepare.sh | 3 +- samples/go/protos/binance/Binance.pb.go | 990 +++++++++--------- samples/go/protos/bitcoin/Bitcoin.pb.go | 313 ++---- samples/go/protos/common/Common.pb.go | 147 +-- samples/go/protos/ethereum/Ethereum.pb.go | 77 +- .../TransactionCompiler.pb.go | 24 +- samples/go/sample/external_signing.go | 14 +- samples/go/types/twdata.go | 2 +- samples/go/types/twstring.go | 2 +- samples/rust/src/build.rs | 3 +- src/Aptos/Signer.cpp | 49 +- src/Aptos/TransactionPayload.cpp | 62 ++ src/Aptos/TransactionPayload.h | 1 + src/rust/bindgen/.gitignore | 1 + swift/.gitignore | 1 + swift/Tests/Blockchains/AptosTests.swift | 36 + swift/common-xcframework.yml | 4 +- swift/fastlane/Fastfile | 6 +- swift/project.yml | 4 +- tests/chains/Aptos/SignerTests.cpp | 63 ++ .../common/rust/bindgen/WalletCoreRsTests.cpp | 16 + tools/generate-files | 4 + tools/install-rust-dependencies | 24 + tools/install-sys-dependencies-linux | 6 + tools/install-sys-dependencies-mac | 5 + tools/ios-build | 3 +- tools/ios-doc | 2 +- tools/rust-bindgen | 43 + 51 files changed, 1529 insertions(+), 855 deletions(-) create mode 100644 rust/.gitignore create mode 100644 rust/Cargo.lock create mode 100644 rust/Cargo.toml create mode 100644 rust/src/lib.rs create mode 100644 rust/src/memory/mod.rs create mode 100644 rust/src/move_parser/mod.rs rename samples/go/protos/{common => transactioncompiler}/TransactionCompiler.pb.go (87%) create mode 100644 src/rust/bindgen/.gitignore create mode 100644 tests/common/rust/bindgen/WalletCoreRsTests.cpp create mode 100755 tools/install-rust-dependencies create mode 100755 tools/install-sys-dependencies-linux create mode 100755 tools/install-sys-dependencies-mac create mode 100755 tools/rust-bindgen diff --git a/.github/workflows/android-ci.yml b/.github/workflows/android-ci.yml index 3dfe3e5b9f0..5203adc04dc 100644 --- a/.github/workflows/android-ci.yml +++ b/.github/workflows/android-ci.yml @@ -19,7 +19,9 @@ jobs: java-version: 11 - name: Install system dependencies - run: brew install boost ninja + run: | + tools/install-sys-dependencies-mac + tools/install-rust-dependencies - name: Install Android Dependencies run: tools/install-android-dependencies diff --git a/.github/workflows/ios-ci.yml b/.github/workflows/ios-ci.yml index a7078f649e3..61813885a4d 100644 --- a/.github/workflows/ios-ci.yml +++ b/.github/workflows/ios-ci.yml @@ -13,7 +13,8 @@ jobs: - uses: actions/checkout@v2 - name: Install system dependencies run: | - brew install boost ninja xcodegen xcbeautify + tools/install-sys-dependencies-mac + tools/install-rust-dependencies - name: Cache internal dependencies id: internal_cache uses: actions/cache@v1.1.2 diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index bed1b725444..5bef8727e51 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -13,8 +13,8 @@ jobs: - uses: actions/checkout@v2 - name: Install system dependencies run: | - # build-essential clang-14 libc++-dev libc++abi-dev ruby-full cmake - sudo apt-get update && sudo apt-get install ninja-build lcov llvm-14 clang-tidy-14 libboost-all-dev --fix-missing + tools/install-sys-dependencies-linux + tools/install-rust-dependencies - name: Cache internal dependencies id: internal_cache uses: actions/cache@v1.1.2 diff --git a/.github/workflows/linux-sampleapp-ci.yml b/.github/workflows/linux-sampleapp-ci.yml index 67bbec223ee..7ed0fdcbbb0 100644 --- a/.github/workflows/linux-sampleapp-ci.yml +++ b/.github/workflows/linux-sampleapp-ci.yml @@ -13,7 +13,8 @@ jobs: - uses: actions/checkout@v2 - name: Install system dependencies run: | - sudo apt-get update && sudo apt-get install ninja-build llvm-11 libboost-all-dev clang-11 rustc --fix-missing + tools/install-sys-dependencies-linux + tools/install-rust-dependencies - name: Cache internal dependencies id: internal_cache uses: actions/cache@v1.1.2 diff --git a/.github/workflows/wasm-ci.yml b/.github/workflows/wasm-ci.yml index d383cc49195..d41158c4933 100644 --- a/.github/workflows/wasm-ci.yml +++ b/.github/workflows/wasm-ci.yml @@ -14,9 +14,8 @@ jobs: - name: Install system dependencies run: | - # build-essential clang-11 libc++-dev libc++abi-dev ruby-full cmake python3 - sudo apt-get update && sudo apt-get install libboost-all-dev --fix-missing - + tools/install-sys-dependencies-linux + tools/install-rust-dependencies - name: Install emsdk run: tools/install-wasm-dependencies diff --git a/CMakeLists.txt b/CMakeLists.txt index ed02ed918ed..a6dbdf3c1f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,8 +30,11 @@ target_link_directories(${PROJECT_NAME}_INTERFACE INTERFACE ${PREFIX}/lib) set_project_warnings(${PROJECT_NAME}_INTERFACE) add_subdirectory(trezor-crypto) +set(WALLET_CORE_RS_LIB libwallet_core_rs.a) +set(WALLET_CORE_BINDGEN ${PREFIX}/lib/${WALLET_CORE_RS_LIB}) if (TW_COMPILE_WASM) message(STATUS "Wasm build enabled") + set(WALLET_CORE_BINDGEN ${PREFIX}/wasm32-unknown-emscripten/release/${WALLET_CORE_RS_LIB}) add_subdirectory(wasm) endif () @@ -48,13 +51,21 @@ if (${ANDROID}) file(GLOB_RECURSE sources src/*.c src/*.cc src/*.cpp src/*.h jni/cpp/*.c jni/cpp/*.cpp jni/cpp/*.h jni/cpp/*.c) add_library(TrustWalletCore SHARED ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) find_library(log-lib log) - target_link_libraries(TrustWalletCore PUBLIC ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf ${log-lib} Boost::boost) + if (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "arm64-v8a") + set(WALLET_CORE_BINDGEN ${PREFIX}/aarch64-linux-android/release/${WALLET_CORE_RS_LIB}) + elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL "x86") + set(WALLET_CORE_BINDGEN ${PREFIX}/i686-linux-android/release/${WALLET_CORE_RS_LIB}) + elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL "armeabi-v7a") + set(WALLET_CORE_BINDGEN ${PREFIX}/armv7-linux-androideabi/release/${WALLET_CORE_RS_LIB}) + elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL "x86_64") + set(WALLET_CORE_BINDGEN ${PREFIX}/x86_64-linux-android/release/${WALLET_CORE_RS_LIB}) + endif() + target_link_libraries(TrustWalletCore PUBLIC ${WALLET_CORE_BINDGEN} ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf ${log-lib} Boost::boost) else () message("Configuring standalone") file(GLOB_RECURSE sources src/*.c src/*.cc src/*.cpp src/*.h) - add_library(TrustWalletCore ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) - - target_link_libraries(TrustWalletCore PUBLIC ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf Boost::boost) + add_library(TrustWalletCore STATIC ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) + target_link_libraries(TrustWalletCore PUBLIC ${WALLET_CORE_BINDGEN} ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf Boost::boost) endif () if (TW_CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt index 6d52a4c9d1d..2b9d9b416c1 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/aptos/TestAptosSigner.kt @@ -23,6 +23,54 @@ class TestAptosSigner { System.loadLibrary("TrustWalletCore") } + @Test + fun AptosTransactionBlindSigning() { + // Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x7efd69e7f9462774b932ce500ab51c0d0dcc004cf272e09f8ffd5804c2a84e33?network=mainnet + val key = + "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec".toHexBytesInByteString() + + val payloadJson = """ + { + "function": "0x16fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c::AnimeSwapPoolV1::swap_exact_coins_for_coins_3_pair_entry", + "type_arguments": [ + "0x1::aptos_coin::AptosCoin", + "0x881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f4::coin::MOJO", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDT", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC" + ], + "arguments": [ + "1000000", + "49329" + ], + "type": "entry_function_payload" + } + """.trimIndent() + val signingInput = Aptos.SigningInput.newBuilder() + .setChainId(1) + .setExpirationTimestampSecs(3664390082) + .setGasUnitPrice(100) + .setMaxGasAmount(100011) + .setSender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30") + .setSequenceNumber(42) + .setAnyEncoded(payloadJson) + .setPrivateKey(key) + .build() + + val result = AnySigner.sign(signingInput, CoinType.APTOS, Aptos.SigningOutput.parser()) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.rawTxn.toByteArray())), + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f302a000000000000000216fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c0f416e696d6553776170506f6f6c563127737761705f65786163745f636f696e735f666f725f636f696e735f335f706169725f656e747279040700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e0007881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f404636f696e044d4f4a4f0007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa05617373657404555344540007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa056173736574045553444300020840420f000000000008b1c0000000000000ab860100000000006400000000000000c2276ada0000000001" + ) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.authenticator.signature.toByteArray())), + "42cd67406e85afd1e948e7ad7f5f484fb4c60d82b267c6b6b28a92301e228b983206d2b87cd5487cf9acfb0effbd183ab90123570eb2e047cb152d337152210b" + ) + assertEquals( + Numeric.cleanHexPrefix(Numeric.toHexString(result.encoded.toByteArray())), + "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f302a000000000000000216fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c0f416e696d6553776170506f6f6c563127737761705f65786163745f636f696e735f666f725f636f696e735f335f706169725f656e747279040700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e0007881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f404636f696e044d4f4a4f0007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa05617373657404555344540007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa056173736574045553444300020840420f000000000008b1c0000000000000ab860100000000006400000000000000c2276ada00000000010020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c4042cd67406e85afd1e948e7ad7f5f484fb4c60d82b267c6b6b28a92301e228b983206d2b87cd5487cf9acfb0effbd183ab90123570eb2e047cb152d337152210b" + ) + } + @Test fun AptosTransactionSigning() { // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xb4d62afd3862116e060dd6ad9848ccb50c2bc177799819f1d29c059ae2042467?network=devnet diff --git a/rust/.gitignore b/rust/.gitignore new file mode 100644 index 00000000000..bca6f9b85aa --- /dev/null +++ b/rust/.gitignore @@ -0,0 +1,7 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/rust/Cargo.lock b/rust/Cargo.lock new file mode 100644 index 00000000000..18607412aba --- /dev/null +++ b/rust/Cargo.lock @@ -0,0 +1,224 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" + +[[package]] +name = "bcs" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b06b4c1f053002b70e7084ac944c77d58d5d92b2110dbc5e852735e00ad3ccc" +dependencies = [ + "serde", + "thiserror", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "libc" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "move-core-types" +version = "0.0.4" +source = "git+https://github.com/move-language/move?rev=f7137eabc2046f76fdad3ded2c51e03a3b1fbd01#f7137eabc2046f76fdad3ded2c51e03a3b1fbd01" +dependencies = [ + "anyhow", + "bcs", + "hex", + "once_cell", + "rand", + "ref-cast", + "serde", + "serde_bytes", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ref-cast" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b15debb4f9d60d767cd8ca9ef7abb2452922f3214671ff052defc7f3502c44" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfa8511e9e94fd3de6585a3d3cd00e01ed556dc9814829280af0e8dc72a8f36" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "wallet-core-rs" +version = "0.1.0" +dependencies = [ + "bcs", + "hex", + "move-core-types", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 00000000000..9a75f71be9c --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "wallet-core-rs" +version = "0.1.0" +edition = "2021" + +[lib] +name = "wallet_core_rs" +crate-type = ["staticlib"] # Creates static lib + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +move-core-types = { git = "https://github.com/move-language/move", rev = "f7137eabc2046f76fdad3ded2c51e03a3b1fbd01", features = ["address32"] } +bcs = "0.1.4" +hex = "0.4.3" + +[dev-dependencies] diff --git a/rust/src/lib.rs b/rust/src/lib.rs new file mode 100644 index 00000000000..4f3c0712189 --- /dev/null +++ b/rust/src/lib.rs @@ -0,0 +1,8 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +pub mod move_parser; +pub mod memory; diff --git a/rust/src/memory/mod.rs b/rust/src/memory/mod.rs new file mode 100644 index 00000000000..91bb4d4ddf6 --- /dev/null +++ b/rust/src/memory/mod.rs @@ -0,0 +1,30 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +use std::ffi::{c_char, CString}; + +#[no_mangle] +pub unsafe extern fn free_string(ptr: *const c_char) { + // Take the ownership back to rust and drop the owner + let _ = CString::from_raw(ptr as *mut _); +} + +pub fn c_string_standalone(input: String) -> *const c_char { + let res = CString::new(input).unwrap(); + let p = res.as_ptr(); + std::mem::forget(res); + p +} + +#[cfg(test)] +mod tests { + use crate::memory::{c_string_standalone, free_string}; + + #[test] + fn tests_ffi_string() { + unsafe { free_string(c_string_standalone("foo".to_string())); } + } +} diff --git a/rust/src/move_parser/mod.rs b/rust/src/move_parser/mod.rs new file mode 100644 index 00000000000..ba788b5b042 --- /dev/null +++ b/rust/src/move_parser/mod.rs @@ -0,0 +1,87 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +use std::{ + ffi::c_char, + ffi::CStr +}; +use move_core_types::*; +use move_core_types::language_storage::TypeTag; +use move_core_types::transaction_argument::TransactionArgument; +use crate::memory; + +#[repr(C)] +#[derive(PartialEq, Debug)] +pub enum ETypeTag { + Bool = 1, + U8 = 2, + U64 = 3, + U128 = 4, + Address = 5, + Signer = 6, + Vector = 7, + Struct = 8, + Error = 9 +} + +#[no_mangle] +pub extern fn parse_type_tag(input: *const c_char) -> ETypeTag { + let s = unsafe { CStr::from_ptr(input).to_str().unwrap() }; + let transaction_argument = match parser::parse_type_tag(s) { + Ok(v) => v, + Err(_) => return ETypeTag::Error + }; + return match transaction_argument { + TypeTag::Bool => ETypeTag::Bool, + TypeTag::U8 => ETypeTag::U8, + TypeTag::U64 => ETypeTag::U64, + TypeTag::U128 => ETypeTag::U128, + TypeTag::Address => ETypeTag::Address, + TypeTag::Signer => ETypeTag::Signer, + TypeTag::Vector(_) => ETypeTag::Vector, + TypeTag::Struct(_) => ETypeTag::Struct + } +} + +#[no_mangle] +pub extern fn parse_function_argument_to_bcs(input: *const c_char) -> *const c_char { + let s = unsafe { CStr::from_ptr(input).to_str().unwrap() }; + let transaction_argument = match parser::parse_transaction_argument(s) { + Ok(v) => v, + Err(_) => return "\0".as_ptr() as *const c_char + }; + let v = match transaction_argument { + TransactionArgument::U8(v) => hex::encode(bcs::to_bytes(&v).unwrap()), + TransactionArgument::U64(v) => hex::encode(bcs::to_bytes(&v).unwrap()), + TransactionArgument::U128(v) => hex::encode(bcs::to_bytes(&v).unwrap()), + TransactionArgument::Address(v) => hex::encode(bcs::to_bytes(&v).unwrap()), + TransactionArgument::U8Vector(v) => hex::encode(bcs::to_bytes(&v).unwrap()), + TransactionArgument::Bool(v) => hex::encode(bcs::to_bytes(&v).unwrap()), + }; + memory::c_string_standalone(v) +} + +#[cfg(test)] +mod tests { + use crate::move_parser::{ETypeTag, parse_function_argument_to_bcs, parse_type_tag}; + use std::ffi::CStr; + use std::ffi::c_char; + + #[test] + fn tests_type_tag() { + let tag = parse_type_tag("0x1::aptos_coin::AptosCoin\0".as_ptr() as *const c_char); + assert_eq!(tag, ETypeTag::Struct); + } + + #[test] + fn tests_function_argument_to_bcs() { + let str = unsafe { CStr::from_ptr(parse_function_argument_to_bcs("10000000\0".as_ptr() as *const c_char)).to_str().unwrap() }; + assert_eq!(str, "8096980000000000"); + + let str = unsafe { CStr::from_ptr(parse_function_argument_to_bcs("5047445908\0".as_ptr() as *const c_char)).to_str().unwrap() }; + assert_eq!(str, "94e9d92c01000000"); + } +} diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index 5ecf5e6ba0d..a7c743f3e81 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -71,4 +71,4 @@ SET (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINK_FLAGS}") add_executable (sample sample.cpp) # link with our library, and default platform libraries -target_link_libraries (sample TrustWalletCore TrezorCrypto protobuf pthread ${PLATFORM_LIBS}) +target_link_libraries (sample PUBLIC TrustWalletCore wallet_core_rs TrezorCrypto protobuf pthread ${PLATFORM_LIBS}) diff --git a/samples/go/core/bitcoin.go b/samples/go/core/bitcoin.go index 5613b452ffa..b9b0d218298 100644 --- a/samples/go/core/bitcoin.go +++ b/samples/go/core/bitcoin.go @@ -1,7 +1,7 @@ package core // #cgo CFLAGS: -I../../../include -// #cgo LDFLAGS: -L../../../build -L../../../build/trezor-crypto -lTrustWalletCore -lprotobuf -lTrezorCrypto -lstdc++ -lm +// #cgo LDFLAGS: -L../../../build -L../../../build/local/lib -L../../../build/trezor-crypto -lTrustWalletCore -lwallet_core_rs -lprotobuf -lTrezorCrypto -lstdc++ -lm // #include // #include // #include diff --git a/samples/go/core/coin.go b/samples/go/core/coin.go index 122e9a286fb..f1dd5dc94d9 100644 --- a/samples/go/core/coin.go +++ b/samples/go/core/coin.go @@ -1,7 +1,7 @@ package core // #cgo CFLAGS: -I../../../include -// #cgo LDFLAGS: -L../../../build -L../../../build/trezor-crypto -lTrustWalletCore -lprotobuf -lTrezorCrypto -lstdc++ -lm +// #cgo LDFLAGS: -L../../../build -L../../../build/local/lib -L../../../build/trezor-crypto -lTrustWalletCore -lwallet_core_rs -lprotobuf -lTrezorCrypto -lstdc++ -lm // #include // #include import "C" diff --git a/samples/go/core/datavector.go b/samples/go/core/datavector.go index 014030e8817..04a4e4bd520 100644 --- a/samples/go/core/datavector.go +++ b/samples/go/core/datavector.go @@ -1,7 +1,7 @@ package core // #cgo CFLAGS: -I../../../include -// #cgo LDFLAGS: -L../../../build -L../../../build/trezor-crypto -lTrustWalletCore -lprotobuf -lTrezorCrypto -lstdc++ -lm +// #cgo LDFLAGS: -L../../../build -L../../../build/local/lib -L../../../build/trezor-crypto -lTrustWalletCore -lwallet_core_rs -lprotobuf -lTrezorCrypto -lstdc++ -lm // #include import "C" import "tw/types" diff --git a/samples/go/core/mnemonic.go b/samples/go/core/mnemonic.go index 12394cc86b9..a1968b864b9 100644 --- a/samples/go/core/mnemonic.go +++ b/samples/go/core/mnemonic.go @@ -1,7 +1,7 @@ package core // #cgo CFLAGS: -I../../../include -// #cgo LDFLAGS: -L../../../build -L../../../build/trezor-crypto -lTrustWalletCore -lprotobuf -lTrezorCrypto -lstdc++ -lm +// #cgo LDFLAGS: -L../../../build -L../../../build/local/lib -L../../../build/trezor-crypto -lTrustWalletCore -lwallet_core_rs -lprotobuf -lTrezorCrypto -lstdc++ -lm // #include import "C" diff --git a/samples/go/core/publicKey.go b/samples/go/core/publicKey.go index d116f8e7270..bf70a64622f 100644 --- a/samples/go/core/publicKey.go +++ b/samples/go/core/publicKey.go @@ -1,7 +1,7 @@ package core // #cgo CFLAGS: -I../../../include -// #cgo LDFLAGS: -L../../../build -L../../../build/trezor-crypto -lTrustWalletCore -lprotobuf -lTrezorCrypto -lstdc++ -lm +// #cgo LDFLAGS: -L../../../build -L../../../build/local/lib -L../../../build/trezor-crypto -lTrustWalletCore -lwallet_core_rs -lprotobuf -lTrezorCrypto -lstdc++ -lm // #include import "C" diff --git a/samples/go/core/transaction.go b/samples/go/core/transaction.go index 3b3333d5a11..8aa9e1a900c 100644 --- a/samples/go/core/transaction.go +++ b/samples/go/core/transaction.go @@ -1,7 +1,7 @@ package core // #cgo CFLAGS: -I../../../include -// #cgo LDFLAGS: -L../../../build -L../../../build/trezor-crypto -lTrustWalletCore -lprotobuf -lTrezorCrypto -lstdc++ -lm +// #cgo LDFLAGS: -L../../../build -L../../../build/local/lib -L../../../build/trezor-crypto -lTrustWalletCore -lwallet_core_rs -lprotobuf -lTrezorCrypto -lstdc++ -lm // #include // #include import "C" diff --git a/samples/go/core/transactionHelper.go b/samples/go/core/transactionHelper.go index c8414724a32..6062be8b753 100644 --- a/samples/go/core/transactionHelper.go +++ b/samples/go/core/transactionHelper.go @@ -1,7 +1,7 @@ package core // #cgo CFLAGS: -I../../../include -// #cgo LDFLAGS: -L../../../build -L../../../build/trezor-crypto -lTrustWalletCore -lprotobuf -lTrezorCrypto -lstdc++ -lm +// #cgo LDFLAGS: -L../../../build -L../../../build/local/lib -L../../../build/trezor-crypto -lTrustWalletCore -lwallet_core_rs -lprotobuf -lTrezorCrypto -lstdc++ -lm // #include import "C" import "tw/types" diff --git a/samples/go/core/wallet.go b/samples/go/core/wallet.go index 09af05cdd42..ee95b763631 100644 --- a/samples/go/core/wallet.go +++ b/samples/go/core/wallet.go @@ -1,7 +1,7 @@ package core // #cgo CFLAGS: -I../../../include -// #cgo LDFLAGS: -L../../../build -L../../../build/trezor-crypto -lTrustWalletCore -lprotobuf -lTrezorCrypto -lstdc++ -lm +// #cgo LDFLAGS: -L../../../build -L../../../build/local/lib -L../../../build/trezor-crypto -lTrustWalletCore -lwallet_core_rs -lprotobuf -lTrezorCrypto -lstdc++ -lm // #include // #include // #include diff --git a/samples/go/dev-console/native/cgo.go b/samples/go/dev-console/native/cgo.go index 3e0569e9162..b393d457f7a 100644 --- a/samples/go/dev-console/native/cgo.go +++ b/samples/go/dev-console/native/cgo.go @@ -1,7 +1,7 @@ package native // #cgo CFLAGS: -I packaged/include -// #cgo LDFLAGS: -lTrustWalletCore -lstdc++ -lm -lprotobuf -lTrezorCrypto +// #cgo LDFLAGS: -lTrustWalletCore -lstdc++ -lm -lprotobuf -lwallet_core_rs -lTrezorCrypto // // // #cgo LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib -L${SRCDIR}/packaged/lib diff --git a/samples/go/dev-console/prepare.sh b/samples/go/dev-console/prepare.sh index 76ec7e9bb85..ff2a4f6af3a 100755 --- a/samples/go/dev-console/prepare.sh +++ b/samples/go/dev-console/prepare.sh @@ -5,6 +5,7 @@ cmake -DCMAKE_BUILD_TYPE=Release -DTW_UNIT_TESTS=OFF -DTW_BUILD_EXAMPLES=OFF -DT ninja cp libTrustWalletCore.a ../native/packaged/lib/ cp libprotobuf.a ../native/packaged/lib +cp ../../../../build/local/lib/libwallet_core_rs.a ../native/packaged/lib cp trezor-crypto/libTrezorCrypto.a ../native/packaged/lib cd - -cp -R ../../../include native/packaged/ \ No newline at end of file +cp -R ../../../include native/packaged/ diff --git a/samples/go/protos/binance/Binance.pb.go b/samples/go/protos/binance/Binance.pb.go index 9205f012247..9f8752135da 100644 --- a/samples/go/protos/binance/Binance.pb.go +++ b/samples/go/protos/binance/Binance.pb.go @@ -1,17 +1,17 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.0 -// protoc v3.19.2 +// protoc-gen-go v1.28.1 +// protoc v3.21.5 // source: Binance.proto package binance import ( - common "tw/protos/common" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + common "tw/protos/common" ) const ( @@ -21,18 +21,22 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// Transaction structure, used internally type Transaction struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // int64 SIZE-OF-ENCODED // varint encoded length of the structure after encoding - // 0xF0625DEE // prefix - Msgs [][]byte `protobuf:"bytes,1,rep,name=msgs,proto3" json:"msgs,omitempty"` // array of size 1, containing the transaction message, which are one of the transaction type below - Signatures [][]byte `protobuf:"bytes,2,rep,name=signatures,proto3" json:"signatures,omitempty"` // array of size 1, containing the standard signature structure of the transaction sender - Memo string `protobuf:"bytes,3,opt,name=memo,proto3" json:"memo,omitempty"` // a short sentence of remark for the transaction, only for `Transfer` transactions. - Source int64 `protobuf:"varint,4,opt,name=source,proto3" json:"source,omitempty"` // an identifier for tools triggerring this transaction, set to zero if unwilling to disclose. - Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` // reserved for future use + // array of size 1, containing the transaction message, which are one of the transaction type below + Msgs [][]byte `protobuf:"bytes,1,rep,name=msgs,proto3" json:"msgs,omitempty"` + // array of size 1, containing the standard signature structure of the transaction sender + Signatures [][]byte `protobuf:"bytes,2,rep,name=signatures,proto3" json:"signatures,omitempty"` + // a short sentence of remark for the transaction, only for `Transfer` transactions. + Memo string `protobuf:"bytes,3,opt,name=memo,proto3" json:"memo,omitempty"` + // an identifier for tools triggering this transaction, set to zero if unwilling to disclose. + Source int64 `protobuf:"varint,4,opt,name=source,proto3" json:"source,omitempty"` + // reserved for future use + Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` } func (x *Transaction) Reset() { @@ -102,15 +106,20 @@ func (x *Transaction) GetData() []byte { return nil } +// Signature structure, used internally type Signature struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - PubKey []byte `protobuf:"bytes,1,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"` // public key bytes of the signer address - Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` // signature bytes, please check chain access section for signature generation - AccountNumber int64 `protobuf:"varint,3,opt,name=account_number,json=accountNumber,proto3" json:"account_number,omitempty"` // another identifier of signer, which can be read from chain by account REST API or RPC - Sequence int64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` // sequence number for the next transaction + // public key bytes of the signer address + PubKey []byte `protobuf:"bytes,1,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"` + // signature bytes, please check chain access section for signature generation + Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` + // another identifier of signer, which can be read from chain by account REST API or RPC + AccountNumber int64 `protobuf:"varint,3,opt,name=account_number,json=accountNumber,proto3" json:"account_number,omitempty"` + // sequence number for the next transaction + Sequence int64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` } func (x *Signature) Reset() { @@ -173,20 +182,28 @@ func (x *Signature) GetSequence() int64 { return 0 } +// Message for Trade order type TradeOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // 0xCE6DC043 // prefix - Sender []byte `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` // originating address - Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` // order id, optional - Symbol string `protobuf:"bytes,3,opt,name=symbol,proto3" json:"symbol,omitempty"` // symbol for trading pair in full name of the tokens - Ordertype int64 `protobuf:"varint,4,opt,name=ordertype,proto3" json:"ordertype,omitempty"` // only accept 2 for now, meaning limit order - Side int64 `protobuf:"varint,5,opt,name=side,proto3" json:"side,omitempty"` // 1 for buy and 2 fory sell - Price int64 `protobuf:"varint,6,opt,name=price,proto3" json:"price,omitempty"` // price of the order, which is the real price multiplied by 1e8 (10^8) and rounded to integer - Quantity int64 `protobuf:"varint,7,opt,name=quantity,proto3" json:"quantity,omitempty"` // quantity of the order, which is the real price multiplied by 1e8 (10^8) and rounded to integer - Timeinforce int64 `protobuf:"varint,8,opt,name=timeinforce,proto3" json:"timeinforce,omitempty"` // 1 for Good Till Expire(GTE) order and 3 for Immediate Or Cancel (IOC) + // originating address + Sender []byte `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + // order id, optional + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + // symbol for trading pair in full name of the tokens + Symbol string `protobuf:"bytes,3,opt,name=symbol,proto3" json:"symbol,omitempty"` + // only accept 2 for now, meaning limit order + Ordertype int64 `protobuf:"varint,4,opt,name=ordertype,proto3" json:"ordertype,omitempty"` + // 1 for buy and 2 for sell + Side int64 `protobuf:"varint,5,opt,name=side,proto3" json:"side,omitempty"` + // price of the order, which is the real price multiplied by 1e8 (10^8) and rounded to integer + Price int64 `protobuf:"varint,6,opt,name=price,proto3" json:"price,omitempty"` + // quantity of the order, which is the real price multiplied by 1e8 (10^8) and rounded to integer + Quantity int64 `protobuf:"varint,7,opt,name=quantity,proto3" json:"quantity,omitempty"` + // 1 for Good Till Expire(GTE) order and 3 for Immediate Or Cancel (IOC) + Timeinforce int64 `protobuf:"varint,8,opt,name=timeinforce,proto3" json:"timeinforce,omitempty"` } func (x *TradeOrder) Reset() { @@ -277,15 +294,18 @@ func (x *TradeOrder) GetTimeinforce() int64 { return 0 } +// Message for CancelTrade order type CancelTradeOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // 0x166E681B // prefix - Sender []byte `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` // originating address - Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` // symbol for trading pair in full name of the tokens - Refid string `protobuf:"bytes,3,opt,name=refid,proto3" json:"refid,omitempty"` // order id to cancel + // originating address + Sender []byte `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + // symbol for trading pair in full name of the tokens + Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` + // order id to cancel + Refid string `protobuf:"bytes,3,opt,name=refid,proto3" json:"refid,omitempty"` } func (x *CancelTradeOrder) Reset() { @@ -341,12 +361,15 @@ func (x *CancelTradeOrder) GetRefid() string { return "" } +// Message for Send order type SendOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Inputs []*SendOrder_Input `protobuf:"bytes,1,rep,name=inputs,proto3" json:"inputs,omitempty"` + // Send inputs + Inputs []*SendOrder_Input `protobuf:"bytes,1,rep,name=inputs,proto3" json:"inputs,omitempty"` + // Send outputs Outputs []*SendOrder_Output `protobuf:"bytes,2,rep,name=outputs,proto3" json:"outputs,omitempty"` } @@ -396,17 +419,22 @@ func (x *SendOrder) GetOutputs() []*SendOrder_Output { return nil } +// Message for TokenIssue order type TokenIssueOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // 0x17EFAB80 // prefix - From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // owner address - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // token name - Symbol string `protobuf:"bytes,3,opt,name=symbol,proto3" json:"symbol,omitempty"` // token symbol, in full name with "-" suffix - TotalSupply int64 `protobuf:"varint,4,opt,name=total_supply,json=totalSupply,proto3" json:"total_supply,omitempty"` // total supply - Mintable bool `protobuf:"varint,5,opt,name=mintable,proto3" json:"mintable,omitempty"` // mintable + // owner address + From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // token name + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // token symbol, in full name with "-" suffix + Symbol string `protobuf:"bytes,3,opt,name=symbol,proto3" json:"symbol,omitempty"` + // total supply + TotalSupply int64 `protobuf:"varint,4,opt,name=total_supply,json=totalSupply,proto3" json:"total_supply,omitempty"` + // mintable + Mintable bool `protobuf:"varint,5,opt,name=mintable,proto3" json:"mintable,omitempty"` } func (x *TokenIssueOrder) Reset() { @@ -476,15 +504,18 @@ func (x *TokenIssueOrder) GetMintable() bool { return false } +// Message for TokenMint order type TokenMintOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // 0x467E0829 // prefix - From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // owner address - Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` // token symbol, in full name with "-" suffix - Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"` // amount to mint + // owner address + From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // token symbol, in full name with "-" suffix + Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` + // amount to mint + Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"` } func (x *TokenMintOrder) Reset() { @@ -540,15 +571,18 @@ func (x *TokenMintOrder) GetAmount() int64 { return 0 } +// Message for TokenBurn order type TokenBurnOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // 0x7ED2D2A0 // prefix - From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // owner address - Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` // token symbol, in full name with "-" suffix - Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"` // amount to burn + // owner address + From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // token symbol, in full name with "-" suffix + Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` + // amount to burn + Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"` } func (x *TokenBurnOrder) Reset() { @@ -604,15 +638,18 @@ func (x *TokenBurnOrder) GetAmount() int64 { return 0 } +// Message for TokenFreeze order type TokenFreezeOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // 0xE774B32D // prefix - From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // owner address - Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` // token symbol, in full name with "-" suffix - Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"` // amount of token to freeze + // owner address + From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // token symbol, in full name with "-" suffix + Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` + // amount of token to freeze + Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"` } func (x *TokenFreezeOrder) Reset() { @@ -668,15 +705,18 @@ func (x *TokenFreezeOrder) GetAmount() int64 { return 0 } +// Message for TokenUnfreeze order type TokenUnfreezeOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // 0x6515FF0D // prefix - From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // owner address - Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` // token symbol, in full name with "-" suffix - Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"` // amount of token to unfreeze + // owner address + From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // token symbol, in full name with "-" suffix + Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` + // amount of token to unfreeze + Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"` } func (x *TokenUnfreezeOrder) Reset() { @@ -732,22 +772,32 @@ func (x *TokenUnfreezeOrder) GetAmount() int64 { return 0 } +// Message for HashTimeLock order type HTLTOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // 0xB33F9A24 // prefix - From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // signer address - To []byte `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` // recipient address - RecipientOtherChain string `protobuf:"bytes,3,opt,name=recipient_other_chain,json=recipientOtherChain,proto3" json:"recipient_other_chain,omitempty"` - SenderOtherChain string `protobuf:"bytes,4,opt,name=sender_other_chain,json=senderOtherChain,proto3" json:"sender_other_chain,omitempty"` - RandomNumberHash []byte `protobuf:"bytes,5,opt,name=random_number_hash,json=randomNumberHash,proto3" json:"random_number_hash,omitempty"` //hash of a random number and timestamp, based on SHA256 - Timestamp int64 `protobuf:"varint,6,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Amount []*SendOrder_Token `protobuf:"bytes,7,rep,name=amount,proto3" json:"amount,omitempty"` - ExpectedIncome string `protobuf:"bytes,8,opt,name=expected_income,json=expectedIncome,proto3" json:"expected_income,omitempty"` // expected gained token on the other chain - HeightSpan int64 `protobuf:"varint,9,opt,name=height_span,json=heightSpan,proto3" json:"height_span,omitempty"` - CrossChain bool `protobuf:"varint,10,opt,name=cross_chain,json=crossChain,proto3" json:"cross_chain,omitempty"` + // signer address + From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // recipient address + To []byte `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` + // source on other chain, optional + RecipientOtherChain string `protobuf:"bytes,3,opt,name=recipient_other_chain,json=recipientOtherChain,proto3" json:"recipient_other_chain,omitempty"` + // recipient on other chain, optional + SenderOtherChain string `protobuf:"bytes,4,opt,name=sender_other_chain,json=senderOtherChain,proto3" json:"sender_other_chain,omitempty"` + // hash of a random number and timestamp, based on SHA256 + RandomNumberHash []byte `protobuf:"bytes,5,opt,name=random_number_hash,json=randomNumberHash,proto3" json:"random_number_hash,omitempty"` + // timestamp + Timestamp int64 `protobuf:"varint,6,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // amounts + Amount []*SendOrder_Token `protobuf:"bytes,7,rep,name=amount,proto3" json:"amount,omitempty"` + // expected gained token on the other chain + ExpectedIncome string `protobuf:"bytes,8,opt,name=expected_income,json=expectedIncome,proto3" json:"expected_income,omitempty"` + // period expressed in block heights + HeightSpan int64 `protobuf:"varint,9,opt,name=height_span,json=heightSpan,proto3" json:"height_span,omitempty"` + // set for cross-chain send + CrossChain bool `protobuf:"varint,10,opt,name=cross_chain,json=crossChain,proto3" json:"cross_chain,omitempty"` } func (x *HTLTOrder) Reset() { @@ -852,15 +902,18 @@ func (x *HTLTOrder) GetCrossChain() bool { return false } +// Message for Deposit HTLT order type DepositHTLTOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // 0xB33F9A24 // prefix - From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // signer address + // signer address + From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // amounts Amount []*SendOrder_Token `protobuf:"bytes,2,rep,name=amount,proto3" json:"amount,omitempty"` - SwapId []byte `protobuf:"bytes,3,opt,name=swap_id,json=swapId,proto3" json:"swap_id,omitempty"` + // swap ID + SwapId []byte `protobuf:"bytes,3,opt,name=swap_id,json=swapId,proto3" json:"swap_id,omitempty"` } func (x *DepositHTLTOrder) Reset() { @@ -916,14 +969,17 @@ func (x *DepositHTLTOrder) GetSwapId() []byte { return nil } +// Message for Claim HTLT order type ClaimHTLOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // 0xC1665300 // prefix - From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // signer address - SwapId []byte `protobuf:"bytes,2,opt,name=swap_id,json=swapId,proto3" json:"swap_id,omitempty"` + // signer address + From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // swap ID + SwapId []byte `protobuf:"bytes,2,opt,name=swap_id,json=swapId,proto3" json:"swap_id,omitempty"` + // random number input RandomNumber []byte `protobuf:"bytes,3,opt,name=random_number,json=randomNumber,proto3" json:"random_number,omitempty"` } @@ -980,13 +1036,15 @@ func (x *ClaimHTLOrder) GetRandomNumber() []byte { return nil } +// Message for Refund HTLT order type RefundHTLTOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // 0x3454A27C // prefix - From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // signer address + // signer address + From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // swap ID SwapId []byte `protobuf:"bytes,2,opt,name=swap_id,json=swapId,proto3" json:"swap_id,omitempty"` } @@ -1036,15 +1094,20 @@ func (x *RefundHTLTOrder) GetSwapId() []byte { return nil } +// Transfer type TransferOut struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` - To []byte `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` - Amount *SendOrder_Token `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount,omitempty"` - ExpireTime int64 `protobuf:"varint,4,opt,name=expire_time,json=expireTime,proto3" json:"expire_time,omitempty"` + // source address + From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + // recipient address + To []byte `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` + // transfer amount + Amount *SendOrder_Token `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount,omitempty"` + // expiration time + ExpireTime int64 `protobuf:"varint,4,opt,name=expire_time,json=expireTime,proto3" json:"expire_time,omitempty"` } func (x *TransferOut) Reset() { @@ -1328,16 +1391,20 @@ func (x *SideChainUndelegate) GetChainId() string { return "" } +// Message for TimeLock order type TimeLockOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - FromAddress []byte `protobuf:"bytes,1,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` // owner address + // owner address + FromAddress []byte `protobuf:"bytes,1,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` + // Description (optional) Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` // Array of symbol/amount pairs. see SDK https://github.com/binance-chain/javascript-sdk/blob/master/docs/api-docs/classes/tokenmanagement.md#timelock - Amount []*SendOrder_Token `protobuf:"bytes,3,rep,name=amount,proto3" json:"amount,omitempty"` - LockTime int64 `protobuf:"varint,4,opt,name=lock_time,json=lockTime,proto3" json:"lock_time,omitempty"` + Amount []*SendOrder_Token `protobuf:"bytes,3,rep,name=amount,proto3" json:"amount,omitempty"` + // lock time + LockTime int64 `protobuf:"varint,4,opt,name=lock_time,json=lockTime,proto3" json:"lock_time,omitempty"` } func (x *TimeLockOrder) Reset() { @@ -1400,17 +1467,22 @@ func (x *TimeLockOrder) GetLockTime() int64 { return 0 } +// Message for TimeRelock order type TimeRelockOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - FromAddress []byte `protobuf:"bytes,1,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` // owner address - Id int64 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"` // order ID + // owner address + FromAddress []byte `protobuf:"bytes,1,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` + // order ID + Id int64 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"` + // Description (optional) Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` // Array of symbol/amount pairs. - Amount []*SendOrder_Token `protobuf:"bytes,4,rep,name=amount,proto3" json:"amount,omitempty"` - LockTime int64 `protobuf:"varint,5,opt,name=lock_time,json=lockTime,proto3" json:"lock_time,omitempty"` + Amount []*SendOrder_Token `protobuf:"bytes,4,rep,name=amount,proto3" json:"amount,omitempty"` + // lock time + LockTime int64 `protobuf:"varint,5,opt,name=lock_time,json=lockTime,proto3" json:"lock_time,omitempty"` } func (x *TimeRelockOrder) Reset() { @@ -1480,13 +1552,16 @@ func (x *TimeRelockOrder) GetLockTime() int64 { return 0 } +// Message for TimeUnlock order type TimeUnlockOrder struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - FromAddress []byte `protobuf:"bytes,1,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` // owner address - Id int64 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"` // order ID + // owner address + FromAddress []byte `protobuf:"bytes,1,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` + // order ID + Id int64 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"` } func (x *TimeUnlockOrder) Reset() { @@ -1535,18 +1610,30 @@ func (x *TimeUnlockOrder) GetId() int64 { return 0 } -// Input data necessary to create a signed order. +// Input data necessary to create a signed transaction. type SigningInput struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` - AccountNumber int64 `protobuf:"varint,2,opt,name=account_number,json=accountNumber,proto3" json:"account_number,omitempty"` - Sequence int64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` - Source int64 `protobuf:"varint,4,opt,name=source,proto3" json:"source,omitempty"` - Memo string `protobuf:"bytes,5,opt,name=memo,proto3" json:"memo,omitempty"` - PrivateKey []byte `protobuf:"bytes,6,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"` + // Chain ID + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // Source account number + AccountNumber int64 `protobuf:"varint,2,opt,name=account_number,json=accountNumber,proto3" json:"account_number,omitempty"` + // Sequence number (account specific) + Sequence int64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` + // Transaction source, see https://github.com/bnb-chain/BEPs/blob/master/BEP10.md + // Some important values: + // 0: Default source value (e.g. for Binance Chain Command Line, or SDKs) + // 1: Binance DEX Web Wallet + // 2: Trust Wallet + Source int64 `protobuf:"varint,4,opt,name=source,proto3" json:"source,omitempty"` + // Optional memo + Memo string `protobuf:"bytes,5,opt,name=memo,proto3" json:"memo,omitempty"` + // The secret private key used for signing (32 bytes). + PrivateKey []byte `protobuf:"bytes,6,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"` + // Payload message + // // Types that are assignable to OrderOneof: // *SigningInput_TradeOrder // *SigningInput_CancelTradeOrder @@ -1902,7 +1989,7 @@ func (*SigningInput_TimeRelockOrder) isSigningInput_OrderOneof() {} func (*SigningInput_TimeUnlockOrder) isSigningInput_OrderOneof() {} -// Transaction signing output. +// Result containing the signed and encoded transaction. type SigningOutput struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1910,9 +1997,9 @@ type SigningOutput struct { // Signed and encoded transaction bytes. Encoded []byte `protobuf:"bytes,1,opt,name=encoded,proto3" json:"encoded,omitempty"` - /// error code, 0 is ok, other codes will be treated as errors + // OK (=0) or other codes in case of error Error common.SigningError `protobuf:"varint,2,opt,name=error,proto3,enum=TW.Common.Proto.SigningError" json:"error,omitempty"` - /// error description + // error description in case of error ErrorMessage string `protobuf:"bytes,3,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` } @@ -1969,59 +2056,22 @@ func (x *SigningOutput) GetErrorMessage() string { return "" } -type Signature_PubKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *Signature_PubKey) Reset() { - *x = Signature_PubKey{} - if protoimpl.UnsafeEnabled { - mi := &file_Binance_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Signature_PubKey) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Signature_PubKey) ProtoMessage() {} - -func (x *Signature_PubKey) ProtoReflect() protoreflect.Message { - mi := &file_Binance_proto_msgTypes[23] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Signature_PubKey.ProtoReflect.Descriptor instead. -func (*Signature_PubKey) Descriptor() ([]byte, []int) { - return file_Binance_proto_rawDescGZIP(), []int{1, 0} -} - -// 0x2A2C87FA -// A symbol-amount pair. Could be moved out of SendOrder; kept here for backward compatibility. +// A token amount, symbol-amount pair. Could be moved out of SendOrder; kept here for backward compatibility. type SendOrder_Token struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` - Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` + // Token ID + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + // Amount + Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` } func (x *SendOrder_Token) Reset() { *x = SendOrder_Token{} if protoimpl.UnsafeEnabled { - mi := &file_Binance_proto_msgTypes[24] + mi := &file_Binance_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2034,7 +2084,7 @@ func (x *SendOrder_Token) String() string { func (*SendOrder_Token) ProtoMessage() {} func (x *SendOrder_Token) ProtoReflect() protoreflect.Message { - mi := &file_Binance_proto_msgTypes[24] + mi := &file_Binance_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2064,19 +2114,22 @@ func (x *SendOrder_Token) GetAmount() int64 { return 0 } +// Transaction input type SendOrder_Input struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - Coins []*SendOrder_Token `protobuf:"bytes,2,rep,name=coins,proto3" json:"coins,omitempty"` + // source address + Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // input coin amounts + Coins []*SendOrder_Token `protobuf:"bytes,2,rep,name=coins,proto3" json:"coins,omitempty"` } func (x *SendOrder_Input) Reset() { *x = SendOrder_Input{} if protoimpl.UnsafeEnabled { - mi := &file_Binance_proto_msgTypes[25] + mi := &file_Binance_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2089,7 +2142,7 @@ func (x *SendOrder_Input) String() string { func (*SendOrder_Input) ProtoMessage() {} func (x *SendOrder_Input) ProtoReflect() protoreflect.Message { - mi := &file_Binance_proto_msgTypes[25] + mi := &file_Binance_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2119,19 +2172,22 @@ func (x *SendOrder_Input) GetCoins() []*SendOrder_Token { return nil } +// Transaction output type SendOrder_Output struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - Coins []*SendOrder_Token `protobuf:"bytes,2,rep,name=coins,proto3" json:"coins,omitempty"` + // destination address + Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // output coin amounts + Coins []*SendOrder_Token `protobuf:"bytes,2,rep,name=coins,proto3" json:"coins,omitempty"` } func (x *SendOrder_Output) Reset() { *x = SendOrder_Output{} if protoimpl.UnsafeEnabled { - mi := &file_Binance_proto_msgTypes[26] + mi := &file_Binance_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2144,7 +2200,7 @@ func (x *SendOrder_Output) String() string { func (*SendOrder_Output) ProtoMessage() {} func (x *SendOrder_Output) ProtoReflect() protoreflect.Message { - mi := &file_Binance_proto_msgTypes[26] + mi := &file_Binance_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2188,7 +2244,7 @@ var file_Binance_proto_rawDesc = []byte{ 0x09, 0x52, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, - 0x61, 0x74, 0x61, 0x22, 0x8f, 0x01, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x61, 0x74, 0x61, 0x22, 0x85, 0x01, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, @@ -2196,317 +2252,312 @@ var file_Binance_proto_rawDesc = []byte{ 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x1a, 0x08, 0x0a, 0x06, 0x50, - 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0xd2, 0x01, 0x0a, 0x0a, 0x54, 0x72, 0x61, 0x64, 0x65, 0x4f, + 0x03, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0xd2, 0x01, 0x0a, 0x0a, + 0x54, 0x72, 0x61, 0x64, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, + 0x6e, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6f, + 0x72, 0x64, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x64, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x20, + 0x0a, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, + 0x22, 0x58, 0x0a, 0x10, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x64, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, - 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x74, 0x79, - 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x04, 0x73, 0x69, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, - 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, - 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x69, 0x6d, 0x65, - 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, - 0x69, 0x6d, 0x65, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0x58, 0x0a, 0x10, 0x43, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x64, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x16, - 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, - 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x14, - 0x0a, 0x05, 0x72, 0x65, 0x66, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x72, - 0x65, 0x66, 0x69, 0x64, 0x22, 0xf4, 0x02, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, - 0x65, 0x72, 0x12, 0x39, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, - 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x3c, 0x0a, - 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x4f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x1a, 0x35, 0x0a, 0x05, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x1a, 0x5a, 0x0a, 0x05, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x37, 0x0a, 0x05, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, + 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x66, 0x69, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x72, 0x65, 0x66, 0x69, 0x64, 0x22, 0xf4, 0x02, 0x0a, 0x09, 0x53, + 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, + 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, + 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x73, 0x12, 0x3c, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, - 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x05, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x1a, 0x5b, - 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x37, 0x0a, 0x05, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x05, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x22, 0x90, 0x01, 0x0a, 0x0f, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, - 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, - 0x72, 0x6f, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, - 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, - 0x21, 0x0a, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x79, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x53, 0x75, 0x70, 0x70, - 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x69, 0x6e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x54, - 0x0a, 0x0e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4d, 0x69, 0x6e, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, - 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, - 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x16, 0x0a, 0x06, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x54, 0x0a, 0x0e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x75, 0x72, - 0x6e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, + 0x72, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x73, 0x1a, 0x35, 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, + 0x6e, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x65, 0x6e, 0x6f, 0x6d, + 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0x5a, 0x0a, 0x05, 0x49, 0x6e, 0x70, 0x75, + 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x37, 0x0a, 0x05, 0x63, + 0x6f, 0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, + 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, + 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x05, 0x63, + 0x6f, 0x69, 0x6e, 0x73, 0x1a, 0x5b, 0x0a, 0x06, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x18, + 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x37, 0x0a, 0x05, 0x63, 0x6f, 0x69, 0x6e, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, + 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, + 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x05, 0x63, 0x6f, 0x69, 0x6e, + 0x73, 0x22, 0x90, 0x01, 0x0a, 0x0f, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x73, + 0x75, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x69, 0x6e, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x22, 0x54, 0x0a, 0x0e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4d, 0x69, 0x6e, + 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x56, 0x0a, 0x10, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x46, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, + 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x54, 0x0a, 0x0e, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x42, 0x75, 0x72, 0x6e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, + 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x22, 0x56, 0x0a, 0x10, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x46, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4f, + 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, + 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, + 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x58, 0x0a, 0x12, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x55, 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x22, 0x58, 0x0a, 0x12, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x6e, 0x66, 0x72, 0x65, - 0x65, 0x7a, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, - 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x83, 0x03, 0x0a, - 0x09, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, - 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, - 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x32, - 0x0a, 0x15, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6f, 0x74, 0x68, 0x65, - 0x72, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x72, - 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x4f, 0x74, 0x68, 0x65, 0x72, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x74, 0x68, - 0x65, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, - 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4f, 0x74, 0x68, 0x65, 0x72, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x72, 0x61, - 0x6e, 0x64, 0x6f, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1c, - 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x39, 0x0a, 0x06, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, - 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x65, - 0x12, 0x1f, 0x0a, 0x0b, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x73, 0x70, 0x61, 0x6e, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x53, 0x70, 0x61, - 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x22, 0x7a, 0x0a, 0x10, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x48, 0x54, 0x4c, - 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x39, 0x0a, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, - 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, - 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x69, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x77, 0x61, 0x70, 0x49, 0x64, 0x22, 0x61, - 0x0a, 0x0d, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x48, 0x54, 0x4c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, - 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, - 0x72, 0x6f, 0x6d, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x77, 0x61, 0x70, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, - 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x22, 0x3e, 0x0a, 0x0f, 0x52, 0x65, 0x66, 0x75, 0x6e, 0x64, 0x48, 0x54, 0x4c, 0x54, 0x4f, - 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x77, 0x61, 0x70, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x77, 0x61, 0x70, 0x49, - 0x64, 0x22, 0x8d, 0x01, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4f, 0x75, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x39, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, - 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, - 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, - 0x65, 0x22, 0xbf, 0x01, 0x0a, 0x11, 0x53, 0x69, 0x64, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x44, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x6c, 0x65, 0x67, - 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, - 0x0a, 0x0e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, - 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x41, 0x0a, 0x0a, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, - 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, - 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x0a, 0x64, 0x65, - 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x49, 0x64, 0x22, 0xee, 0x01, 0x0a, 0x13, 0x53, 0x69, 0x64, 0x65, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x52, 0x65, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, - 0x64, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, - 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, - 0x12, 0x2c, 0x0a, 0x12, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x64, 0x73, - 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x44, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x39, - 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, + 0x6e, 0x74, 0x22, 0x83, 0x03, 0x0a, 0x09, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, + 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x02, 0x74, 0x6f, 0x12, 0x32, 0x0a, 0x15, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, + 0x74, 0x5f, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x13, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x4f, 0x74, + 0x68, 0x65, 0x72, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x5f, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4f, 0x74, 0x68, 0x65, + 0x72, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, + 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x10, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x48, 0x61, 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x39, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x27, 0x0a, + 0x0f, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x65, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x5f, 0x73, 0x70, 0x61, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x68, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x53, 0x70, 0x61, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x72, 0x6f, 0x73, 0x73, + 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x63, 0x72, + 0x6f, 0x73, 0x73, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x7a, 0x0a, 0x10, 0x44, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, + 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, + 0x12, 0x39, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x73, + 0x77, 0x61, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x77, + 0x61, 0x70, 0x49, 0x64, 0x22, 0x61, 0x0a, 0x0d, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x48, 0x54, 0x4c, + 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x77, 0x61, + 0x70, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x77, 0x61, 0x70, + 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x5f, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x72, 0x61, 0x6e, 0x64, 0x6f, + 0x6d, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3e, 0x0a, 0x0f, 0x52, 0x65, 0x66, 0x75, 0x6e, + 0x64, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, + 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x17, + 0x0a, 0x07, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x06, 0x73, 0x77, 0x61, 0x70, 0x49, 0x64, 0x22, 0x8d, 0x01, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x66, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, + 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x39, 0x0a, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, + 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, + 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x06, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x65, 0x78, 0x70, + 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xbf, 0x01, 0x0a, 0x11, 0x53, 0x69, 0x64, 0x65, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, + 0x0e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, + 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x41, 0x0a, 0x0a, 0x64, + 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x52, 0x0a, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, + 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x22, 0xee, 0x01, 0x0a, 0x13, 0x53, 0x69, + 0x64, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, + 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x67, + 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x53, + 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x6f, 0x72, 0x5f, 0x64, 0x73, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x44, 0x73, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x12, 0x39, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, + 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, + 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x22, 0xb9, 0x01, 0x0a, 0x13, 0x53, + 0x69, 0x64, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, + 0x74, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, + 0x67, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0d, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x12, 0x39, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x22, 0xac, 0x01, 0x0a, 0x0d, 0x54, 0x69, 0x6d, 0x65, 0x4c, + 0x6f, 0x63, 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x6d, + 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, + 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6c, 0x6f, 0x63, + 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xbe, 0x01, 0x0a, 0x0f, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, + 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x6f, + 0x6d, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, + 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x49, 0x64, 0x22, 0xb9, 0x01, 0x0a, 0x13, 0x53, 0x69, 0x64, 0x65, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x25, 0x0a, 0x0e, - 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x41, - 0x64, 0x64, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, - 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, 0x39, 0x0a, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, - 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, - 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, - 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, - 0x22, 0xac, 0x01, 0x0a, 0x0d, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x4f, 0x72, 0x64, - 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, - 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, - 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x22, - 0xbe, 0x01, 0x0a, 0x0f, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, - 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, - 0x4f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, - 0x22, 0x44, 0x0a, 0x0f, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x22, 0xf9, 0x0c, 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x69, - 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, - 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, - 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x65, 0x71, - 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x65, 0x6d, - 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, - 0x65, 0x79, 0x12, 0x3f, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x64, 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65, - 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, - 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x72, 0x61, 0x64, 0x65, - 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0a, 0x74, 0x72, 0x61, 0x64, 0x65, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x12, 0x52, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f, 0x74, 0x72, - 0x61, 0x64, 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x22, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x64, 0x65, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x72, 0x61, - 0x64, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x3c, 0x0a, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x5f, - 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x54, 0x57, - 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, - 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, - 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x47, 0x0a, 0x0c, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x5f, - 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x54, 0x57, - 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x46, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, - 0x00, 0x52, 0x0b, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x4d, - 0x0a, 0x0e, 0x75, 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, - 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, - 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, - 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0d, - 0x75, 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x3c, 0x0a, - 0x0a, 0x68, 0x74, 0x6c, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x6e, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, + 0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6c, 0x6f, + 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x44, 0x0a, 0x0f, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, + 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x6f, + 0x6d, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x22, 0xf9, 0x0c, 0x0a, + 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x19, 0x0a, + 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, + 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, + 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, + 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x3f, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x64, + 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x54, 0x72, 0x61, 0x64, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0a, 0x74, + 0x72, 0x61, 0x64, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x52, 0x0a, 0x12, 0x63, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x5f, 0x74, 0x72, 0x61, 0x64, 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, + 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, + 0x72, 0x61, 0x64, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x63, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x64, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x3c, 0x0a, + 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, - 0x52, 0x09, 0x68, 0x74, 0x6c, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x51, 0x0a, 0x11, 0x64, - 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x48, 0x54, 0x4c, 0x54, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, - 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, - 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, - 0x74, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x64, 0x65, - 0x70, 0x6f, 0x73, 0x69, 0x74, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x4a, - 0x0a, 0x0f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x48, 0x54, 0x4c, 0x54, 0x5f, 0x6f, 0x72, 0x64, 0x65, - 0x72, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, - 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, - 0x48, 0x54, 0x4c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0e, 0x63, 0x6c, 0x61, 0x69, - 0x6d, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x10, 0x72, 0x65, - 0x66, 0x75, 0x6e, 0x64, 0x48, 0x54, 0x4c, 0x54, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x10, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, - 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x66, 0x75, 0x6e, 0x64, 0x48, 0x54, - 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0f, 0x72, 0x65, 0x66, 0x75, 0x6e, - 0x64, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x0b, 0x69, 0x73, - 0x73, 0x75, 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x4f, 0x72, 0x64, - 0x65, 0x72, 0x48, 0x00, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, - 0x12, 0x41, 0x0a, 0x0a, 0x6d, 0x69, 0x6e, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x12, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, - 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4d, 0x69, 0x6e, - 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x09, 0x6d, 0x69, 0x6e, 0x74, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0a, 0x62, 0x75, 0x72, 0x6e, 0x5f, 0x6f, 0x72, 0x64, 0x65, - 0x72, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, - 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x42, 0x75, 0x72, 0x6e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x09, 0x62, 0x75, 0x72, - 0x6e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x4d, 0x0a, 0x12, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, - 0x65, 0x72, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x14, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4f, 0x75, - 0x74, 0x48, 0x00, 0x52, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4f, 0x75, 0x74, - 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x55, 0x0a, 0x13, 0x73, 0x69, 0x64, 0x65, 0x5f, 0x64, 0x65, - 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x15, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x64, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x44, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x11, 0x73, 0x69, 0x64, 0x65, 0x44, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x5b, 0x0a, 0x15, - 0x73, 0x69, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, - 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x54, 0x57, - 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, - 0x69, 0x64, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, - 0x74, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x69, 0x64, 0x65, 0x52, 0x65, 0x64, 0x65, 0x6c, 0x65, - 0x67, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x5b, 0x0a, 0x15, 0x73, 0x69, 0x64, - 0x65, 0x5f, 0x75, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x72, 0x64, - 0x65, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, - 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x64, 0x65, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x48, - 0x00, 0x52, 0x13, 0x73, 0x69, 0x64, 0x65, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, - 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x49, 0x0a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, - 0x6f, 0x63, 0x6b, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1f, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, - 0x48, 0x00, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x4f, 0x72, 0x64, 0x65, - 0x72, 0x12, 0x4f, 0x0a, 0x11, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x65, 0x6c, 0x6f, 0x63, 0x6b, - 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, + 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x47, 0x0a, 0x0c, 0x66, + 0x72, 0x65, 0x65, 0x7a, 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x46, 0x72, 0x65, 0x65, 0x7a, 0x65, + 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4f, + 0x72, 0x64, 0x65, 0x72, 0x12, 0x4d, 0x0a, 0x0e, 0x75, 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, + 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x54, + 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4f, 0x72, 0x64, + 0x65, 0x72, 0x48, 0x00, 0x52, 0x0d, 0x75, 0x6e, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4f, 0x72, + 0x64, 0x65, 0x72, 0x12, 0x3c, 0x0a, 0x0a, 0x68, 0x74, 0x6c, 0x74, 0x5f, 0x6f, 0x72, 0x64, 0x65, + 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, + 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x54, 0x4c, 0x54, 0x4f, + 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x09, 0x68, 0x74, 0x6c, 0x74, 0x4f, 0x72, 0x64, 0x65, + 0x72, 0x12, 0x51, 0x0a, 0x11, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x48, 0x54, 0x4c, 0x54, + 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, - 0x00, 0x52, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x72, 0x64, - 0x65, 0x72, 0x12, 0x4f, 0x0a, 0x11, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x6c, 0x6f, 0x63, - 0x6b, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, + 0x48, 0x00, 0x52, 0x10, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x48, 0x54, 0x4c, 0x54, 0x4f, + 0x72, 0x64, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x0f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x48, 0x54, 0x4c, + 0x54, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x48, 0x54, 0x4c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, + 0x52, 0x0e, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, + 0x12, 0x4e, 0x0a, 0x10, 0x72, 0x65, 0x66, 0x75, 0x6e, 0x64, 0x48, 0x54, 0x4c, 0x54, 0x5f, 0x6f, + 0x72, 0x64, 0x65, 0x72, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, + 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, + 0x66, 0x75, 0x6e, 0x64, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, + 0x0f, 0x72, 0x65, 0x66, 0x75, 0x6e, 0x64, 0x48, 0x54, 0x4c, 0x54, 0x4f, 0x72, 0x64, 0x65, 0x72, + 0x12, 0x44, 0x0a, 0x0b, 0x69, 0x73, 0x73, 0x75, 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, + 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, + 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, + 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0a, 0x6d, 0x69, 0x6e, 0x74, 0x5f, 0x6f, + 0x72, 0x64, 0x65, 0x72, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x54, 0x57, 0x2e, + 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x4d, 0x69, 0x6e, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x09, + 0x6d, 0x69, 0x6e, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0a, 0x62, 0x75, 0x72, + 0x6e, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, - 0x48, 0x00, 0x52, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x6e, 0x65, - 0x6f, 0x66, 0x22, 0x83, 0x01, 0x0a, 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x4f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x33, - 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, - 0x54, 0x57, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x56, 0x0a, 0x15, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x6a, 0x6e, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, - 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x62, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x75, 0x72, 0x6e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, + 0x00, 0x52, 0x09, 0x62, 0x75, 0x72, 0x6e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x4d, 0x0a, 0x12, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, + 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x66, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x48, 0x00, 0x52, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x66, 0x65, 0x72, 0x4f, 0x75, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x55, 0x0a, 0x13, 0x73, + 0x69, 0x64, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, + 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x64, 0x65, + 0x43, 0x68, 0x61, 0x69, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, + 0x11, 0x73, 0x69, 0x64, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, + 0x65, 0x72, 0x12, 0x5b, 0x0a, 0x15, 0x73, 0x69, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x64, 0x65, 0x6c, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x16, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x64, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x65, + 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x69, 0x64, 0x65, + 0x52, 0x65, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, + 0x5b, 0x0a, 0x15, 0x73, 0x69, 0x64, 0x65, 0x5f, 0x75, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, + 0x74, 0x65, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, + 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x53, 0x69, 0x64, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x55, 0x6e, 0x64, 0x65, 0x6c, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x13, 0x73, 0x69, 0x64, 0x65, 0x55, 0x6e, 0x64, + 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x49, 0x0a, 0x0f, + 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, + 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, + 0x63, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x63, + 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x4c, 0x6f, + 0x63, 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x4f, 0x0a, 0x11, 0x74, 0x69, 0x6d, 0x65, 0x5f, + 0x72, 0x65, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x19, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x6c, 0x6f, 0x63, 0x6b, + 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x6c, + 0x6f, 0x63, 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x4f, 0x0a, 0x11, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x1a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, + 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x6c, 0x6f, 0x63, + 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x55, 0x6e, + 0x6c, 0x6f, 0x63, 0x6b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x5f, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x22, 0x83, 0x01, 0x0a, 0x0d, 0x53, 0x69, 0x67, + 0x6e, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, + 0x63, 0x6f, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x63, + 0x6f, 0x64, 0x65, 0x64, 0x12, 0x33, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x54, 0x57, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x17, + 0x0a, 0x15, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x6a, 0x6e, + 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2521,7 +2572,7 @@ func file_Binance_proto_rawDescGZIP() []byte { return file_Binance_proto_rawDescData } -var file_Binance_proto_msgTypes = make([]protoimpl.MessageInfo, 27) +var file_Binance_proto_msgTypes = make([]protoimpl.MessageInfo, 26) var file_Binance_proto_goTypes = []interface{}{ (*Transaction)(nil), // 0: TW.Binance.Proto.Transaction (*Signature)(nil), // 1: TW.Binance.Proto.Signature @@ -2546,23 +2597,22 @@ var file_Binance_proto_goTypes = []interface{}{ (*TimeUnlockOrder)(nil), // 20: TW.Binance.Proto.TimeUnlockOrder (*SigningInput)(nil), // 21: TW.Binance.Proto.SigningInput (*SigningOutput)(nil), // 22: TW.Binance.Proto.SigningOutput - (*Signature_PubKey)(nil), // 23: TW.Binance.Proto.Signature.PubKey - (*SendOrder_Token)(nil), // 24: TW.Binance.Proto.SendOrder.Token - (*SendOrder_Input)(nil), // 25: TW.Binance.Proto.SendOrder.Input - (*SendOrder_Output)(nil), // 26: TW.Binance.Proto.SendOrder.Output - (common.SigningError)(0), // 27: TW.Common.Proto.SigningError + (*SendOrder_Token)(nil), // 23: TW.Binance.Proto.SendOrder.Token + (*SendOrder_Input)(nil), // 24: TW.Binance.Proto.SendOrder.Input + (*SendOrder_Output)(nil), // 25: TW.Binance.Proto.SendOrder.Output + (common.SigningError)(0), // 26: TW.Common.Proto.SigningError } var file_Binance_proto_depIdxs = []int32{ - 25, // 0: TW.Binance.Proto.SendOrder.inputs:type_name -> TW.Binance.Proto.SendOrder.Input - 26, // 1: TW.Binance.Proto.SendOrder.outputs:type_name -> TW.Binance.Proto.SendOrder.Output - 24, // 2: TW.Binance.Proto.HTLTOrder.amount:type_name -> TW.Binance.Proto.SendOrder.Token - 24, // 3: TW.Binance.Proto.DepositHTLTOrder.amount:type_name -> TW.Binance.Proto.SendOrder.Token - 24, // 4: TW.Binance.Proto.TransferOut.amount:type_name -> TW.Binance.Proto.SendOrder.Token - 24, // 5: TW.Binance.Proto.SideChainDelegate.delegation:type_name -> TW.Binance.Proto.SendOrder.Token - 24, // 6: TW.Binance.Proto.SideChainRedelegate.amount:type_name -> TW.Binance.Proto.SendOrder.Token - 24, // 7: TW.Binance.Proto.SideChainUndelegate.amount:type_name -> TW.Binance.Proto.SendOrder.Token - 24, // 8: TW.Binance.Proto.TimeLockOrder.amount:type_name -> TW.Binance.Proto.SendOrder.Token - 24, // 9: TW.Binance.Proto.TimeRelockOrder.amount:type_name -> TW.Binance.Proto.SendOrder.Token + 24, // 0: TW.Binance.Proto.SendOrder.inputs:type_name -> TW.Binance.Proto.SendOrder.Input + 25, // 1: TW.Binance.Proto.SendOrder.outputs:type_name -> TW.Binance.Proto.SendOrder.Output + 23, // 2: TW.Binance.Proto.HTLTOrder.amount:type_name -> TW.Binance.Proto.SendOrder.Token + 23, // 3: TW.Binance.Proto.DepositHTLTOrder.amount:type_name -> TW.Binance.Proto.SendOrder.Token + 23, // 4: TW.Binance.Proto.TransferOut.amount:type_name -> TW.Binance.Proto.SendOrder.Token + 23, // 5: TW.Binance.Proto.SideChainDelegate.delegation:type_name -> TW.Binance.Proto.SendOrder.Token + 23, // 6: TW.Binance.Proto.SideChainRedelegate.amount:type_name -> TW.Binance.Proto.SendOrder.Token + 23, // 7: TW.Binance.Proto.SideChainUndelegate.amount:type_name -> TW.Binance.Proto.SendOrder.Token + 23, // 8: TW.Binance.Proto.TimeLockOrder.amount:type_name -> TW.Binance.Proto.SendOrder.Token + 23, // 9: TW.Binance.Proto.TimeRelockOrder.amount:type_name -> TW.Binance.Proto.SendOrder.Token 2, // 10: TW.Binance.Proto.SigningInput.trade_order:type_name -> TW.Binance.Proto.TradeOrder 3, // 11: TW.Binance.Proto.SigningInput.cancel_trade_order:type_name -> TW.Binance.Proto.CancelTradeOrder 4, // 12: TW.Binance.Proto.SigningInput.send_order:type_name -> TW.Binance.Proto.SendOrder @@ -2582,9 +2632,9 @@ var file_Binance_proto_depIdxs = []int32{ 18, // 26: TW.Binance.Proto.SigningInput.time_lock_order:type_name -> TW.Binance.Proto.TimeLockOrder 19, // 27: TW.Binance.Proto.SigningInput.time_relock_order:type_name -> TW.Binance.Proto.TimeRelockOrder 20, // 28: TW.Binance.Proto.SigningInput.time_unlock_order:type_name -> TW.Binance.Proto.TimeUnlockOrder - 27, // 29: TW.Binance.Proto.SigningOutput.error:type_name -> TW.Common.Proto.SigningError - 24, // 30: TW.Binance.Proto.SendOrder.Input.coins:type_name -> TW.Binance.Proto.SendOrder.Token - 24, // 31: TW.Binance.Proto.SendOrder.Output.coins:type_name -> TW.Binance.Proto.SendOrder.Token + 26, // 29: TW.Binance.Proto.SigningOutput.error:type_name -> TW.Common.Proto.SigningError + 23, // 30: TW.Binance.Proto.SendOrder.Input.coins:type_name -> TW.Binance.Proto.SendOrder.Token + 23, // 31: TW.Binance.Proto.SendOrder.Output.coins:type_name -> TW.Binance.Proto.SendOrder.Token 32, // [32:32] is the sub-list for method output_type 32, // [32:32] is the sub-list for method input_type 32, // [32:32] is the sub-list for extension type_name @@ -2875,18 +2925,6 @@ func file_Binance_proto_init() { } } file_Binance_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Signature_PubKey); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Binance_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SendOrder_Token); i { case 0: return &v.state @@ -2898,7 +2936,7 @@ func file_Binance_proto_init() { return nil } } - file_Binance_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + file_Binance_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SendOrder_Input); i { case 0: return &v.state @@ -2910,7 +2948,7 @@ func file_Binance_proto_init() { return nil } } - file_Binance_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + file_Binance_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SendOrder_Output); i { case 0: return &v.state @@ -2950,7 +2988,7 @@ func file_Binance_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_Binance_proto_rawDesc, NumEnums: 0, - NumMessages: 27, + NumMessages: 26, NumExtensions: 0, NumServices: 0, }, diff --git a/samples/go/protos/bitcoin/Bitcoin.pb.go b/samples/go/protos/bitcoin/Bitcoin.pb.go index 88b884e6912..1758d1bd22e 100644 --- a/samples/go/protos/bitcoin/Bitcoin.pb.go +++ b/samples/go/protos/bitcoin/Bitcoin.pb.go @@ -1,17 +1,17 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.0 -// protoc v3.19.2 +// protoc-gen-go v1.28.1 +// protoc v3.21.5 // source: Bitcoin.proto package bitcoin import ( - common "tw/protos/common" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + common "tw/protos/common" ) const ( @@ -21,6 +21,7 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// A transaction, with its inputs and outputs type Transaction struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -32,7 +33,7 @@ type Transaction struct { LockTime uint32 `protobuf:"varint,2,opt,name=lockTime,proto3" json:"lockTime,omitempty"` // A list of 1 or more transaction inputs or sources for coins. Inputs []*TransactionInput `protobuf:"bytes,3,rep,name=inputs,proto3" json:"inputs,omitempty"` - // A list of 1 or more transaction outputs or destinations for coins + // A list of 1 or more transaction outputs or destinations for coins. Outputs []*TransactionOutput `protobuf:"bytes,4,rep,name=outputs,proto3" json:"outputs,omitempty"` } @@ -169,7 +170,7 @@ type OutPoint struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The hash of the referenced transaction. + // The hash of the referenced transaction (network byte order, usually needs to be reversed). Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` // The index of the specific output in the transaction. Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` @@ -355,64 +356,6 @@ func (x *UnspentTransaction) GetAmount() int64 { return 0 } -// Pair of destination address and amount, used for extra outputs -type OutputAddress struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Destination address - ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` - // Amount to be paid to this output - Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` -} - -func (x *OutputAddress) Reset() { - *x = OutputAddress{} - if protoimpl.UnsafeEnabled { - mi := &file_Bitcoin_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *OutputAddress) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*OutputAddress) ProtoMessage() {} - -func (x *OutputAddress) ProtoReflect() protoreflect.Message { - mi := &file_Bitcoin_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use OutputAddress.ProtoReflect.Descriptor instead. -func (*OutputAddress) Descriptor() ([]byte, []int) { - return file_Bitcoin_proto_rawDescGZIP(), []int{5} -} - -func (x *OutputAddress) GetToAddress() string { - if x != nil { - return x.ToAddress - } - return "" -} - -func (x *OutputAddress) GetAmount() int64 { - if x != nil { - return x.Amount - } - return 0 -} - // Input data necessary to create a signed transaction. type SigningInput struct { state protoimpl.MessageState @@ -425,22 +368,23 @@ type SigningInput struct { // except when use_max_amount is set, in that case this amount is not relevant, maximum possible amount will be used (max avail less fee). // If amount is equal or more than the available amount, also max amount will be used. Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` - // Transaction fee per byte. + // Transaction fee rate, satoshis per byte, used to compute required fee (when planning) ByteFee int64 `protobuf:"varint,3,opt,name=byte_fee,json=byteFee,proto3" json:"byte_fee,omitempty"` - // Recipient's address. + // Recipient's address, as string. ToAddress string `protobuf:"bytes,4,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` - // Change address. + // Change address, as string. ChangeAddress string `protobuf:"bytes,5,opt,name=change_address,json=changeAddress,proto3" json:"change_address,omitempty"` - // Available private keys. + // The available secret private key or keys required for signing (32 bytes each). PrivateKey [][]byte `protobuf:"bytes,6,rep,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"` // Available redeem scripts indexed by script hash. Scripts map[string][]byte `protobuf:"bytes,7,rep,name=scripts,proto3" json:"scripts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - // Available unspent transaction outputs. + // Available input unspent transaction outputs. Utxo []*UnspentTransaction `protobuf:"bytes,8,rep,name=utxo,proto3" json:"utxo,omitempty"` - // If sending max amount. - UseMaxAmount bool `protobuf:"varint,9,opt,name=use_max_amount,json=useMaxAmount,proto3" json:"use_max_amount,omitempty"` - CoinType uint32 `protobuf:"varint,10,opt,name=coin_type,json=coinType,proto3" json:"coin_type,omitempty"` - // Optional transaction plan + // Set if sending max amount is requested. + UseMaxAmount bool `protobuf:"varint,9,opt,name=use_max_amount,json=useMaxAmount,proto3" json:"use_max_amount,omitempty"` + // Coin type (used by forks). + CoinType uint32 `protobuf:"varint,10,opt,name=coin_type,json=coinType,proto3" json:"coin_type,omitempty"` + // Optional transaction plan. If missing, plan will be computed. Plan *TransactionPlan `protobuf:"bytes,11,opt,name=plan,proto3" json:"plan,omitempty"` // Optional lockTime, default value 0 means no time locking. // If all inputs have final (`0xffffffff`) sequence numbers then `lockTime` is irrelevant. @@ -450,18 +394,12 @@ type SigningInput struct { LockTime uint32 `protobuf:"varint,12,opt,name=lock_time,json=lockTime,proto3" json:"lock_time,omitempty"` // Optional zero-amount, OP_RETURN output OutputOpReturn []byte `protobuf:"bytes,13,opt,name=output_op_return,json=outputOpReturn,proto3" json:"output_op_return,omitempty"` - // Optional additional destination addresses, additional to first to_address output - ExtraOutputs []*OutputAddress `protobuf:"bytes,14,rep,name=extra_outputs,json=extraOutputs,proto3" json:"extra_outputs,omitempty"` - // If use max utxo. - UseMaxUtxo bool `protobuf:"varint,15,opt,name=use_max_utxo,json=useMaxUtxo,proto3" json:"use_max_utxo,omitempty"` - // If disable dust filter. - DisableDustFilter bool `protobuf:"varint,16,opt,name=disable_dust_filter,json=disableDustFilter,proto3" json:"disable_dust_filter,omitempty"` } func (x *SigningInput) Reset() { *x = SigningInput{} if protoimpl.UnsafeEnabled { - mi := &file_Bitcoin_proto_msgTypes[6] + mi := &file_Bitcoin_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -474,7 +412,7 @@ func (x *SigningInput) String() string { func (*SigningInput) ProtoMessage() {} func (x *SigningInput) ProtoReflect() protoreflect.Message { - mi := &file_Bitcoin_proto_msgTypes[6] + mi := &file_Bitcoin_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -487,7 +425,7 @@ func (x *SigningInput) ProtoReflect() protoreflect.Message { // Deprecated: Use SigningInput.ProtoReflect.Descriptor instead. func (*SigningInput) Descriptor() ([]byte, []int) { - return file_Bitcoin_proto_rawDescGZIP(), []int{6} + return file_Bitcoin_proto_rawDescGZIP(), []int{5} } func (x *SigningInput) GetHashType() uint32 { @@ -581,27 +519,6 @@ func (x *SigningInput) GetOutputOpReturn() []byte { return nil } -func (x *SigningInput) GetExtraOutputs() []*OutputAddress { - if x != nil { - return x.ExtraOutputs - } - return nil -} - -func (x *SigningInput) GetUseMaxUtxo() bool { - if x != nil { - return x.UseMaxUtxo - } - return false -} - -func (x *SigningInput) GetDisableDustFilter() bool { - if x != nil { - return x.DisableDustFilter - } - return false -} - // Describes a preliminary transaction plan. type TransactionPlan struct { state protoimpl.MessageState @@ -610,13 +527,13 @@ type TransactionPlan struct { // Amount to be received at the other end. Amount int64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"` - // Maximum available amount. + // Maximum available amount in all the input UTXOs. AvailableAmount int64 `protobuf:"varint,2,opt,name=available_amount,json=availableAmount,proto3" json:"available_amount,omitempty"` // Estimated transaction fee. Fee int64 `protobuf:"varint,3,opt,name=fee,proto3" json:"fee,omitempty"` - // Change. + // Remaining change Change int64 `protobuf:"varint,4,opt,name=change,proto3" json:"change,omitempty"` - // Selected unspent transaction outputs. + // Selected unspent transaction outputs (subset of all input UTXOs) Utxos []*UnspentTransaction `protobuf:"bytes,5,rep,name=utxos,proto3" json:"utxos,omitempty"` // Zcash branch id BranchId []byte `protobuf:"bytes,6,opt,name=branch_id,json=branchId,proto3" json:"branch_id,omitempty"` @@ -629,7 +546,7 @@ type TransactionPlan struct { func (x *TransactionPlan) Reset() { *x = TransactionPlan{} if protoimpl.UnsafeEnabled { - mi := &file_Bitcoin_proto_msgTypes[7] + mi := &file_Bitcoin_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -642,7 +559,7 @@ func (x *TransactionPlan) String() string { func (*TransactionPlan) ProtoMessage() {} func (x *TransactionPlan) ProtoReflect() protoreflect.Message { - mi := &file_Bitcoin_proto_msgTypes[7] + mi := &file_Bitcoin_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -655,7 +572,7 @@ func (x *TransactionPlan) ProtoReflect() protoreflect.Message { // Deprecated: Use TransactionPlan.ProtoReflect.Descriptor instead. func (*TransactionPlan) Descriptor() ([]byte, []int) { - return file_Bitcoin_proto_rawDescGZIP(), []int{7} + return file_Bitcoin_proto_rawDescGZIP(), []int{6} } func (x *TransactionPlan) GetAmount() int64 { @@ -714,17 +631,18 @@ func (x *TransactionPlan) GetOutputOpReturn() []byte { return nil } -// Transaction signing output. +// Result containing the signed and encoded transaction. +// Note that the amount may be different than the requested amount to account for fees and available funds. type SigningOutput struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Resulting transaction. Note that the amount may be different than the requested amount to account for fees and available funds. + // Resulting transaction. Transaction *Transaction `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"` // Signed and encoded transaction bytes. Encoded []byte `protobuf:"bytes,2,opt,name=encoded,proto3" json:"encoded,omitempty"` - // Transaction id + // Transaction ID (hash) TransactionId string `protobuf:"bytes,3,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` // Optional error Error common.SigningError `protobuf:"varint,4,opt,name=error,proto3,enum=TW.Common.Proto.SigningError" json:"error,omitempty"` @@ -735,7 +653,7 @@ type SigningOutput struct { func (x *SigningOutput) Reset() { *x = SigningOutput{} if protoimpl.UnsafeEnabled { - mi := &file_Bitcoin_proto_msgTypes[8] + mi := &file_Bitcoin_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -748,7 +666,7 @@ func (x *SigningOutput) String() string { func (*SigningOutput) ProtoMessage() {} func (x *SigningOutput) ProtoReflect() protoreflect.Message { - mi := &file_Bitcoin_proto_msgTypes[8] + mi := &file_Bitcoin_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -761,7 +679,7 @@ func (x *SigningOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use SigningOutput.ProtoReflect.Descriptor instead. func (*SigningOutput) Descriptor() ([]byte, []int) { - return file_Bitcoin_proto_rawDescGZIP(), []int{8} + return file_Bitcoin_proto_rawDescGZIP(), []int{7} } func (x *SigningOutput) GetTransaction() *Transaction { @@ -799,6 +717,7 @@ func (x *SigningOutput) GetErrorMessage() string { return "" } +/// Pre-image hash to be used for signing type HashPublicKey struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -813,7 +732,7 @@ type HashPublicKey struct { func (x *HashPublicKey) Reset() { *x = HashPublicKey{} if protoimpl.UnsafeEnabled { - mi := &file_Bitcoin_proto_msgTypes[9] + mi := &file_Bitcoin_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -826,7 +745,7 @@ func (x *HashPublicKey) String() string { func (*HashPublicKey) ProtoMessage() {} func (x *HashPublicKey) ProtoReflect() protoreflect.Message { - mi := &file_Bitcoin_proto_msgTypes[9] + mi := &file_Bitcoin_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -839,7 +758,7 @@ func (x *HashPublicKey) ProtoReflect() protoreflect.Message { // Deprecated: Use HashPublicKey.ProtoReflect.Descriptor instead. func (*HashPublicKey) Descriptor() ([]byte, []int) { - return file_Bitcoin_proto_rawDescGZIP(), []int{9} + return file_Bitcoin_proto_rawDescGZIP(), []int{8} } func (x *HashPublicKey) GetDataHash() []byte { @@ -873,7 +792,7 @@ type PreSigningOutput struct { func (x *PreSigningOutput) Reset() { *x = PreSigningOutput{} if protoimpl.UnsafeEnabled { - mi := &file_Bitcoin_proto_msgTypes[10] + mi := &file_Bitcoin_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -886,7 +805,7 @@ func (x *PreSigningOutput) String() string { func (*PreSigningOutput) ProtoMessage() {} func (x *PreSigningOutput) ProtoReflect() protoreflect.Message { - mi := &file_Bitcoin_proto_msgTypes[10] + mi := &file_Bitcoin_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -899,7 +818,7 @@ func (x *PreSigningOutput) ProtoReflect() protoreflect.Message { // Deprecated: Use PreSigningOutput.ProtoReflect.Descriptor instead. func (*PreSigningOutput) Descriptor() ([]byte, []int) { - return file_Bitcoin_proto_rawDescGZIP(), []int{10} + return file_Bitcoin_proto_rawDescGZIP(), []int{9} } func (x *PreSigningOutput) GetHashPublicKeys() []*HashPublicKey { @@ -967,53 +886,39 @@ var file_Bitcoin_proto_rawDesc = []byte{ 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x22, 0x46, 0x0a, 0x0d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xdb, 0x05, 0x0a, 0x0c, 0x53, 0x69, - 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x61, - 0x73, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x68, - 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x19, 0x0a, 0x08, 0x62, 0x79, 0x74, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x07, 0x62, 0x79, 0x74, 0x65, 0x46, 0x65, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, - 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, - 0x06, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, - 0x79, 0x12, 0x45, 0x0a, 0x07, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, - 0x75, 0x74, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x07, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x12, 0x38, 0x0a, 0x04, 0x75, 0x74, 0x78, 0x6f, - 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x74, 0x63, - 0x6f, 0x69, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, - 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x75, 0x74, - 0x78, 0x6f, 0x12, 0x24, 0x0a, 0x0e, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x4d, - 0x61, 0x78, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x69, 0x6e, - 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x63, 0x6f, 0x69, - 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, - 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x1b, 0x0a, 0x09, - 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x5f, 0x6f, 0x70, 0x5f, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x18, 0x0d, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4f, 0x70, 0x52, 0x65, 0x74, - 0x75, 0x72, 0x6e, 0x12, 0x44, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x54, 0x57, 0x2e, - 0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0c, 0x65, 0x78, 0x74, - 0x72, 0x61, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x75, 0x73, 0x65, - 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0a, 0x75, 0x73, 0x65, 0x4d, 0x61, 0x78, 0x55, 0x74, 0x78, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x64, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x75, 0x73, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, - 0x65, 0x72, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, - 0x65, 0x44, 0x75, 0x73, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x1a, 0x3a, 0x0a, 0x0c, 0x53, + 0x74, 0x22, 0xc3, 0x04, 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, + 0x75, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x68, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x79, 0x74, 0x65, 0x5f, + 0x66, 0x65, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x79, 0x74, 0x65, 0x46, + 0x65, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x70, + 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x45, 0x0a, 0x07, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x54, 0x57, 0x2e, + 0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, + 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, + 0x12, 0x38, 0x0a, 0x04, 0x75, 0x74, 0x78, 0x6f, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, + 0x2e, 0x54, 0x57, 0x2e, 0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x75, 0x74, 0x78, 0x6f, 0x12, 0x24, 0x0a, 0x0e, 0x75, 0x73, + 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x4d, 0x61, 0x78, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x08, 0x63, 0x6f, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x35, 0x0a, + 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x54, 0x57, + 0x2e, 0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x04, + 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, + 0x65, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6f, 0x70, 0x5f, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x4f, 0x70, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x1a, 0x3a, 0x0a, 0x0c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, @@ -1068,13 +973,9 @@ var file_Bitcoin_proto_rawDesc = []byte{ 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x58, + 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x17, 0x0a, 0x15, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x6a, 0x6e, - 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x3f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x75, - 0x74, 0x78, 0x6f, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1089,42 +990,40 @@ func file_Bitcoin_proto_rawDescGZIP() []byte { return file_Bitcoin_proto_rawDescData } -var file_Bitcoin_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_Bitcoin_proto_msgTypes = make([]protoimpl.MessageInfo, 11) var file_Bitcoin_proto_goTypes = []interface{}{ (*Transaction)(nil), // 0: TW.Bitcoin.Proto.Transaction (*TransactionInput)(nil), // 1: TW.Bitcoin.Proto.TransactionInput (*OutPoint)(nil), // 2: TW.Bitcoin.Proto.OutPoint (*TransactionOutput)(nil), // 3: TW.Bitcoin.Proto.TransactionOutput (*UnspentTransaction)(nil), // 4: TW.Bitcoin.Proto.UnspentTransaction - (*OutputAddress)(nil), // 5: TW.Bitcoin.Proto.OutputAddress - (*SigningInput)(nil), // 6: TW.Bitcoin.Proto.SigningInput - (*TransactionPlan)(nil), // 7: TW.Bitcoin.Proto.TransactionPlan - (*SigningOutput)(nil), // 8: TW.Bitcoin.Proto.SigningOutput - (*HashPublicKey)(nil), // 9: TW.Bitcoin.Proto.HashPublicKey - (*PreSigningOutput)(nil), // 10: TW.Bitcoin.Proto.PreSigningOutput - nil, // 11: TW.Bitcoin.Proto.SigningInput.ScriptsEntry - (common.SigningError)(0), // 12: TW.Common.Proto.SigningError + (*SigningInput)(nil), // 5: TW.Bitcoin.Proto.SigningInput + (*TransactionPlan)(nil), // 6: TW.Bitcoin.Proto.TransactionPlan + (*SigningOutput)(nil), // 7: TW.Bitcoin.Proto.SigningOutput + (*HashPublicKey)(nil), // 8: TW.Bitcoin.Proto.HashPublicKey + (*PreSigningOutput)(nil), // 9: TW.Bitcoin.Proto.PreSigningOutput + nil, // 10: TW.Bitcoin.Proto.SigningInput.ScriptsEntry + (common.SigningError)(0), // 11: TW.Common.Proto.SigningError } var file_Bitcoin_proto_depIdxs = []int32{ 1, // 0: TW.Bitcoin.Proto.Transaction.inputs:type_name -> TW.Bitcoin.Proto.TransactionInput 3, // 1: TW.Bitcoin.Proto.Transaction.outputs:type_name -> TW.Bitcoin.Proto.TransactionOutput 2, // 2: TW.Bitcoin.Proto.TransactionInput.previousOutput:type_name -> TW.Bitcoin.Proto.OutPoint 2, // 3: TW.Bitcoin.Proto.UnspentTransaction.out_point:type_name -> TW.Bitcoin.Proto.OutPoint - 11, // 4: TW.Bitcoin.Proto.SigningInput.scripts:type_name -> TW.Bitcoin.Proto.SigningInput.ScriptsEntry + 10, // 4: TW.Bitcoin.Proto.SigningInput.scripts:type_name -> TW.Bitcoin.Proto.SigningInput.ScriptsEntry 4, // 5: TW.Bitcoin.Proto.SigningInput.utxo:type_name -> TW.Bitcoin.Proto.UnspentTransaction - 7, // 6: TW.Bitcoin.Proto.SigningInput.plan:type_name -> TW.Bitcoin.Proto.TransactionPlan - 5, // 7: TW.Bitcoin.Proto.SigningInput.extra_outputs:type_name -> TW.Bitcoin.Proto.OutputAddress - 4, // 8: TW.Bitcoin.Proto.TransactionPlan.utxos:type_name -> TW.Bitcoin.Proto.UnspentTransaction - 12, // 9: TW.Bitcoin.Proto.TransactionPlan.error:type_name -> TW.Common.Proto.SigningError - 0, // 10: TW.Bitcoin.Proto.SigningOutput.transaction:type_name -> TW.Bitcoin.Proto.Transaction - 12, // 11: TW.Bitcoin.Proto.SigningOutput.error:type_name -> TW.Common.Proto.SigningError - 9, // 12: TW.Bitcoin.Proto.PreSigningOutput.hash_public_keys:type_name -> TW.Bitcoin.Proto.HashPublicKey - 12, // 13: TW.Bitcoin.Proto.PreSigningOutput.error:type_name -> TW.Common.Proto.SigningError - 14, // [14:14] is the sub-list for method output_type - 14, // [14:14] is the sub-list for method input_type - 14, // [14:14] is the sub-list for extension type_name - 14, // [14:14] is the sub-list for extension extendee - 0, // [0:14] is the sub-list for field type_name + 6, // 6: TW.Bitcoin.Proto.SigningInput.plan:type_name -> TW.Bitcoin.Proto.TransactionPlan + 4, // 7: TW.Bitcoin.Proto.TransactionPlan.utxos:type_name -> TW.Bitcoin.Proto.UnspentTransaction + 11, // 8: TW.Bitcoin.Proto.TransactionPlan.error:type_name -> TW.Common.Proto.SigningError + 0, // 9: TW.Bitcoin.Proto.SigningOutput.transaction:type_name -> TW.Bitcoin.Proto.Transaction + 11, // 10: TW.Bitcoin.Proto.SigningOutput.error:type_name -> TW.Common.Proto.SigningError + 8, // 11: TW.Bitcoin.Proto.PreSigningOutput.hash_public_keys:type_name -> TW.Bitcoin.Proto.HashPublicKey + 11, // 12: TW.Bitcoin.Proto.PreSigningOutput.error:type_name -> TW.Common.Proto.SigningError + 13, // [13:13] is the sub-list for method output_type + 13, // [13:13] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension type_name + 13, // [13:13] is the sub-list for extension extendee + 0, // [0:13] is the sub-list for field type_name } func init() { file_Bitcoin_proto_init() } @@ -1194,18 +1093,6 @@ func file_Bitcoin_proto_init() { } } file_Bitcoin_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OutputAddress); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Bitcoin_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SigningInput); i { case 0: return &v.state @@ -1217,7 +1104,7 @@ func file_Bitcoin_proto_init() { return nil } } - file_Bitcoin_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_Bitcoin_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TransactionPlan); i { case 0: return &v.state @@ -1229,7 +1116,7 @@ func file_Bitcoin_proto_init() { return nil } } - file_Bitcoin_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_Bitcoin_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SigningOutput); i { case 0: return &v.state @@ -1241,7 +1128,7 @@ func file_Bitcoin_proto_init() { return nil } } - file_Bitcoin_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_Bitcoin_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*HashPublicKey); i { case 0: return &v.state @@ -1253,7 +1140,7 @@ func file_Bitcoin_proto_init() { return nil } } - file_Bitcoin_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_Bitcoin_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PreSigningOutput); i { case 0: return &v.state @@ -1272,7 +1159,7 @@ func file_Bitcoin_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_Bitcoin_proto_rawDesc, NumEnums: 0, - NumMessages: 12, + NumMessages: 11, NumExtensions: 0, NumServices: 0, }, diff --git a/samples/go/protos/common/Common.pb.go b/samples/go/protos/common/Common.pb.go index bc50f992214..ddf4fd142cc 100644 --- a/samples/go/protos/common/Common.pb.go +++ b/samples/go/protos/common/Common.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.0 -// protoc v3.19.2 +// protoc-gen-go v1.28.1 +// protoc v3.21.5 // source: Common.proto package common @@ -20,38 +20,65 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// Error codes, used in multiple blockchains. type SigningError int32 const ( - SigningError_OK SigningError = 0 // OK - // chain-generic, generic - SigningError_Error_general SigningError = 1 + // This is the OK case, with value=0 + SigningError_OK SigningError = 0 + // Chain-generic codes: + // Generic error (used if there is no suitable specific error is adequate) + SigningError_Error_general SigningError = 1 + // Internal error, indicates some very unusual, unexpected case SigningError_Error_internal SigningError = 2 - // chain-generic, input - SigningError_Error_low_balance SigningError = 3 - SigningError_Error_zero_amount_requested SigningError = 4 // Requested amount is zero - SigningError_Error_missing_private_key SigningError = 5 - SigningError_Error_invalid_private_key SigningError = 15 - SigningError_Error_invalid_address SigningError = 16 - SigningError_Error_invalid_utxo SigningError = 17 - SigningError_Error_invalid_utxo_amount SigningError = 18 - // chain-generic, fee + // Chain-generic codes, input related: + // Low balance: the sender balance is not enough to cover the send and other auxiliary amount such as fee, deposit, or minimal balance. + SigningError_Error_low_balance SigningError = 3 + // Requested amount is zero, send of 0 makes no sense + SigningError_Error_zero_amount_requested SigningError = 4 + // One required key is missing (too few or wrong keys are provided) + SigningError_Error_missing_private_key SigningError = 5 + // A private key provided is invalid (e.g. wrong size, usually should be 32 bytes) + SigningError_Error_invalid_private_key SigningError = 15 + // A provided address (e.g. destination address) is invalid + SigningError_Error_invalid_address SigningError = 16 + // A provided input UTXO is invalid + SigningError_Error_invalid_utxo SigningError = 17 + // The amount of an input UTXO is invalid + SigningError_Error_invalid_utxo_amount SigningError = 18 + // Chain-generic, fee related: + // Wrong fee is given, probably it is too low to cover minimal fee for the transaction SigningError_Error_wrong_fee SigningError = 6 - // chain-generic, signing - SigningError_Error_signing SigningError = 7 - SigningError_Error_tx_too_big SigningError = 8 // [NEO] Transaction too big, fee in GAS needed or try send by parts - // UTXO-chain specific, inputs - SigningError_Error_missing_input_utxos SigningError = 9 // No UTXOs provided [BTC] - SigningError_Error_not_enough_utxos SigningError = 10 // Not enough non-dust input UTXOs to cover requested amount (dust UTXOs are filtered out) [BTC] - // UTXO-chain specific, script - SigningError_Error_script_redeem SigningError = 11 // [BTC] Missing redeem script - SigningError_Error_script_output SigningError = 12 // [BTC] Invalid output script - SigningError_Error_script_witness_program SigningError = 13 // [BTC] Unrecognized witness program - SigningError_Error_invalid_memo SigningError = 14 // e.g. [XRP] Invalid tag - SigningError_Error_input_parse SigningError = 19 // e.g. Invalid input data - SigningError_Error_no_support_n2n SigningError = 20 // e.g. Not support n2n transaction - SigningError_Error_signatures_count SigningError = 21 // Incorrect count of signatures passed to compile - SigningError_Error_invalid_params SigningError = 22 // Incorrect parameters + // Chain-generic, signing related: + // General signing error + SigningError_Error_signing SigningError = 7 + // Resulting transaction is too large + // [NEO] Transaction too big, fee in GAS needed or try send by parts + SigningError_Error_tx_too_big SigningError = 8 + // UTXO-chain specific, input related: + // No input UTXOs provided [BTC] + SigningError_Error_missing_input_utxos SigningError = 9 + // Not enough non-dust input UTXOs to cover requested amount (dust UTXOs are filtered out) [BTC] + SigningError_Error_not_enough_utxos SigningError = 10 + // UTXO-chain specific, script related: + // [BTC] Missing required redeem script + SigningError_Error_script_redeem SigningError = 11 + // [BTC] Invalid required output script + SigningError_Error_script_output SigningError = 12 + // [BTC] Unrecognized witness program + SigningError_Error_script_witness_program SigningError = 13 + // Invalid memo, e.g. [XRP] Invalid tag + SigningError_Error_invalid_memo SigningError = 14 + // Some input field cannot be parsed + SigningError_Error_input_parse SigningError = 19 + // Multi-input and multi-output transaction not supported + SigningError_Error_no_support_n2n SigningError = 20 + // Incorrect count of signatures passed to compile + SigningError_Error_signatures_count SigningError = 21 + // Incorrect input parameter + SigningError_Error_invalid_params SigningError = 22 + // Invalid input token amount + SigningError_Error_invalid_requested_token_amount SigningError = 23 ) // Enum value maps for SigningError. @@ -80,31 +107,33 @@ var ( 20: "Error_no_support_n2n", 21: "Error_signatures_count", 22: "Error_invalid_params", + 23: "Error_invalid_requested_token_amount", } SigningError_value = map[string]int32{ - "OK": 0, - "Error_general": 1, - "Error_internal": 2, - "Error_low_balance": 3, - "Error_zero_amount_requested": 4, - "Error_missing_private_key": 5, - "Error_invalid_private_key": 15, - "Error_invalid_address": 16, - "Error_invalid_utxo": 17, - "Error_invalid_utxo_amount": 18, - "Error_wrong_fee": 6, - "Error_signing": 7, - "Error_tx_too_big": 8, - "Error_missing_input_utxos": 9, - "Error_not_enough_utxos": 10, - "Error_script_redeem": 11, - "Error_script_output": 12, - "Error_script_witness_program": 13, - "Error_invalid_memo": 14, - "Error_input_parse": 19, - "Error_no_support_n2n": 20, - "Error_signatures_count": 21, - "Error_invalid_params": 22, + "OK": 0, + "Error_general": 1, + "Error_internal": 2, + "Error_low_balance": 3, + "Error_zero_amount_requested": 4, + "Error_missing_private_key": 5, + "Error_invalid_private_key": 15, + "Error_invalid_address": 16, + "Error_invalid_utxo": 17, + "Error_invalid_utxo_amount": 18, + "Error_wrong_fee": 6, + "Error_signing": 7, + "Error_tx_too_big": 8, + "Error_missing_input_utxos": 9, + "Error_not_enough_utxos": 10, + "Error_script_redeem": 11, + "Error_script_output": 12, + "Error_script_witness_program": 13, + "Error_invalid_memo": 14, + "Error_input_parse": 19, + "Error_no_support_n2n": 20, + "Error_signatures_count": 21, + "Error_invalid_params": 22, + "Error_invalid_requested_token_amount": 23, } ) @@ -140,7 +169,7 @@ var File_Common_proto protoreflect.FileDescriptor var file_Common_proto_rawDesc = []byte{ 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x54, 0x57, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2a, - 0xd1, 0x04, 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0xfb, 0x04, 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x10, 0x02, 0x12, @@ -177,13 +206,11 @@ var file_Common_proto_rawDesc = []byte{ 0x16, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x10, 0x15, 0x12, 0x18, 0x0a, 0x14, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x10, 0x16, 0x42, 0x55, 0x0a, 0x15, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x63, 0x6f, - 0x72, 0x65, 0x2e, 0x6a, 0x6e, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x3c, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, - 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2d, 0x69, 0x6e, 0x74, - 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, - 0x61, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x73, 0x10, 0x16, 0x12, 0x28, 0x0a, 0x24, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x69, 0x6e, 0x76, + 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x10, 0x17, 0x42, 0x17, 0x0a, + 0x15, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x6a, 0x6e, 0x69, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/samples/go/protos/ethereum/Ethereum.pb.go b/samples/go/protos/ethereum/Ethereum.pb.go index 14707736bce..ef2cad5cac3 100644 --- a/samples/go/protos/ethereum/Ethereum.pb.go +++ b/samples/go/protos/ethereum/Ethereum.pb.go @@ -1,17 +1,17 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.0 -// protoc v3.19.2 +// protoc-gen-go v1.28.1 +// protoc v3.21.5 // source: Ethereum.proto package ethereum import ( - common "tw/protos/common" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + common "tw/protos/common" ) const ( @@ -21,11 +21,14 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// Transaction type type TransactionMode int32 const ( - TransactionMode_Legacy TransactionMode = 0 // Legacy transaction, pre-EIP2718/EIP1559; for fee gasPrice/gasLimit is used - TransactionMode_Enveloped TransactionMode = 1 // Enveloped transaction EIP2718 (with type 0x2), fee is according to EIP1559 (base fee, inclusion fee, ...) + // Legacy transaction, pre-EIP2718/EIP1559; for fee gasPrice/gasLimit is used + TransactionMode_Legacy TransactionMode = 0 + // Enveloped transaction EIP2718 (with type 0x2), fee is according to EIP1559 (base fee, inclusion fee, ...) + TransactionMode_Enveloped TransactionMode = 1 ) // Enum value maps for TransactionMode. @@ -73,6 +76,8 @@ type Transaction struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Payload transfer + // // Types that are assignable to TransactionOneof: // *Transaction_Transfer_ // *Transaction_Erc20Transfer @@ -211,28 +216,29 @@ type SigningInput struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Chain identifier (256-bit number) + // Chain identifier (uint256, serialized little endian) ChainId []byte `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` - // Nonce (256-bit number) + // Nonce (uint256, serialized little endian) Nonce []byte `protobuf:"bytes,2,opt,name=nonce,proto3" json:"nonce,omitempty"` // Transaction version selector: Legacy or enveloped, has impact on fee structure. // Default is Legacy (value 0) TxMode TransactionMode `protobuf:"varint,3,opt,name=tx_mode,json=txMode,proto3,enum=TW.Ethereum.Proto.TransactionMode" json:"tx_mode,omitempty"` - // Gas price (256-bit number) + // Gas price (uint256, serialized little endian) // Relevant for legacy transactions only (disregarded for enveloped/EIP1559) GasPrice []byte `protobuf:"bytes,4,opt,name=gas_price,json=gasPrice,proto3" json:"gas_price,omitempty"` - // Gas limit (256-bit number) + // Gas limit (uint256, serialized little endian) GasLimit []byte `protobuf:"bytes,5,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` - // Maxinmum optional inclusion fee (aka tip) (256-bit number) + // Maximum optional inclusion fee (aka tip) (uint256, serialized little endian) // Relevant for enveloped/EIP1559 transactions only, tx_mode=Enveloped, (disregarded for legacy) MaxInclusionFeePerGas []byte `protobuf:"bytes,6,opt,name=max_inclusion_fee_per_gas,json=maxInclusionFeePerGas,proto3" json:"max_inclusion_fee_per_gas,omitempty"` - // Maxinmum fee (256-bit number) + // Maximum fee (uint256, serialized little endian) // Relevant for enveloped/EIP1559 transactions only, tx_mode=Enveloped, (disregarded for legacy) MaxFeePerGas []byte `protobuf:"bytes,7,opt,name=max_fee_per_gas,json=maxFeePerGas,proto3" json:"max_fee_per_gas,omitempty"` // Recipient's address. ToAddress string `protobuf:"bytes,8,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` - // Private key. - PrivateKey []byte `protobuf:"bytes,9,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"` + // The secret private key used for signing (32 bytes). + PrivateKey []byte `protobuf:"bytes,9,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"` + // The payload transaction Transaction *Transaction `protobuf:"bytes,10,opt,name=transaction,proto3" json:"transaction,omitempty"` } @@ -338,7 +344,7 @@ func (x *SigningInput) GetTransaction() *Transaction { return nil } -// Transaction signing output. +// Result containing the signed and encoded transaction. type SigningOutput struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -346,14 +352,15 @@ type SigningOutput struct { // Signed and encoded transaction bytes. Encoded []byte `protobuf:"bytes,1,opt,name=encoded,proto3" json:"encoded,omitempty"` - V []byte `protobuf:"bytes,2,opt,name=v,proto3" json:"v,omitempty"` - R []byte `protobuf:"bytes,3,opt,name=r,proto3" json:"r,omitempty"` - S []byte `protobuf:"bytes,4,opt,name=s,proto3" json:"s,omitempty"` + // The V, R, S components of the resulting signature, (each uint256, serialized little endian) + V []byte `protobuf:"bytes,2,opt,name=v,proto3" json:"v,omitempty"` + R []byte `protobuf:"bytes,3,opt,name=r,proto3" json:"r,omitempty"` + S []byte `protobuf:"bytes,4,opt,name=s,proto3" json:"s,omitempty"` // The payload part, supplied in the input or assembled from input parameters Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` - /// error code, 0 is ok, other codes will be treated as errors + // error code, 0 is ok, other codes will be treated as errors Error common.SigningError `protobuf:"varint,6,opt,name=error,proto3,enum=TW.Common.Proto.SigningError" json:"error,omitempty"` - /// error code description + // error code description ErrorMessage string `protobuf:"bytes,7,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` } @@ -444,7 +451,7 @@ type Transaction_Transfer struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Amount to send in wei (256-bit number) + // Amount to send in wei (uint256, serialized little endian) Amount []byte `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` // Optional payload data Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` @@ -502,8 +509,9 @@ type Transaction_ERC20Transfer struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // destination address (string) To string `protobuf:"bytes,1,opt,name=to,proto3" json:"to,omitempty"` - // Amount to send (256-bit number) + // Amount to send (uint256, serialized little endian) Amount []byte `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"` } @@ -559,8 +567,9 @@ type Transaction_ERC20Approve struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Target of the approval Spender string `protobuf:"bytes,1,opt,name=spender,proto3" json:"spender,omitempty"` - // Amount to send (256-bit number) + // Amount to send (uint256, serialized little endian) Amount []byte `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"` } @@ -616,9 +625,11 @@ type Transaction_ERC721Transfer struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Source address From string `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` - To string `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` - // ID of the token (256-bit number) + // Destination address + To string `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` + // ID of the token (uint256, serialized little endian) TokenId []byte `protobuf:"bytes,3,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` } @@ -681,11 +692,13 @@ type Transaction_ERC1155Transfer struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Source address From string `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` - To string `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` - // ID of the token (256-bit number) + // Destination address + To string `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` + // ID of the token (uint256, serialized little endian) TokenId []byte `protobuf:"bytes,3,opt,name=token_id,json=tokenId,proto3" json:"token_id,omitempty"` - // The amount of tokens being transferred + // The amount of tokens being transferred (uint256, serialized little endian) Value []byte `protobuf:"bytes,4,opt,name=value,proto3" json:"value,omitempty"` Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` } @@ -763,7 +776,7 @@ type Transaction_ContractGeneric struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Amount to send in wei (256-bit number) + // Amount to send in wei (uint256, serialized little endian) Amount []byte `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` // Contract call payload data Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` @@ -924,13 +937,9 @@ var file_Ethereum_proto_rawDesc = []byte{ 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x2c, 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x6e, - 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x10, 0x01, 0x42, 0x57, 0x0a, 0x15, 0x77, 0x61, 0x6c, + 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x10, 0x01, 0x42, 0x17, 0x0a, 0x15, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x6a, 0x6e, 0x69, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, - 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, - 0x75, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/samples/go/protos/common/TransactionCompiler.pb.go b/samples/go/protos/transactioncompiler/TransactionCompiler.pb.go similarity index 87% rename from samples/go/protos/common/TransactionCompiler.pb.go rename to samples/go/protos/transactioncompiler/TransactionCompiler.pb.go index 8baf5d4f998..d71cf247ce1 100644 --- a/samples/go/protos/common/TransactionCompiler.pb.go +++ b/samples/go/protos/transactioncompiler/TransactionCompiler.pb.go @@ -1,16 +1,17 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.0 -// protoc v3.19.2 +// protoc-gen-go v1.28.1 +// protoc v3.21.5 // source: TransactionCompiler.proto -package common +package transactioncompiler import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + common "tw/protos/common" ) const ( @@ -31,7 +32,7 @@ type PreSigningOutput struct { /// Pre-image data Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` /// error code, 0 is ok, other codes will be treated as errors - Error SigningError `protobuf:"varint,3,opt,name=error,proto3,enum=TW.Common.Proto.SigningError" json:"error,omitempty"` + Error common.SigningError `protobuf:"varint,3,opt,name=error,proto3,enum=TW.Common.Proto.SigningError" json:"error,omitempty"` /// error code description ErrorMessage string `protobuf:"bytes,4,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` } @@ -82,11 +83,11 @@ func (x *PreSigningOutput) GetData() []byte { return nil } -func (x *PreSigningOutput) GetError() SigningError { +func (x *PreSigningOutput) GetError() common.SigningError { if x != nil { return x.Error } - return SigningError_OK + return common.SigningError(0) } func (x *PreSigningOutput) GetErrorMessage() string { @@ -112,13 +113,9 @@ var file_TransactionCompiler_proto_rawDesc = []byte{ 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x55, + 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x17, 0x0a, 0x15, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x6a, 0x6e, - 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -136,7 +133,7 @@ func file_TransactionCompiler_proto_rawDescGZIP() []byte { var file_TransactionCompiler_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_TransactionCompiler_proto_goTypes = []interface{}{ (*PreSigningOutput)(nil), // 0: TW.TxCompiler.Proto.PreSigningOutput - (SigningError)(0), // 1: TW.Common.Proto.SigningError + (common.SigningError)(0), // 1: TW.Common.Proto.SigningError } var file_TransactionCompiler_proto_depIdxs = []int32{ 1, // 0: TW.TxCompiler.Proto.PreSigningOutput.error:type_name -> TW.Common.Proto.SigningError @@ -152,7 +149,6 @@ func file_TransactionCompiler_proto_init() { if File_TransactionCompiler_proto != nil { return } - file_Common_proto_init() if !protoimpl.UnsafeEnabled { file_TransactionCompiler_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PreSigningOutput); i { diff --git a/samples/go/sample/external_signing.go b/samples/go/sample/external_signing.go index 636f56dbc0d..87b5b96d6b3 100644 --- a/samples/go/sample/external_signing.go +++ b/samples/go/sample/external_signing.go @@ -7,8 +7,8 @@ import ( "tw/core" "tw/protos/binance" "tw/protos/bitcoin" - "tw/protos/common" "tw/protos/ethereum" + "tw/protos/transactioncompiler" "google.golang.org/protobuf/proto" ) @@ -30,10 +30,10 @@ func SignExternalBinanceDemo() { coin, "bnb1grpf0955h0ykzq3ar5nmum7y6gdfl6lxfn46h2", // from "bnb1hlly02l6ahjsgxw9wlcswnlwdhg4xhx38yxpd5", // to - "1", // amount - "BNB", // asset - "", // memo - "", // chainId + "1", // amount + "BNB", // asset + "", // memo + "", // chainId ) fmt.Println("txInputData len: ", len(txInputData)) @@ -41,7 +41,7 @@ func SignExternalBinanceDemo() { hashes := core.PreImageHashes(coin, txInputData) fmt.Println("hash(es): ", len(hashes), hex.EncodeToString(hashes)) - var preSigningOutput common.PreSigningOutput + var preSigningOutput transactioncompiler.PreSigningOutput proto.Unmarshal(hashes, &preSigningOutput) fmt.Println("\n==> Step 3: Compile transaction info") @@ -93,7 +93,7 @@ func SignExternalEthereumDemo() { hashes := core.PreImageHashes(coin, txInputData2) fmt.Println("hash(es): ", len(hashes), hex.EncodeToString(hashes)) - var preSigningOutput common.PreSigningOutput + var preSigningOutput transactioncompiler.PreSigningOutput proto.Unmarshal(hashes, &preSigningOutput) fmt.Println("\n==> Step 3: Compile transaction info") diff --git a/samples/go/types/twdata.go b/samples/go/types/twdata.go index dcb7bdc95f8..5bc9fa90f77 100644 --- a/samples/go/types/twdata.go +++ b/samples/go/types/twdata.go @@ -1,7 +1,7 @@ package types // #cgo CFLAGS: -I../../../include -// #cgo LDFLAGS: -L../../../build -L../../../build/trezor-crypto -lTrustWalletCore -lprotobuf -lTrezorCrypto -lstdc++ -lm +// #cgo LDFLAGS: -L../../../build -L../../../build/local/lib -L../../../build/trezor-crypto -lTrustWalletCore -lwallet_core_rs -lprotobuf -lTrezorCrypto -lstdc++ -lm // #include import "C" diff --git a/samples/go/types/twstring.go b/samples/go/types/twstring.go index 3c5b2668c64..b61c52c565a 100644 --- a/samples/go/types/twstring.go +++ b/samples/go/types/twstring.go @@ -1,7 +1,7 @@ package types // #cgo CFLAGS: -I../../../include -// #cgo LDFLAGS: -L../../../build -L../../../build/trezor-crypto -lTrustWalletCore -lprotobuf -lTrezorCrypto -lstdc++ -lm +// #cgo LDFLAGS: -L../../../build -L../../../build/local/lib -L../../../build/trezor-crypto -lTrustWalletCore -lwallet_core_rs -lprotobuf -lTrezorCrypto -lstdc++ -lm // #include import "C" diff --git a/samples/rust/src/build.rs b/samples/rust/src/build.rs index cb96ab2c9c9..4f98962f974 100644 --- a/samples/rust/src/build.rs +++ b/samples/rust/src/build.rs @@ -11,7 +11,7 @@ use std::path::Path; static WALLET_CORE_PROJECT_DIR: &str = "../.."; // libs to link with, in reverse dependency order -static LIBS: [&str; 3] = ["TrustWalletCore", "TrezorCrypto", "protobuf"]; +static LIBS: [&str; 4] = ["TrustWalletCore", "TrezorCrypto", "protobuf", "wallet_core_rs"]; fn main() { // Generate protobuf interface files @@ -33,6 +33,7 @@ fn main() { println!("cargo:rustc-link-search=native={}/build", WALLET_CORE_PROJECT_DIR); println!("cargo:rustc-link-search=native={}/build/trezor-crypto", WALLET_CORE_PROJECT_DIR); + println!("cargo:rustc-link-search=native={}/build/local/lib", WALLET_CORE_PROJECT_DIR); // Libraries; order matters for i in 0..LIBS.len() { diff --git a/src/Aptos/Signer.cpp b/src/Aptos/Signer.cpp index 9c15ea200af..9ee223e5601 100644 --- a/src/Aptos/Signer.cpp +++ b/src/Aptos/Signer.cpp @@ -131,27 +131,38 @@ TransactionPayload registerTokenPayload(const Proto::SigningInput& input) { Proto::SigningOutput blindSign(const Proto::SigningInput& input) { auto output = Proto::SigningOutput(); - BCS::Serializer serializer; - auto encodedCall = parse_hex(input.any_encoded()); - serializer.add_bytes(begin(encodedCall), end(encodedCall)); auto privateKey = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); - auto signature = privateKey.sign(encodedCall, TWCurveED25519); auto pubKeyData = privateKey.getPublicKey(TWPublicKeyTypeED25519).bytes; - output.set_raw_txn(encodedCall.data(), encodedCall.size()); - output.mutable_authenticator()->set_public_key(pubKeyData.data(), pubKeyData.size()); - output.mutable_authenticator()->set_signature(signature.data(), signature.size()); - serializer << BCS::uleb128{.value = 0} << pubKeyData << signature; - output.set_encoded(serializer.bytes.data(), serializer.bytes.size()); - - // clang-format off - nlohmann::json json = { - {"type", "ed25519_signature"}, - {"public_key", hexEncoded(pubKeyData)}, - {"signature", hexEncoded(signature)} - }; - // clang-format on - - output.set_json(json.dump()); + if (nlohmann::json j = nlohmann::json::parse(input.any_encoded(), nullptr, false); j.is_discarded()) { + BCS::Serializer serializer; + auto encodedCall = parse_hex(input.any_encoded()); + serializer.add_bytes(begin(encodedCall), end(encodedCall)); + auto signature = privateKey.sign(encodedCall, TWCurveED25519); + output.set_raw_txn(encodedCall.data(), encodedCall.size()); + output.mutable_authenticator()->set_public_key(pubKeyData.data(), pubKeyData.size()); + output.mutable_authenticator()->set_signature(signature.data(), signature.size()); + serializer << BCS::uleb128{.value = 0} << pubKeyData << signature; + output.set_encoded(serializer.bytes.data(), serializer.bytes.size()); + + // clang-format off + nlohmann::json json = { + {"type", "ed25519_signature"}, + {"public_key", hexEncoded(pubKeyData)}, + {"signature", hexEncoded(signature)} + }; + // clang-format on + output.set_json(json.dump()); + } else { + TransactionBuilder::builder() + .sender(Address(input.sender())) + .sequenceNumber(input.sequence_number()) + .payload(EntryFunction::from_json(j)) + .maxGasAmount(input.max_gas_amount()) + .gasUnitPrice(input.gas_unit_price()) + .expirationTimestampSecs(input.expiration_timestamp_secs()) + .chainId(static_cast(input.chain_id())) + .sign(input, output); + } return output; } diff --git a/src/Aptos/TransactionPayload.cpp b/src/Aptos/TransactionPayload.cpp index 1e5b188e290..bc39b80866e 100644 --- a/src/Aptos/TransactionPayload.cpp +++ b/src/Aptos/TransactionPayload.cpp @@ -4,6 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include "rust/bindgen/WalletCoreRSBindgen.h" #include #include @@ -54,4 +55,65 @@ nlohmann::json EntryFunction::json() const noexcept { return out; } +EntryFunction EntryFunction::from_json(const nlohmann::json& payload) noexcept { + auto splitFunctor = [](std::string s, std::string_view delimiter) { + size_t pos_start = 0, pos_end, delim_len = delimiter.size(); + std::string token; + std::vector output; + + while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) { + token = s.substr(pos_start, pos_end - pos_start); + pos_start = pos_end + delim_len; + output.emplace_back(token); + } + + output.emplace_back(s.substr(pos_start)); + return output; + }; + auto functionSplitted = splitFunctor(payload.at("function").get(), "::"); + auto moduleId = ModuleId(Address(functionSplitted[0]), functionSplitted[1]); + std::vector args; + for (auto&& cur : payload.at("arguments")) { + auto curStr = cur.get(); + auto* res = parse_function_argument_to_bcs(curStr.c_str()); + args.emplace_back(parse_hex(res)); + free_string(res); + } + + std::vector tags; + + for (auto&& cur : payload.at("type_arguments")) { + auto curStr = cur.get(); + switch (parse_type_tag(curStr.c_str())) { + case ETypeTag::Bool: + break; + case ETypeTag::U8: + break; + case ETypeTag::U64: + break; + case ETypeTag::U128: + break; + case ETypeTag::Address: + break; + case ETypeTag::Signer: + break; + case ETypeTag::Vector: + break; + case ETypeTag::Struct: { + auto structSplitted = splitFunctor(curStr, "::"); + auto addr = Address(structSplitted[0]); + TypeTag tag = {TypeTag::TypeTagVariant(TStructTag{.st = StructTag(addr, structSplitted[1], structSplitted[2], {})})}; + tags.emplace_back(tag); + break; + } + case ETypeTag::Error: + break; + default: + break; + } + } + + return EntryFunction(moduleId, functionSplitted[2], tags, {args}, payload.at("arguments")); +} + } // namespace TW::Aptos diff --git a/src/Aptos/TransactionPayload.h b/src/Aptos/TransactionPayload.h index e52124f84ff..d6c453f995c 100644 --- a/src/Aptos/TransactionPayload.h +++ b/src/Aptos/TransactionPayload.h @@ -21,6 +21,7 @@ class EntryFunction { [[nodiscard]] const std::vector& tyArgs() const noexcept { return mTyArgs; } [[nodiscard]] const std::vector& args() const noexcept { return mArgs; } [[nodiscard]] nlohmann::json json() const noexcept; + static EntryFunction from_json(const nlohmann::json& json) noexcept; private: ModuleId mModule; diff --git a/src/rust/bindgen/.gitignore b/src/rust/bindgen/.gitignore new file mode 100644 index 00000000000..424c745c125 --- /dev/null +++ b/src/rust/bindgen/.gitignore @@ -0,0 +1 @@ +*.h diff --git a/swift/.gitignore b/swift/.gitignore index 7166ea4da50..f392a48ec06 100644 --- a/swift/.gitignore +++ b/swift/.gitignore @@ -14,3 +14,4 @@ cpp.xcconfig # fastlane fastlane/README.md fastlane/report.xml +WalletCoreRs.xcframework diff --git a/swift/Tests/Blockchains/AptosTests.swift b/swift/Tests/Blockchains/AptosTests.swift index 3c54581dafe..66f4b33ae48 100644 --- a/swift/Tests/Blockchains/AptosTests.swift +++ b/swift/Tests/Blockchains/AptosTests.swift @@ -19,6 +19,42 @@ class AptosTests: XCTestCase { XCTAssertNil(AnyAddress(string: invalid, coin: .aptos)) XCTAssertFalse(AnyAddress.isValid(string: invalid, coin: .aptos)) } + + func testBlindSign() { + // Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x7efd69e7f9462774b932ce500ab51c0d0dcc004cf272e09f8ffd5804c2a84e33?network=mainnet + let payloadJson = """ + { + "function": "0x16fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c::AnimeSwapPoolV1::swap_exact_coins_for_coins_3_pair_entry", + "type_arguments": [ + "0x1::aptos_coin::AptosCoin", + "0x881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f4::coin::MOJO", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDT", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC" + ], + "arguments": ["1000000", "49329"], + "type": "entry_function_payload" + } + """ + // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xb4d62afd3862116e060dd6ad9848ccb50c2bc177799819f1d29c059ae2042467?network=devnet + let privateKeyData = Data(hexString: "5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")! + let input = AptosSigningInput.with { + $0.chainID = 1 + $0.anyEncoded = payloadJson + $0.expirationTimestampSecs = 3664390082 + $0.gasUnitPrice = 100 + $0.maxGasAmount = 100011 + $0.sequenceNumber = 42 + $0.sender = "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30" + $0.privateKey = privateKeyData + } + let output: AptosSigningOutput = AnySigner.sign(input: input, coin: .aptos) + let expectedRawTx = "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f302a000000000000000216fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c0f416e696d6553776170506f6f6c563127737761705f65786163745f636f696e735f666f725f636f696e735f335f706169725f656e747279040700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e0007881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f404636f696e044d4f4a4f0007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa05617373657404555344540007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa056173736574045553444300020840420f000000000008b1c0000000000000ab860100000000006400000000000000c2276ada0000000001" + let expectedSignature = "42cd67406e85afd1e948e7ad7f5f484fb4c60d82b267c6b6b28a92301e228b983206d2b87cd5487cf9acfb0effbd183ab90123570eb2e047cb152d337152210b" + let expectedSignedTx = "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f302a000000000000000216fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c0f416e696d6553776170506f6f6c563127737761705f65786163745f636f696e735f666f725f636f696e735f335f706169725f656e747279040700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e0007881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f404636f696e044d4f4a4f0007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa05617373657404555344540007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa056173736574045553444300020840420f000000000008b1c0000000000000ab860100000000006400000000000000c2276ada00000000010020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c4042cd67406e85afd1e948e7ad7f5f484fb4c60d82b267c6b6b28a92301e228b983206d2b87cd5487cf9acfb0effbd183ab90123570eb2e047cb152d337152210b" + XCTAssertEqual(output.rawTxn.hexString, expectedRawTx) + XCTAssertEqual(output.authenticator.signature.hexString, expectedSignature) + XCTAssertEqual(output.encoded.hexString, expectedSignedTx) + } func testSign() { // Successfully broadcasted https://explorer.aptoslabs.com/txn/0xb4d62afd3862116e060dd6ad9848ccb50c2bc177799819f1d29c059ae2042467?network=devnet diff --git a/swift/common-xcframework.yml b/swift/common-xcframework.yml index fead1284c2c..dae0d4b55c7 100644 --- a/swift/common-xcframework.yml +++ b/swift/common-xcframework.yml @@ -8,7 +8,6 @@ options: macOS: 10.14 settings: base: - ENABLE_BITCODE: YES HEADER_SEARCH_PATHS: $(SRCROOT)/wallet-core ${SRCROOT}/trezor-crypto/crypto SYSTEM_HEADER_SEARCH_PATHS: ${SRCROOT}/include ${SRCROOT}/../build/local/include ${SRCROOT}/trezor-crypto/include $(SRCROOT)/protobuf /usr/local/include /opt/homebrew/include CLANG_CXX_LANGUAGE_STANDARD: c++20 @@ -35,12 +34,15 @@ targets: - "proto/*.proto" - "Tron/Protobuf/*.proto" - "Zilliqa/Protobuf/*.proto" + - "Cosmos/Protobuf/*.proto" + - "Hedera/Protobuf/*.proto" dependencies: - target: trezor-crypto_${platform} link: true - target: protobuf_${platform} link: true - sdk: libc++.tbd + - framework: WalletCoreRs.xcframework settings: SKIP_INSTALL: false SUPPORTS_MACCATALYST: true diff --git a/swift/fastlane/Fastfile b/swift/fastlane/Fastfile index 54bb2511daf..298bcb35a56 100644 --- a/swift/fastlane/Fastfile +++ b/swift/fastlane/Fastfile @@ -14,7 +14,8 @@ platform :ios do workspace: 'TrustWalletCore.xcworkspace', scheme: 'WalletCore', destinations: ['iOS', 'macOS'], - xcframework_output_directory: 'build' + xcframework_output_directory: 'build', + enable_bitcode: false ) end @@ -24,7 +25,8 @@ platform :ios do workspace: 'TrustWalletCore.xcworkspace', scheme: 'SwiftProtobuf', destinations: ['iOS', 'macOS'], - xcframework_output_directory: 'build' + xcframework_output_directory: 'build', + enable_bitcode: false ) end end diff --git a/swift/project.yml b/swift/project.yml index 274533d6a6b..df46f6a29e5 100644 --- a/swift/project.yml +++ b/swift/project.yml @@ -27,9 +27,10 @@ targets: excludes: - ".vscode" - "proto/*.proto" - - "Cosmos/Protobuf/*.proto" - "Tron/Protobuf/*.proto" - "Zilliqa/Protobuf/*.proto" + - "Cosmos/Protobuf/*.proto" + - "Hedera/Protobuf/*.proto" - Sources dependencies: - target: trezor-crypto @@ -37,6 +38,7 @@ targets: - target: protobuf link: true - sdk: libc++.tbd + - framework: WalletCoreRs.xcframework scheme: testTargets: - WalletCoreTests diff --git a/tests/chains/Aptos/SignerTests.cpp b/tests/chains/Aptos/SignerTests.cpp index c47c05bc3e5..8b9bd0c7f03 100644 --- a/tests/chains/Aptos/SignerTests.cpp +++ b/tests/chains/Aptos/SignerTests.cpp @@ -244,6 +244,69 @@ TEST(AptosSigner, CreateAccount) { assertJSONEqual(expectedJson, parsedJson); } +TEST(AptosSigner, BlindSignFromJson) { + // Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x7efd69e7f9462774b932ce500ab51c0d0dcc004cf272e09f8ffd5804c2a84e33?network=mainnet + auto payloadJson = R"( + { + "function": "0x16fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c::AnimeSwapPoolV1::swap_exact_coins_for_coins_3_pair_entry", + "type_arguments": [ + "0x1::aptos_coin::AptosCoin", + "0x881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f4::coin::MOJO", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDT", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC" + ], + "arguments": [ + "1000000", + "49329" + ], + "type": "entry_function_payload" + })"_json; + Proto::SigningInput input; + input.set_sequence_number(42); + input.set_sender("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"); + input.set_gas_unit_price(100); + input.set_max_gas_amount(100011); + input.set_expiration_timestamp_secs(3664390082); + input.set_any_encoded(payloadJson.dump()); + auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + input.set_chain_id(1); + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.raw_txn()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f302a000000000000000216fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c0f416e696d6553776170506f6f6c563127737761705f65786163745f636f696e735f666f725f636f696e735f335f706169725f656e747279040700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e0007881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f404636f696e044d4f4a4f0007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa05617373657404555344540007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa056173736574045553444300020840420f000000000008b1c0000000000000ab860100000000006400000000000000c2276ada0000000001"); + ASSERT_EQ(hex(result.authenticator().signature()), "42cd67406e85afd1e948e7ad7f5f484fb4c60d82b267c6b6b28a92301e228b983206d2b87cd5487cf9acfb0effbd183ab90123570eb2e047cb152d337152210b"); + ASSERT_EQ(hex(result.encoded()), "07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f302a000000000000000216fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c0f416e696d6553776170506f6f6c563127737761705f65786163745f636f696e735f666f725f636f696e735f335f706169725f656e747279040700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e0007881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f404636f696e044d4f4a4f0007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa05617373657404555344540007f22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa056173736574045553444300020840420f000000000008b1c0000000000000ab860100000000006400000000000000c2276ada00000000010020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c4042cd67406e85afd1e948e7ad7f5f484fb4c60d82b267c6b6b28a92301e228b983206d2b87cd5487cf9acfb0effbd183ab90123570eb2e047cb152d337152210b"); + nlohmann::json expectedJson = R"( +{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "100011", + "payload": { + "function": "0x16fe2df00ea7dde4a63409201f7f4e536bde7bb7335526a35d05111e68aa322c::AnimeSwapPoolV1::swap_exact_coins_for_coins_3_pair_entry", + "type_arguments": [ + "0x1::aptos_coin::AptosCoin", + "0x881ac202b1f1e6ad4efcff7a1d0579411533f2502417a19211cfc49751ddb5f4::coin::MOJO", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDT", + "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC" + ], + "arguments": [ + "1000000", + "49329" + ], + "type": "entry_function_payload" + }, + "sender": "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", + "sequence_number": "42", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0x42cd67406e85afd1e948e7ad7f5f484fb4c60d82b267c6b6b28a92301e228b983206d2b87cd5487cf9acfb0effbd183ab90123570eb2e047cb152d337152210b", + "type": "ed25519_signature" + } +} + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(result.json()); + assertJSONEqual(expectedJson, parsedJson); +} + TEST(AptosSigner, BlindSign) { // successfully broadcasted https://explorer.aptoslabs.com/txn/0xd95857a9e644528708778a3a0a6e13986751944fca30eaac98853c1655de0422?network=Devnet // encoded submission with: diff --git a/tests/common/rust/bindgen/WalletCoreRsTests.cpp b/tests/common/rust/bindgen/WalletCoreRsTests.cpp new file mode 100644 index 00000000000..ce99263e0c1 --- /dev/null +++ b/tests/common/rust/bindgen/WalletCoreRsTests.cpp @@ -0,0 +1,16 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "rust/bindgen/WalletCoreRSBindgen.h" + +#include "gtest/gtest.h" + +TEST(RustBindgen, MoveParseFunctionArgument) { + std::string arg = "10000000"; + auto* result = parse_function_argument_to_bcs(arg.c_str()); + ASSERT_EQ(std::string(result), "8096980000000000"); + free_string(result); +} diff --git a/tools/generate-files b/tools/generate-files index e6d74be818e..70825c15aaa 100755 --- a/tools/generate-files +++ b/tools/generate-files @@ -52,6 +52,9 @@ codegen/bin/codegen # Convert doxygen comments to appropriate format tools/doxygen_convert_comments +# Generate rust bindgen +tools/rust-bindgen + # Generate Java, C++ and Swift Protobuf files if [ -x "$(command -v protoc-gen-swift)" ]; then "$PROTOC" -I=$PREFIX/include -I=src/proto --cpp_out=src/proto --java_out=lite:jni/java --swift_out=swift/Sources/Generated/Protobuf --swift_opt=Visibility=Public src/proto/*.proto @@ -79,3 +82,4 @@ if [ -x "$(command -v xcodegen)" ]; then else echo -e "\nWARNING: Skipped generating Xcode project because the xcodegen tool is not installed." fi + diff --git a/tools/install-rust-dependencies b/tools/install-rust-dependencies new file mode 100755 index 00000000000..b2356e561d6 --- /dev/null +++ b/tools/install-rust-dependencies @@ -0,0 +1,24 @@ +#!/bin/bash + +set -e + +if [[ `uname` == "Darwin" ]]; then + rustup update + rustup toolchain install nightly + rustup default nightly + rustup toolchain install nightly-x86_64-apple-darwin + rustup toolchain install nightly-aarch64-apple-darwin + rustup component add rust-src --toolchain nightly-aarch64-apple-darwin + rustup component add rust-src --toolchain nightly-x86_64-apple-darwin +fi + +# Android +rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android +# iOS +rustup target add aarch64-apple-darwin x86_64-apple-darwin +# macOS +rustup target add x86_64-apple-ios aarch64-apple-ios-sim aarch64-apple-ios +# Wasm +rustup target add wasm32-unknown-emscripten + +cargo install cbindgen diff --git a/tools/install-sys-dependencies-linux b/tools/install-sys-dependencies-linux new file mode 100755 index 00000000000..b9173e25e42 --- /dev/null +++ b/tools/install-sys-dependencies-linux @@ -0,0 +1,6 @@ +#!/bin/bash + +set -e + + # build-essential clang-14 libc++-dev libc++abi-dev ruby-full cmake + sudo apt-get update && sudo apt-get install ninja-build lcov llvm-14 clang-tidy-14 libboost-all-dev rustc --fix-missing diff --git a/tools/install-sys-dependencies-mac b/tools/install-sys-dependencies-mac new file mode 100755 index 00000000000..2e7fc69a00e --- /dev/null +++ b/tools/install-sys-dependencies-mac @@ -0,0 +1,5 @@ +#!/bin/bash + +set -e + +brew install boost ninja xcodegen xcbeautify diff --git a/tools/ios-build b/tools/ios-build index e1b3945ecfc..8e12031289e 100755 --- a/tools/ios-build +++ b/tools/ios-build @@ -47,13 +47,14 @@ create_xc_framework() { xcodebuild -create-xcframework -output $BUILD_FOLDER/$FRAMEWORK.xcframework \ -framework $BUILD_FOLDER/ios-arm64.xcarchive/Products/Library/Frameworks/$FRAMEWORK.framework \ -framework $BUILD_FOLDER/ios-arm64_x86_64-simulator.xcarchive/Products/Library/Frameworks/$FRAMEWORK.framework \ + -framework $BUILD_FOLDER/ios-x86_64_arm64-maccatalyst.xcarchive/Products/Library/Frameworks/$FRAMEWORK.framework \ -framework $BUILD_FOLDER/macos-arm64_x86_64.xcarchive/Products/Library/Frameworks/$FRAMEWORK.framework } main() { init + build_mac_x64_arm64 && build_ios_mac_catalyst build_ios_arm64 && build_ios_simulator - build_mac_x64_arm64 create_xc_framework } diff --git a/tools/ios-doc b/tools/ios-doc index 9c004897a18..60c5a41b1cd 100755 --- a/tools/ios-doc +++ b/tools/ios-doc @@ -9,7 +9,7 @@ pushd swift mkdir -p build && rm -rf build/*.doccarchive export DOCC_JSON_PRETTYPRINT="YES" -xcodebuild -workspace TrustWalletCore.xcworkspace -derivedDataPath build/docsData -scheme WalletCore -destination 'platform=iOS Simulator,name=iPhone 13 Pro Max' -parallelizeTargets docbuild | xcbeautify +xcodebuild -workspace TrustWalletCore.xcworkspace -derivedDataPath build/docsData -scheme WalletCore -destination 'platform=iOS Simulator,name=iPhone 14' -parallelizeTargets docbuild | xcbeautify pushd build diff --git a/tools/rust-bindgen b/tools/rust-bindgen new file mode 100755 index 00000000000..ab885868d1c --- /dev/null +++ b/tools/rust-bindgen @@ -0,0 +1,43 @@ +#!/bin/bash + +TARGET_NAME="libwallet_core_rs.a" +TARGET_XCFRAMEWORK_NAME=../swift/WalletCoreRs.xcframework +BUILD_FOLDER=../build/local +CRATE="wallet-core-rs" +HEADER_NAME="WalletCoreRSBindgen.h" + +create_xc_framework() { + rm -rf $TARGET_XCFRAMEWORK_NAME + xcodebuild -create-xcframework -library $BUILD_FOLDER/$TARGET_NAME -library $BUILD_FOLDER/darwin_universal/$TARGET_NAME -library $BUILD_FOLDER/aarch64-apple-ios/release/$TARGET_NAME -library $BUILD_FOLDER/catalyst/$TARGET_NAME -output $TARGET_XCFRAMEWORK_NAME +} + +cd rust + +echo "Generating Native targets" +CARGO_TARGET_DIR=$BUILD_FOLDER/ cargo build --release +CARGO_TARGET_DIR=$BUILD_FOLDER cargo build --target wasm32-unknown-emscripten --release +if [[ `uname` == "Darwin" ]]; then + echo "Generating Android targets" + CARGO_TARGET_DIR=$BUILD_FOLDER/ cargo build --target aarch64-linux-android --release + CARGO_TARGET_DIR=$BUILD_FOLDER/ cargo build --target armv7-linux-androideabi --release + CARGO_TARGET_DIR=$BUILD_FOLDER/ cargo build --target x86_64-linux-android --release + CARGO_TARGET_DIR=$BUILD_FOLDER/ cargo build --target i686-linux-android --release + echo "Generating iOS targets" + CARGO_TARGET_DIR=$BUILD_FOLDER cargo build --target aarch64-apple-ios --release + CARGO_TARGET_DIR=$BUILD_FOLDER cargo build --target aarch64-apple-ios-sim --release + CARGO_TARGET_DIR=$BUILD_FOLDER cargo build --target x86_64-apple-ios --release + CARGO_TARGET_DIR=$BUILD_FOLDER cargo build --target aarch64-apple-darwin --release + CARGO_TARGET_DIR=$BUILD_FOLDER cargo build --target x86_64-apple-darwin --release + CARGO_TARGET_DIR=$BUILD_FOLDER cargo +nightly build -Z build-std --target aarch64-apple-ios-macabi --release + CARGO_TARGET_DIR=$BUILD_FOLDER cargo +nightly build -Z build-std --target x86_64-apple-ios-macabi --release + lipo $BUILD_FOLDER/x86_64-apple-ios/release/$TARGET_NAME $BUILD_FOLDER/aarch64-apple-ios-sim/release/$TARGET_NAME -create -output $BUILD_FOLDER/$TARGET_NAME + mkdir -p $BUILD_FOLDER/darwin_universal + lipo $BUILD_FOLDER/x86_64-apple-darwin/release/$TARGET_NAME $BUILD_FOLDER/aarch64-apple-darwin/release/$TARGET_NAME -create -output $BUILD_FOLDER/darwin_universal/$TARGET_NAME + mkdir -p $BUILD_FOLDER/catalyst + lipo $BUILD_FOLDER/aarch64-apple-ios-macabi/release/$TARGET_NAME $BUILD_FOLDER/x86_64-apple-ios-macabi/release/$TARGET_NAME -create -output $BUILD_FOLDER/catalyst/$TARGET_NAME + + create_xc_framework +fi +cbindgen --crate $CRATE --output ../src/rust/bindgen/$HEADER_NAME +cd - +cp build/local/release/${TARGET_NAME} build/local/lib/ From 933e79018bcfa4fecc87ae73eadeac1f1a1c5341 Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Tue, 6 Dec 2022 07:30:44 +0000 Subject: [PATCH 152/497] fix(docs): fix error when uploading kotlin docs (#2781) --- tools/android-release | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/android-release b/tools/android-release index 4856fa5a5ec..e37796b2f6e 100755 --- a/tools/android-release +++ b/tools/android-release @@ -20,9 +20,13 @@ popd # android echo "Building docs..." tools/kotlin-doc +pushd build/dokka release_url=$(wc_release_url ${version}) echo "release_url url for docs is $release_url" -filename=build/dokka/kdoc.zip +filename=kdoc.zip download_url=$(wc_upload_asset ${release_url} ${filename}) echo "download_url is $download_url" + +popd # build/dokka + From 36d082788534f60ffe2cdc2e54bb83a32260b84a Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 6 Dec 2022 08:41:43 +0100 Subject: [PATCH 153/497] feat(aptos): add aptos staking/unstaking examples (#2780) --- tests/chains/Aptos/SignerTests.cpp | 103 +++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/tests/chains/Aptos/SignerTests.cpp b/tests/chains/Aptos/SignerTests.cpp index 8b9bd0c7f03..544240a7cfc 100644 --- a/tests/chains/Aptos/SignerTests.cpp +++ b/tests/chains/Aptos/SignerTests.cpp @@ -307,6 +307,109 @@ TEST(AptosSigner, BlindSignFromJson) { assertJSONEqual(expectedJson, parsedJson); } +TEST(AptosSigner, BlindSignStaking) { + // Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x25dca849cb4ebacbff223139f7ad5d24c37c225d9506b8b12a925de70429e685/payload + auto payloadJson = R"( + { + "function": "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f::stake_router::stake", + "type_arguments": [], + "arguments": [ + "100000000" + ], + "type": "entry_function_payload" + })"_json; + Proto::SigningInput input; + input.set_sequence_number(43); + input.set_sender("0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc"); + input.set_gas_unit_price(100); + input.set_max_gas_amount(100011); + input.set_expiration_timestamp_secs(3664390082); + input.set_any_encoded(payloadJson.dump()); + auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + input.set_chain_id(1); + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.raw_txn()), "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc2b00000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f75746572057374616b6500010800e1f50500000000ab860100000000006400000000000000c2276ada0000000001"); + ASSERT_EQ(hex(result.authenticator().signature()), "a41b7440a50f36e8491319508734acb55488abc6d88fbc9cb2b37ba23210f01f5d08c856cb7abf18c414cf9302ee144450bd99495a7e21e61f624764db91eb0b"); + ASSERT_EQ(hex(result.encoded()), "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc2b00000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f75746572057374616b6500010800e1f50500000000ab860100000000006400000000000000c2276ada00000000010020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c40a41b7440a50f36e8491319508734acb55488abc6d88fbc9cb2b37ba23210f01f5d08c856cb7abf18c414cf9302ee144450bd99495a7e21e61f624764db91eb0b"); + nlohmann::json expectedJson = R"( +{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "100011", + "payload": { + "function": "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f::stake_router::stake", + "type_arguments": [], + "arguments": [ + "100000000" + ], + "type": "entry_function_payload" + }, + "sender": "0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc", + "sequence_number": "43", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0xa41b7440a50f36e8491319508734acb55488abc6d88fbc9cb2b37ba23210f01f5d08c856cb7abf18c414cf9302ee144450bd99495a7e21e61f624764db91eb0b", + "type": "ed25519_signature" + } +} + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(result.json()); + assertJSONEqual(expectedJson, parsedJson); +} + +TEST(AptosSigner, BlindSignUnStaking) { + // Successfully broadcasted: https://explorer.aptoslabs.com/txn/0x92edb4f756fe86118e34a0e64746c70260ee02c2ae2cf402b3e39f6a282ce968/payload + auto payloadJson = R"( + { + "function": "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f::stake_router::unstake", + "type_arguments": [], + "arguments": [ + "99178100" + ], + "type": "entry_function_payload" + })"_json; + Proto::SigningInput input; + input.set_sequence_number(44); + input.set_sender("0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc"); + input.set_gas_unit_price(100); + input.set_max_gas_amount(100011); + input.set_expiration_timestamp_secs(3664390082); + input.set_any_encoded(payloadJson.dump()); + auto privateKey = PrivateKey(parse_hex("5d996aa76b3212142792d9130796cd2e11e3c445a93118c08414df4f66bc60ec")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + input.set_chain_id(1); + auto result = Signer::sign(input); + ASSERT_EQ(hex(result.raw_txn()), "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc2c00000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f7574657207756e7374616b650001087456e90500000000ab860100000000006400000000000000c2276ada0000000001"); + ASSERT_EQ(hex(result.authenticator().signature()), "a58ad5e3331beb8c0212a18a1f932207cb664b78f5aad3cb1fe7435e0e0e053247ce49b38fd67b064bed34ed643eb6a03165d77c681d7d73ac3161ab984a960a"); + ASSERT_EQ(hex(result.encoded()), "f3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc2c00000000000000028f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f0c7374616b655f726f7574657207756e7374616b650001087456e90500000000ab860100000000006400000000000000c2276ada00000000010020ea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c40a58ad5e3331beb8c0212a18a1f932207cb664b78f5aad3cb1fe7435e0e0e053247ce49b38fd67b064bed34ed643eb6a03165d77c681d7d73ac3161ab984a960a"); + nlohmann::json expectedJson = R"( +{ + "expiration_timestamp_secs": "3664390082", + "gas_unit_price": "100", + "max_gas_amount": "100011", + "payload": { + "function": "0x8f396e4246b2ba87b51c0739ef5ea4f26515a98375308c31ac2ec1e42142a57f::stake_router::unstake", + "type_arguments": [], + "arguments": [ + "99178100" + ], + "type": "entry_function_payload" + }, + "sender": "0xf3d7f364dd7705824a5ebda9c7aab6cb3fc7bb5b58718249f12defec240b36cc", + "sequence_number": "44", + "signature": { + "public_key": "0xea526ba1710343d953461ff68641f1b7df5f23b9042ffa2d2a798d3adb3f3d6c", + "signature": "0xa58ad5e3331beb8c0212a18a1f932207cb664b78f5aad3cb1fe7435e0e0e053247ce49b38fd67b064bed34ed643eb6a03165d77c681d7d73ac3161ab984a960a", + "type": "ed25519_signature" + } +} + )"_json; + nlohmann::json parsedJson = nlohmann::json::parse(result.json()); + assertJSONEqual(expectedJson, parsedJson); +} + + TEST(AptosSigner, BlindSign) { // successfully broadcasted https://explorer.aptoslabs.com/txn/0xd95857a9e644528708778a3a0a6e13986751944fca30eaac98853c1655de0422?network=Devnet // encoded submission with: From f50d771a99519e0723ac25f036c01969f909d710 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 8 Dec 2022 11:57:38 +0100 Subject: [PATCH 154/497] feat(build): update bootstrap.sh (#2787) --- bootstrap.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap.sh b/bootstrap.sh index 1dba588dd30..cdb20a25993 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -7,6 +7,7 @@ set -e echo "#### Initializing workspace with dependencies ... ####" tools/install-dependencies +tools/install-rust-dependencies echo "#### Building and running tests ... ####" tools/build-and-test From c33675119405a951ae2ce887d0a88e77a81c8fcf Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Mon, 12 Dec 2022 18:34:22 +0900 Subject: [PATCH 155/497] Remove WC_ prefix (same with other actions) (#2793) --- android/trustwalletcore/maven-push.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/trustwalletcore/maven-push.gradle b/android/trustwalletcore/maven-push.gradle index 12746f09c4a..ba35797e7fe 100644 --- a/android/trustwalletcore/maven-push.gradle +++ b/android/trustwalletcore/maven-push.gradle @@ -43,8 +43,8 @@ publishing { name = "GitHubPackages" url = uri("https://maven.pkg.github.com/trustwallet/wallet-core") credentials { - username = System.getenv("WC_GITHUB_USER") - password = System.getenv("WC_GITHUB_TOKEN") + username = System.getenv("GITHUB_USER") + password = System.getenv("GITHUB_TOKEN") } } } From 89e337b1df8dcefc8a684578307a30e2e467bed7 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Tue, 13 Dec 2022 13:37:40 +0100 Subject: [PATCH 156/497] Unify Entry::deriveAddress() methods (#2796) --- codegen/lib/templates/newcoin/Entry.cpp.erb | 4 +-- codegen/lib/templates/newcoin/Entry.h.erb | 6 ++-- src/Aeternity/Entry.cpp | 2 +- src/Aeternity/Entry.h | 2 +- src/Aion/Entry.cpp | 2 +- src/Aion/Entry.h | 2 +- src/Algorand/Entry.cpp | 2 +- src/Algorand/Entry.h | 2 +- src/AnyAddress.cpp | 11 ++----- src/AnyAddress.h | 5 ++-- src/Aptos/Entry.cpp | 2 +- src/Aptos/Entry.h | 2 +- src/Binance/Entry.cpp | 2 +- src/Binance/Entry.h | 2 +- src/Bitcoin/Entry.cpp | 6 ++-- src/Bitcoin/Entry.h | 7 +---- src/Cardano/Entry.cpp | 2 +- src/Cardano/Entry.h | 2 +- src/Coin.cpp | 13 +-------- src/Coin.h | 8 ++---- src/CoinEntry.cpp | 32 +++++++++++++++++++++ src/CoinEntry.h | 19 ++++++------ src/Cosmos/Entry.cpp | 9 ++++-- src/Cosmos/Entry.h | 10 +++---- src/Decred/Entry.cpp | 2 +- src/Decred/Entry.h | 2 +- src/EOS/Entry.cpp | 2 +- src/EOS/Entry.h | 2 +- src/Elrond/Entry.cpp | 2 +- src/Elrond/Entry.h | 2 +- src/Ethereum/Entry.cpp | 2 +- src/Ethereum/Entry.h | 2 +- src/Everscale/Entry.cpp | 2 +- src/Everscale/Entry.h | 2 +- src/FIO/Entry.cpp | 2 +- src/FIO/Entry.h | 2 +- src/Filecoin/Entry.cpp | 3 +- src/Filecoin/Entry.h | 11 ++++--- src/Groestlcoin/Entry.cpp | 3 +- src/Groestlcoin/Entry.h | 6 ++-- src/Harmony/Entry.cpp | 2 +- src/Harmony/Entry.h | 2 +- src/Hedera/Entry.cpp | 2 +- src/Hedera/Entry.h | 2 +- src/Icon/Entry.cpp | 2 +- src/Icon/Entry.h | 2 +- src/IoTeX/Entry.cpp | 2 +- src/IoTeX/Entry.h | 2 +- src/Kusama/Entry.cpp | 2 +- src/Kusama/Entry.h | 2 +- src/NEAR/Entry.cpp | 2 +- src/NEAR/Entry.h | 2 +- src/NEO/Entry.cpp | 2 +- src/NEO/Entry.h | 2 +- src/NULS/Entry.cpp | 2 +- src/NULS/Entry.h | 2 +- src/Nano/Entry.cpp | 2 +- src/Nano/Entry.h | 2 +- src/Nebulas/Entry.cpp | 2 +- src/Nebulas/Entry.h | 2 +- src/Nervos/Entry.cpp | 4 +-- src/Nervos/Entry.h | 3 +- src/Nimiq/Entry.cpp | 2 +- src/Nimiq/Entry.h | 2 +- src/Oasis/Entry.cpp | 2 +- src/Oasis/Entry.h | 2 +- src/Ontology/Entry.cpp | 2 +- src/Ontology/Entry.h | 2 +- src/Polkadot/Entry.cpp | 12 +++----- src/Polkadot/Entry.h | 1 - src/Ronin/Entry.cpp | 2 +- src/Ronin/Entry.h | 2 +- src/Solana/Entry.cpp | 2 +- src/Solana/Entry.h | 2 +- src/Stellar/Entry.cpp | 2 +- src/Stellar/Entry.h | 2 +- src/Tezos/Entry.cpp | 2 +- src/Tezos/Entry.h | 2 +- src/Tron/Entry.cpp | 2 +- src/Tron/Entry.h | 2 +- src/Waves/Entry.cpp | 2 +- src/Waves/Entry.h | 2 +- src/XRP/Entry.cpp | 2 +- src/XRP/Entry.h | 2 +- src/Zcash/Entry.cpp | 3 +- src/Zcash/Entry.h | 2 +- src/Zilliqa/Entry.cpp | 2 +- src/Zilliqa/Entry.h | 2 +- src/interface/TWAnyAddress.cpp | 7 +++-- tests/common/AnyAddressTests.cpp | 4 +-- 90 files changed, 164 insertions(+), 157 deletions(-) create mode 100644 src/CoinEntry.cpp diff --git a/codegen/lib/templates/newcoin/Entry.cpp.erb b/codegen/lib/templates/newcoin/Entry.cpp.erb index a29ceb91951..6de5775f5b0 100644 --- a/codegen/lib/templates/newcoin/Entry.cpp.erb +++ b/codegen/lib/templates/newcoin/Entry.cpp.erb @@ -13,11 +13,11 @@ namespace TW::<%= format_name(coin) %> { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress(TWCoinType coin, [[maybe_unused]] const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } -std::string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/codegen/lib/templates/newcoin/Entry.h.erb b/codegen/lib/templates/newcoin/Entry.h.erb index 090d5d06445..52a1866eca6 100644 --- a/codegen/lib/templates/newcoin/Entry.h.erb +++ b/codegen/lib/templates/newcoin/Entry.h.erb @@ -14,9 +14,9 @@ namespace TW::<%= format_name(coin) %> { /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: - virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, const PrefixVariant& addressPrefix) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; // normalizeAddress(): implement this if needed, e.g. Ethereum address is EIP55 checksummed // plan(): implement this if the blockchain is UTXO based }; diff --git a/src/Aeternity/Entry.cpp b/src/Aeternity/Entry.cpp index 0c1fcc95dce..391a248c057 100644 --- a/src/Aeternity/Entry.cpp +++ b/src/Aeternity/Entry.cpp @@ -18,7 +18,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Aeternity/Entry.h b/src/Aeternity/Entry.h index 211ffd707c2..748cd69b91c 100644 --- a/src/Aeternity/Entry.h +++ b/src/Aeternity/Entry.h @@ -15,7 +15,7 @@ namespace TW::Aeternity { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Aion/Entry.cpp b/src/Aion/Entry.cpp index 922e368f611..454fb6cbc05 100644 --- a/src/Aion/Entry.cpp +++ b/src/Aion/Entry.cpp @@ -20,7 +20,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Aion/Entry.h b/src/Aion/Entry.h index 551016bc95c..b09f3a4871f 100644 --- a/src/Aion/Entry.h +++ b/src/Aion/Entry.h @@ -15,7 +15,7 @@ namespace TW::Aion { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Algorand/Entry.cpp b/src/Algorand/Entry.cpp index 135434fc5cc..4eaa61977c7 100644 --- a/src/Algorand/Entry.cpp +++ b/src/Algorand/Entry.cpp @@ -17,7 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Algorand/Entry.h b/src/Algorand/Entry.h index 7fa4a1f91a3..0f152c857cb 100644 --- a/src/Algorand/Entry.h +++ b/src/Algorand/Entry.h @@ -15,7 +15,7 @@ namespace TW::Algorand { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; bool supportsJSONSigning() const { return true; } std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; diff --git a/src/AnyAddress.cpp b/src/AnyAddress.cpp index bf0fb994b98..6d20e19a15c 100644 --- a/src/AnyAddress.cpp +++ b/src/AnyAddress.cpp @@ -25,15 +25,8 @@ AnyAddress* AnyAddress::createAddress(const std::string& address, enum TWCoinTyp return new AnyAddress{.address = std::move(normalized), .coin = coin}; } -AnyAddress* AnyAddress::createAddress(const PublicKey& publicKey, enum TWCoinType coin, const std::string& hrp, TWDerivation derivation) { - - auto derivedAddress = TW::deriveAddress(coin, publicKey, derivation, hrp); - return new AnyAddress{.address = std::move(derivedAddress), .coin = coin}; -} - -AnyAddress* AnyAddress::createAddress(const PublicKey& publicKey, enum TWCoinType coin, const PrefixVariant& addressPrefix, TWDerivation derivation) { - - auto derivedAddress = TW::deriveAddress(coin, publicKey, addressPrefix, derivation); +AnyAddress* AnyAddress::createAddress(const PublicKey& publicKey, enum TWCoinType coin, TWDerivation derivation, const PrefixVariant& prefix) { + const auto derivedAddress = TW::deriveAddress(coin, publicKey, derivation, prefix); return new AnyAddress{.address = std::move(derivedAddress), .coin = coin}; } diff --git a/src/AnyAddress.h b/src/AnyAddress.h index e78f3d67a7c..0735fe24ceb 100644 --- a/src/AnyAddress.h +++ b/src/AnyAddress.h @@ -23,9 +23,10 @@ class AnyAddress { enum TWCoinType coin; + // Create address from string address and optional prefix; also normalizes the address. static AnyAddress* createAddress(const std::string& address, enum TWCoinType coin, const PrefixVariant& prefix = std::monostate()); - static AnyAddress* createAddress(const PublicKey& publicKey, enum TWCoinType coin, const std::string& hrp = "", TWDerivation derivation = TWDerivationDefault); - static AnyAddress* createAddress(const PublicKey& publicKey, enum TWCoinType coin, const PrefixVariant& prefix, TWDerivation derivation = TWDerivationDefault); + // Create address from private key, with optional non-standard derivation and prefix + static AnyAddress* createAddress(const PublicKey& publicKey, enum TWCoinType coin, TWDerivation derivation = TWDerivationDefault, const PrefixVariant& prefix = std::monostate()); Data getData() const; }; diff --git a/src/Aptos/Entry.cpp b/src/Aptos/Entry.cpp index 44261fc64ac..4ecf7f053f6 100644 --- a/src/Aptos/Entry.cpp +++ b/src/Aptos/Entry.cpp @@ -15,7 +15,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Aptos/Entry.h b/src/Aptos/Entry.h index 3496e72e8ac..4f3f722643b 100644 --- a/src/Aptos/Entry.h +++ b/src/Aptos/Entry.h @@ -15,7 +15,7 @@ namespace TW::Aptos { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Binance/Entry.cpp b/src/Binance/Entry.cpp index a92d97c4a2d..f0e74088833 100644 --- a/src/Binance/Entry.cpp +++ b/src/Binance/Entry.cpp @@ -16,7 +16,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Binance/Entry.h b/src/Binance/Entry.h index ee8cd5b158b..3bcd1c91c89 100644 --- a/src/Binance/Entry.h +++ b/src/Binance/Entry.h @@ -15,7 +15,7 @@ namespace TW::Binance { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; bool supportsJSONSigning() const { return true; } diff --git a/src/Bitcoin/Entry.cpp b/src/Bitcoin/Entry.cpp index 861e239c61e..dd40b084e18 100644 --- a/src/Bitcoin/Entry.cpp +++ b/src/Bitcoin/Entry.cpp @@ -63,8 +63,10 @@ std::string Entry::normalizeAddress(TWCoinType coin, const std::string& address) } } -std::string Entry::deriveAddress(TWCoinType coin, TWDerivation derivation, const PublicKey& publicKey, - byte p2pkh, const char* hrp) const { +std::string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const { + byte p2pkh = getFromPrefixPkhOrDefault(addressPrefix, coin); + const char* hrp = getFromPrefixHrpOrDefault(addressPrefix, coin); + switch (coin) { case TWCoinTypeBitcoin: case TWCoinTypeLitecoin: diff --git a/src/Bitcoin/Entry.h b/src/Bitcoin/Entry.h index aec706f5d5f..b3b06d67707 100644 --- a/src/Bitcoin/Entry.h +++ b/src/Bitcoin/Entry.h @@ -17,12 +17,7 @@ class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string normalizeAddress(TWCoinType coin, const std::string& address) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, - const char* hrp) const { - return deriveAddress(coin, TWDerivationDefault, publicKey, p2pkh, hrp); - } - std::string deriveAddress(TWCoinType coin, TWDerivation derivation, const PublicKey& publicKey, - TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Cardano/Entry.cpp b/src/Cardano/Entry.cpp index 2bf09dde28d..df4c166faae 100644 --- a/src/Cardano/Entry.cpp +++ b/src/Cardano/Entry.cpp @@ -17,7 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return AddressV3::isValidLegacy(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return AddressV3(publicKey).string(); } diff --git a/src/Cardano/Entry.h b/src/Cardano/Entry.h index 7cac8650256..04b55e259b8 100644 --- a/src/Cardano/Entry.h +++ b/src/Cardano/Entry.h @@ -15,7 +15,7 @@ namespace TW::Cardano { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Coin.cpp b/src/Coin.cpp index c99c086c8bc..dd82fc790d9 100644 --- a/src/Coin.cpp +++ b/src/Coin.cpp @@ -243,23 +243,12 @@ std::string TW::deriveAddress(TWCoinType coin, const PrivateKey& privateKey, TWD return TW::deriveAddress(coin, privateKey.getPublicKey(keyType), derivation); } -std::string TW::deriveAddress(TWCoinType coin, const PublicKey& publicKey, const PrefixVariant& addressPrefix, TWDerivation derivation) { +std::string TW::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) { auto const* dispatcher = coinDispatcher(coin); assert(dispatcher != nullptr); return dispatcher->deriveAddress(coin, publicKey, derivation, addressPrefix); } -std::string TW::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const std::string& hrp) { - auto p2pkh = TW::p2pkhPrefix(coin); - const char* hrpRaw = [&hrp, coin]() { - return hrp.empty() ? stringForHRP(TW::hrp(coin)) : hrp.c_str(); - }(); - // dispatch - auto* dispatcher = coinDispatcher(coin); - assert(dispatcher != nullptr); - return dispatcher->deriveAddress(coin, derivation, publicKey, p2pkh, hrpRaw); -} - Data TW::addressToData(TWCoinType coin, const std::string& address) { const auto* dispatcher = coinDispatcher(coin); assert(dispatcher != nullptr); diff --git a/src/Coin.h b/src/Coin.h index 3a994267d1b..a4920fe7419 100644 --- a/src/Coin.h +++ b/src/Coin.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -78,10 +78,8 @@ std::string deriveAddress(TWCoinType coin, const PrivateKey& privateKey); /// Derives the address for a particular coin from the private key, with given derivation. std::string deriveAddress(TWCoinType coin, const PrivateKey& privateKey, TWDerivation derivation); -/// Derives the address for a particular coin from the public key, with given derivation. -std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation = TWDerivationDefault, const std::string& hrp = ""); -/// Derives the address for a particular coin from the public key, with given derivation and explicit addressPrefix. -std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, const PrefixVariant& addressPrefix, TWDerivation derivation = TWDerivationDefault); +/// Derives the address for a particular coin from the public key, with given derivation and addressPrefix. +std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation = TWDerivationDefault, const PrefixVariant& addressPrefix = std::monostate()); /// Returns the binary representation of a string address Data addressToData(TWCoinType coin, const std::string& address); diff --git a/src/CoinEntry.cpp b/src/CoinEntry.cpp new file mode 100644 index 00000000000..e61da49ee62 --- /dev/null +++ b/src/CoinEntry.cpp @@ -0,0 +1,32 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "CoinEntry.h" +#include "Coin.h" +#include + +namespace TW { + +const char* getFromPrefixHrpOrDefault(const PrefixVariant &prefix, TWCoinType coin) { + if (std::holds_alternative(prefix)) { + const char* fromPrefix = std::get(prefix); + if (fromPrefix != nullptr && *fromPrefix != 0) { + return fromPrefix; + } + } + // Prefix contains no hrp or empty, return coin-default + return stringForHRP(TW::hrp(coin)); +} + +byte getFromPrefixPkhOrDefault(const PrefixVariant &prefix, TWCoinType coin) { + if (std::holds_alternative(prefix)) { + return std::get(prefix).p2pkh; + } + // Prefix contains no base58 prefixes, return coin-default + return TW::p2pkhPrefix(coin); +} + +} // namespace TW diff --git a/src/CoinEntry.h b/src/CoinEntry.h index 99a56942ff8..5ecb055ddc6 100644 --- a/src/CoinEntry.h +++ b/src/CoinEntry.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -42,15 +42,8 @@ class CoinEntry { virtual bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const = 0; // normalizeAddress is optional, it may leave this default, no-change implementation virtual std::string normalizeAddress([[maybe_unused]] TWCoinType coin, const std::string& address) const { return address; } - // Address derivation, default derivation - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const = 0; - virtual std::string deriveAddress([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { - return ""; - }; - // Address derivation, by default invoking default - virtual std::string deriveAddress(TWCoinType coin, [[maybe_unused]] TWDerivation derivation, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const { - return deriveAddress(coin, publicKey, p2pkh, hrp); - } + // Address derivation + virtual std::string deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const = 0; // Return the binary representation of a string address, used by AnyAddress // It is optional, if not defined, 'AnyAddress' interface will not support this coin. virtual Data addressToData([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const std::string& address) const { return {}; } @@ -117,4 +110,10 @@ Data txCompilerTemplate(const Data& dataIn, Func&& fnHandler) { return TW::data(output.SerializeAsString()); } +// Get the hrp from the prefix variant, or the coin-default if it is empty or it is not an hrp +const char* getFromPrefixHrpOrDefault(const PrefixVariant &prefix, TWCoinType coin); + +// Get the p2pkh prefix from the prefix variant, or the coin-default if it does not contain base58 prefixes +byte getFromPrefixPkhOrDefault(const PrefixVariant &prefix, TWCoinType coin); + } // namespace TW diff --git a/src/Cosmos/Entry.cpp b/src/Cosmos/Entry.cpp index 7de1049e24e..8f6ee8ada61 100644 --- a/src/Cosmos/Entry.cpp +++ b/src/Cosmos/Entry.cpp @@ -26,9 +26,12 @@ bool Entry::validateAddress(TWCoinType coin, const std::string& address, const P return false; } -string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char* hrp) const { - if (!std::string(hrp).empty()) { - return Address(hrp, publicKey, coin).string(); +std::string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, const PrefixVariant& addressPrefix) const { + if (std::holds_alternative(addressPrefix)) { + const std::string hrp = std::get(addressPrefix); + if (!hrp.empty()) { + return Address(hrp, publicKey, coin).string(); + } } return Address(coin, publicKey).string(); } diff --git a/src/Cosmos/Entry.h b/src/Cosmos/Entry.h index 599bb623f01..a77f6104b82 100644 --- a/src/Cosmos/Entry.h +++ b/src/Cosmos/Entry.h @@ -15,11 +15,11 @@ namespace TW::Cosmos { class Entry : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const final; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const final; - Data addressToData(TWCoinType coin, const std::string& address) const final; - void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const override; - bool supportsJSONSigning() const final { return true; } - std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const override; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const override; + Data addressToData(TWCoinType coin, const std::string& address) const final; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const override; + bool supportsJSONSigning() const final { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const override; }; } // namespace TW::Cosmos diff --git a/src/Decred/Entry.cpp b/src/Decred/Entry.cpp index 36e0b21d1e7..778ec5410cc 100644 --- a/src/Decred/Entry.cpp +++ b/src/Decred/Entry.cpp @@ -15,7 +15,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] const char* hrp) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Decred/Entry.h b/src/Decred/Entry.h index d6d2dccb262..af3d8ab9784 100644 --- a/src/Decred/Entry.h +++ b/src/Decred/Entry.h @@ -15,7 +15,7 @@ namespace TW::Decred { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/EOS/Entry.cpp b/src/EOS/Entry.cpp index f2ecbbfa138..efb9f53be96 100644 --- a/src/EOS/Entry.cpp +++ b/src/EOS/Entry.cpp @@ -17,7 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/EOS/Entry.h b/src/EOS/Entry.h index 3d5c1fda040..49fea13f207 100644 --- a/src/EOS/Entry.h +++ b/src/EOS/Entry.h @@ -15,7 +15,7 @@ namespace TW::EOS { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Elrond/Entry.cpp b/src/Elrond/Entry.cpp index ff04f37b8ed..6cd504b6008 100644 --- a/src/Elrond/Entry.cpp +++ b/src/Elrond/Entry.cpp @@ -19,7 +19,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Elrond/Entry.h b/src/Elrond/Entry.h index 27b1270a462..df2a0967e7f 100644 --- a/src/Elrond/Entry.h +++ b/src/Elrond/Entry.h @@ -15,7 +15,7 @@ namespace TW::Elrond { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; bool supportsJSONSigning() const { return true; } diff --git a/src/Ethereum/Entry.cpp b/src/Ethereum/Entry.cpp index 789384a4068..b862da36606 100644 --- a/src/Ethereum/Entry.cpp +++ b/src/Ethereum/Entry.cpp @@ -24,7 +24,7 @@ string Entry::normalizeAddress([[maybe_unused]] TWCoinType coin, const string& a return Address(address).string(); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Ethereum/Entry.h b/src/Ethereum/Entry.h index b92042e91dc..f9a053992c5 100644 --- a/src/Ethereum/Entry.h +++ b/src/Ethereum/Entry.h @@ -16,7 +16,7 @@ class Entry : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const final; std::string normalizeAddress(TWCoinType coin, const std::string& address) const final; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const final; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const final; Data addressToData(TWCoinType coin, const std::string& address) const final; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const override; bool supportsJSONSigning() const final { return true; } diff --git a/src/Everscale/Entry.cpp b/src/Everscale/Entry.cpp index 216cca93ec4..68cd990d2f1 100644 --- a/src/Everscale/Entry.cpp +++ b/src/Everscale/Entry.cpp @@ -25,7 +25,7 @@ string Entry::normalizeAddress([[maybe_unused]] TWCoinType coin, const string& a return Address(address).string(); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey, WorkchainType::Basechain).string(); } diff --git a/src/Everscale/Entry.h b/src/Everscale/Entry.h index d24d55ebceb..c0adfb3fe0a 100644 --- a/src/Everscale/Entry.h +++ b/src/Everscale/Entry.h @@ -16,7 +16,7 @@ class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string normalizeAddress(TWCoinType coin, const std::string& address) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* d) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/FIO/Entry.cpp b/src/FIO/Entry.cpp index c435b98ff4f..42111a0848b 100644 --- a/src/FIO/Entry.cpp +++ b/src/FIO/Entry.cpp @@ -17,7 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/FIO/Entry.h b/src/FIO/Entry.h index 49fa7e95002..98f0fab9106 100644 --- a/src/FIO/Entry.h +++ b/src/FIO/Entry.h @@ -15,7 +15,7 @@ namespace TW::FIO { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Filecoin/Entry.cpp b/src/Filecoin/Entry.cpp index 0317621d6a4..07696a24cb7 100644 --- a/src/Filecoin/Entry.cpp +++ b/src/Filecoin/Entry.cpp @@ -17,8 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, - const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Filecoin/Entry.h b/src/Filecoin/Entry.h index 7db1f33b6b0..57e9f71f111 100644 --- a/src/Filecoin/Entry.h +++ b/src/Filecoin/Entry.h @@ -15,12 +15,11 @@ namespace TW::Filecoin { /// includes in this file class Entry final : public CoinEntry { public: - bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, - const char* hrp) const; - void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - bool supportsJSONSigning() const { return true; } - std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + bool supportsJSONSigning() const { return true; } + std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; } // namespace TW::Filecoin diff --git a/src/Groestlcoin/Entry.cpp b/src/Groestlcoin/Entry.cpp index 6235c416271..4886146bc36 100644 --- a/src/Groestlcoin/Entry.cpp +++ b/src/Groestlcoin/Entry.cpp @@ -19,7 +19,8 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return TW::Bitcoin::SegwitAddress::isValid(address, std::get(addressPrefix)); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TW::byte p2pkh, const char* hrp) const { +std::string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, const PrefixVariant& addressPrefix) const { + std::string hrp = getFromPrefixHrpOrDefault(addressPrefix, coin); return TW::Bitcoin::SegwitAddress(publicKey, hrp).string(); } diff --git a/src/Groestlcoin/Entry.h b/src/Groestlcoin/Entry.h index 37ea8ed1bc2..00e97274de9 100644 --- a/src/Groestlcoin/Entry.h +++ b/src/Groestlcoin/Entry.h @@ -15,9 +15,9 @@ namespace TW::Groestlcoin { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; - void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; - void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; + void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; } // namespace TW::Groestlcoin diff --git a/src/Harmony/Entry.cpp b/src/Harmony/Entry.cpp index 750f4d735ab..ccfd90d67f4 100644 --- a/src/Harmony/Entry.cpp +++ b/src/Harmony/Entry.cpp @@ -20,7 +20,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Harmony/Entry.h b/src/Harmony/Entry.h index 167779f8292..decd33bdaab 100644 --- a/src/Harmony/Entry.h +++ b/src/Harmony/Entry.h @@ -15,7 +15,7 @@ namespace TW::Harmony { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; bool supportsJSONSigning() const { return true; } diff --git a/src/Hedera/Entry.cpp b/src/Hedera/Entry.cpp index 60dfc7e124a..06691828d7c 100644 --- a/src/Hedera/Entry.cpp +++ b/src/Hedera/Entry.cpp @@ -15,7 +15,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Hedera/Entry.h b/src/Hedera/Entry.h index 5cf496ef185..ec85355b1c0 100644 --- a/src/Hedera/Entry.h +++ b/src/Hedera/Entry.h @@ -15,7 +15,7 @@ namespace TW::Hedera { class Entry final : public CoinEntry { public: virtual bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Icon/Entry.cpp b/src/Icon/Entry.cpp index 4df47c1728a..0f5572b8e9a 100644 --- a/src/Icon/Entry.cpp +++ b/src/Icon/Entry.cpp @@ -17,7 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey, Icon::TypeAddress).string(); } diff --git a/src/Icon/Entry.h b/src/Icon/Entry.h index feeed6df284..05d155ec177 100644 --- a/src/Icon/Entry.h +++ b/src/Icon/Entry.h @@ -15,7 +15,7 @@ namespace TW::Icon { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/IoTeX/Entry.cpp b/src/IoTeX/Entry.cpp index 85db67fe256..560aa3dcca1 100644 --- a/src/IoTeX/Entry.cpp +++ b/src/IoTeX/Entry.cpp @@ -19,7 +19,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/IoTeX/Entry.h b/src/IoTeX/Entry.h index 8793f9bcab9..2a6442749c9 100644 --- a/src/IoTeX/Entry.h +++ b/src/IoTeX/Entry.h @@ -15,7 +15,7 @@ namespace TW::IoTeX { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Kusama/Entry.cpp b/src/Kusama/Entry.cpp index 98876e41124..987862b4453 100644 --- a/src/Kusama/Entry.cpp +++ b/src/Kusama/Entry.cpp @@ -17,7 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Kusama/Entry.h b/src/Kusama/Entry.h index 0398c6f4acf..9104e6b514b 100644 --- a/src/Kusama/Entry.h +++ b/src/Kusama/Entry.h @@ -15,7 +15,7 @@ namespace TW::Kusama { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/NEAR/Entry.cpp b/src/NEAR/Entry.cpp index 63d69948969..17c60492305 100644 --- a/src/NEAR/Entry.cpp +++ b/src/NEAR/Entry.cpp @@ -24,7 +24,7 @@ string Entry::normalizeAddress([[maybe_unused]] TWCoinType coin, const string& a return Address(address).string(); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/NEAR/Entry.h b/src/NEAR/Entry.h index 41c5f52fc20..7e1786dc70d 100644 --- a/src/NEAR/Entry.h +++ b/src/NEAR/Entry.h @@ -16,7 +16,7 @@ class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string normalizeAddress(TWCoinType coin, const std::string& address) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/NEO/Entry.cpp b/src/NEO/Entry.cpp index 27a5d53fd92..fb17923025b 100644 --- a/src/NEO/Entry.cpp +++ b/src/NEO/Entry.cpp @@ -18,7 +18,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TW::byte p2pkh, [[maybe_unused]] const char* hrp) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/NEO/Entry.h b/src/NEO/Entry.h index 8881a48a2ba..d250e9bf494 100644 --- a/src/NEO/Entry.h +++ b/src/NEO/Entry.h @@ -15,7 +15,7 @@ namespace TW::NEO { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/NULS/Entry.cpp b/src/NULS/Entry.cpp index 27aba6043d9..726bb87df27 100644 --- a/src/NULS/Entry.cpp +++ b/src/NULS/Entry.cpp @@ -19,7 +19,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/NULS/Entry.h b/src/NULS/Entry.h index 1060cc41c8e..7a295547af5 100644 --- a/src/NULS/Entry.h +++ b/src/NULS/Entry.h @@ -15,7 +15,7 @@ namespace TW::NULS { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Nano/Entry.cpp b/src/Nano/Entry.cpp index 86858b9b1d3..e8e9fc1ab77 100644 --- a/src/Nano/Entry.cpp +++ b/src/Nano/Entry.cpp @@ -17,7 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Nano/Entry.h b/src/Nano/Entry.h index 9ca84e41eb0..50741817798 100644 --- a/src/Nano/Entry.h +++ b/src/Nano/Entry.h @@ -15,7 +15,7 @@ namespace TW::Nano { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; bool supportsJSONSigning() const { return true; } diff --git a/src/Nebulas/Entry.cpp b/src/Nebulas/Entry.cpp index 0487bb74e7d..fa0d26ce4ba 100644 --- a/src/Nebulas/Entry.cpp +++ b/src/Nebulas/Entry.cpp @@ -18,7 +18,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Nebulas/Entry.h b/src/Nebulas/Entry.h index 7fa88305c1c..da13dc54a1d 100644 --- a/src/Nebulas/Entry.h +++ b/src/Nebulas/Entry.h @@ -15,7 +15,7 @@ namespace TW::Nebulas { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Nervos/Entry.cpp b/src/Nervos/Entry.cpp index b4e9b071d55..48299735dc0 100644 --- a/src/Nervos/Entry.cpp +++ b/src/Nervos/Entry.cpp @@ -17,8 +17,8 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address, hrpPrefix ? *hrpPrefix : HRP_NERVOS); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, byte, - const char* hrp) const { +std::string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, const PrefixVariant& addressPrefix) const { + const char* hrp = getFromPrefixHrpOrDefault(addressPrefix, coin); return Address(publicKey, hrp).string(); } diff --git a/src/Nervos/Entry.h b/src/Nervos/Entry.h index e91a777e7fa..6cd02079189 100644 --- a/src/Nervos/Entry.h +++ b/src/Nervos/Entry.h @@ -18,8 +18,7 @@ namespace TW::Nervos { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, byte p2pkh, - const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Nimiq/Entry.cpp b/src/Nimiq/Entry.cpp index c063fe2d977..e750d1524bd 100644 --- a/src/Nimiq/Entry.cpp +++ b/src/Nimiq/Entry.cpp @@ -17,7 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Nimiq/Entry.h b/src/Nimiq/Entry.h index 6e19d3e24af..0a256d002fe 100644 --- a/src/Nimiq/Entry.h +++ b/src/Nimiq/Entry.h @@ -15,7 +15,7 @@ namespace TW::Nimiq { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Oasis/Entry.cpp b/src/Oasis/Entry.cpp index a9e1f4172bf..8d6f24bddd3 100644 --- a/src/Oasis/Entry.cpp +++ b/src/Oasis/Entry.cpp @@ -19,7 +19,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Oasis/Entry.h b/src/Oasis/Entry.h index 4ae19abbf0a..e8d1cf2af05 100644 --- a/src/Oasis/Entry.h +++ b/src/Oasis/Entry.h @@ -15,7 +15,7 @@ namespace TW::Oasis { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Ontology/Entry.cpp b/src/Ontology/Entry.cpp index 51d251e24d0..60d7da78a29 100644 --- a/src/Ontology/Entry.cpp +++ b/src/Ontology/Entry.cpp @@ -17,7 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Ontology/Entry.h b/src/Ontology/Entry.h index 836a0f391e3..42a6ab1424e 100644 --- a/src/Ontology/Entry.h +++ b/src/Ontology/Entry.h @@ -15,7 +15,7 @@ namespace TW::Ontology { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Polkadot/Entry.cpp b/src/Polkadot/Entry.cpp index db51b204ec1..d14e3ed5887 100644 --- a/src/Polkadot/Entry.cpp +++ b/src/Polkadot/Entry.cpp @@ -20,7 +20,10 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, const PrefixVariant& addressPrefix) const { + if (auto* ss58Prefix = std::get_if(&addressPrefix); ss58Prefix) { + return Address(publicKey, *ss58Prefix).string(); + } return Address(publicKey).string(); } @@ -33,11 +36,4 @@ void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::D signTemplate(dataIn, dataOut); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, const PrefixVariant& addressPrefix) const { - if (auto* ss58Prefix = std::get_if(&addressPrefix); ss58Prefix) { - return Address(publicKey, *ss58Prefix).string(); - } - return ""; -} - } // namespace TW::Polkadot diff --git a/src/Polkadot/Entry.h b/src/Polkadot/Entry.h index 5c19d70c6db..d62be51e167 100644 --- a/src/Polkadot/Entry.h +++ b/src/Polkadot/Entry.h @@ -15,7 +15,6 @@ namespace TW::Polkadot { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Ronin/Entry.cpp b/src/Ronin/Entry.cpp index 6eaf45cf2d8..8ad42d7feb6 100644 --- a/src/Ronin/Entry.cpp +++ b/src/Ronin/Entry.cpp @@ -22,7 +22,7 @@ string Entry::normalizeAddress([[maybe_unused]] TWCoinType coin, const string& a return Address(address).string(); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Ronin/Entry.h b/src/Ronin/Entry.h index 8723a549db1..1b485ea4cc1 100644 --- a/src/Ronin/Entry.h +++ b/src/Ronin/Entry.h @@ -15,7 +15,7 @@ class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string normalizeAddress(TWCoinType coin, const std::string& address) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; bool supportsJSONSigning() const { return true; } diff --git a/src/Solana/Entry.cpp b/src/Solana/Entry.cpp index 1e216d426ab..9ce90b67609 100644 --- a/src/Solana/Entry.cpp +++ b/src/Solana/Entry.cpp @@ -20,7 +20,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Solana/Entry.h b/src/Solana/Entry.h index 2735b866e69..3812f579ad9 100644 --- a/src/Solana/Entry.h +++ b/src/Solana/Entry.h @@ -15,7 +15,7 @@ namespace TW::Solana { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; bool supportsJSONSigning() const { return true; } diff --git a/src/Stellar/Entry.cpp b/src/Stellar/Entry.cpp index ce6cded2f72..f694d347c7f 100644 --- a/src/Stellar/Entry.cpp +++ b/src/Stellar/Entry.cpp @@ -17,7 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Stellar/Entry.h b/src/Stellar/Entry.h index 14f9dc4b6cd..617aa3cac10 100644 --- a/src/Stellar/Entry.h +++ b/src/Stellar/Entry.h @@ -15,7 +15,7 @@ namespace TW::Stellar { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Tezos/Entry.cpp b/src/Tezos/Entry.cpp index 19a6dc9f66c..39120d30a1b 100644 --- a/src/Tezos/Entry.cpp +++ b/src/Tezos/Entry.cpp @@ -17,7 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Tezos/Entry.h b/src/Tezos/Entry.h index ae744e64236..3b9f1bd697c 100644 --- a/src/Tezos/Entry.h +++ b/src/Tezos/Entry.h @@ -15,7 +15,7 @@ namespace TW::Tezos { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; bool supportsJSONSigning() const { return true; } std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; diff --git a/src/Tron/Entry.cpp b/src/Tron/Entry.cpp index 8a0feb4d29b..393c6be330d 100644 --- a/src/Tron/Entry.cpp +++ b/src/Tron/Entry.cpp @@ -18,7 +18,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Tron/Entry.h b/src/Tron/Entry.h index 531f2ef9127..d689b890aa7 100644 --- a/src/Tron/Entry.h +++ b/src/Tron/Entry.h @@ -15,7 +15,7 @@ namespace TW::Tron { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Waves/Entry.cpp b/src/Waves/Entry.cpp index 30b5e730871..5e0e0580904 100644 --- a/src/Waves/Entry.cpp +++ b/src/Waves/Entry.cpp @@ -19,7 +19,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Waves/Entry.h b/src/Waves/Entry.h index fe30cd62120..68d760f6718 100644 --- a/src/Waves/Entry.h +++ b/src/Waves/Entry.h @@ -15,7 +15,7 @@ namespace TW::Waves { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/XRP/Entry.cpp b/src/XRP/Entry.cpp index 7fd7c10f85e..c916cdcfd82 100644 --- a/src/XRP/Entry.cpp +++ b/src/XRP/Entry.cpp @@ -18,7 +18,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address) || XAddress::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/XRP/Entry.h b/src/XRP/Entry.h index f30c07fb4bc..0e8f4d98d59 100644 --- a/src/XRP/Entry.h +++ b/src/XRP/Entry.h @@ -15,7 +15,7 @@ namespace TW::Ripple { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Zcash/Entry.cpp b/src/Zcash/Entry.cpp index 883cf768027..5e23b51d63c 100644 --- a/src/Zcash/Entry.cpp +++ b/src/Zcash/Entry.cpp @@ -15,7 +15,8 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return TAddress::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, [[maybe_unused]] const char* hrp) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, const PrefixVariant& addressPrefix) const { + byte p2pkh = getFromPrefixPkhOrDefault(addressPrefix, coin); return TAddress(publicKey, p2pkh).string(); } diff --git a/src/Zcash/Entry.h b/src/Zcash/Entry.h index c50bcfc8ea7..787597ba42e 100644 --- a/src/Zcash/Entry.h +++ b/src/Zcash/Entry.h @@ -15,7 +15,7 @@ namespace TW::Zcash { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; void plan(TWCoinType coin, const Data& dataIn, Data& dataOut) const; diff --git a/src/Zilliqa/Entry.cpp b/src/Zilliqa/Entry.cpp index 249c2e2b5b0..3d4a09a635d 100644 --- a/src/Zilliqa/Entry.cpp +++ b/src/Zilliqa/Entry.cpp @@ -17,7 +17,7 @@ bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& return Address::isValid(address); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, byte, const char*) const { +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address(publicKey).string(); } diff --git a/src/Zilliqa/Entry.h b/src/Zilliqa/Entry.h index 90eda0931d1..a19932b711c 100644 --- a/src/Zilliqa/Entry.h +++ b/src/Zilliqa/Entry.h @@ -15,7 +15,7 @@ namespace TW::Zilliqa { class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; - std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; bool supportsJSONSigning() const { return true; } diff --git a/src/interface/TWAnyAddress.cpp b/src/interface/TWAnyAddress.cpp index 4f4713679ed..aae4d7d1fbf 100644 --- a/src/interface/TWAnyAddress.cpp +++ b/src/interface/TWAnyAddress.cpp @@ -10,6 +10,7 @@ #include "Data.h" #include "Coin.h" +#include "CoinEntry.h" #include "AnyAddress.h" bool TWAnyAddressEqual(struct TWAnyAddress* _Nonnull lhs, struct TWAnyAddress* _Nonnull rhs) { @@ -70,17 +71,17 @@ struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKey( struct TWAnyAddress* _Nonnull TWAnyAddressCreateWithPublicKeyDerivation( struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin, enum TWDerivation derivation) { - return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin, std::string(""), derivation)}; + return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin, derivation)}; } struct TWAnyAddress* _Nonnull TWAnyAddressCreateBech32WithPublicKey( struct TWPublicKey* _Nonnull publicKey, enum TWCoinType coin, TWString* _Nonnull hrp) { const auto& hrpStr = *reinterpret_cast(hrp); - return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin, hrpStr)}; + return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin, TWDerivationDefault, TW::Bech32Prefix(hrpStr.c_str()))}; } struct TWAnyAddress* TWAnyAddressCreateSS58WithPublicKey(struct TWPublicKey* publicKey, enum TWCoinType coin, uint32_t ss58Prefix) { - return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin, ss58Prefix)}; + return new TWAnyAddress{TW::AnyAddress::createAddress(publicKey->impl, coin, TWDerivationDefault, TW::SS58Prefix(ss58Prefix))}; } void TWAnyAddressDelete(struct TWAnyAddress* _Nonnull address) { diff --git a/tests/common/AnyAddressTests.cpp b/tests/common/AnyAddressTests.cpp index 917bd0ca07d..9adc700a2a1 100644 --- a/tests/common/AnyAddressTests.cpp +++ b/tests/common/AnyAddressTests.cpp @@ -30,11 +30,11 @@ TEST(AnyAddress, createFromPubKeyDerivation) { const Data key = parse_hex(ANY_ADDRESS_TEST_PUBKEY); PublicKey publicKey(key, TWPublicKeyTypeSECP256k1); { - std::unique_ptr addr(AnyAddress::createAddress(publicKey, TWCoinTypeBitcoin, std::string(""), TWDerivationDefault)); + std::unique_ptr addr(AnyAddress::createAddress(publicKey, TWCoinTypeBitcoin, TWDerivationDefault, std::monostate())); EXPECT_EQ(addr->address, ANY_ADDRESS_TEST_ADDRESS); } { - std::unique_ptr addr(AnyAddress::createAddress(publicKey, TWCoinTypeBitcoin, std::string(""), TWDerivationBitcoinLegacy)); + std::unique_ptr addr(AnyAddress::createAddress(publicKey, TWCoinTypeBitcoin, TWDerivationBitcoinLegacy, std::monostate())); EXPECT_EQ(addr->address, "1JvRfEQFv5q5qy9uTSAezH7kVQf4hqnHXx"); } } From 501f683b2b8301bc027b99a1ceaed1e104f70a2f Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Thu, 15 Dec 2022 08:41:08 +0100 Subject: [PATCH 157/497] =?UTF-8?q?New=20=E2=80=98newevmchain=E2=80=99=20s?= =?UTF-8?q?cript,=20subset=20of=20=E2=80=98newcoin=E2=80=99=20(#2792)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- codegen/bin/newcoin | 134 +---------------------------- codegen/bin/newevmchain | 21 +++++ codegen/lib/coin_skeleton_gen.rb | 142 +++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 130 deletions(-) create mode 100755 codegen/bin/newevmchain create mode 100755 codegen/lib/coin_skeleton_gen.rb diff --git a/codegen/bin/newcoin b/codegen/bin/newcoin index 8fdacb210fe..aeeec609d73 100755 --- a/codegen/bin/newcoin +++ b/codegen/bin/newcoin @@ -1,96 +1,14 @@ #!/usr/bin/env ruby -# Sript for creating new skeleton files for a new coin -# 1. Add relevsant entry to registry.json (in order to minimize merge conflict, don't add at the very end) +# Sript for creating new skeleton files for a new coin. See also `newevmchain`. +# 1. Add relevant entry to registry.json (in order to minimize merge conflict, don't add at the very end) # 2. Invoke this script with the id of the coin, e.g.: codegen/bin/newcoin ethereum -require 'erb' require 'fileutils' -require 'json' CurrentDir = File.dirname(__FILE__) $LOAD_PATH.unshift(File.join(CurrentDir, '..', 'lib')) -require 'entity_decl' -require 'code_generator' -require 'coin_test_gen' - -$flag_comment = " // TODO remove if the blockchain already exists, or just remove this comment if not" - -# Transforms a coin name to a C++ name -def self.format_name(coin) - formatted = coin['name'] - formatted = formatted.gsub(/-/, ' ') - formatted = formatted.gsub(/\./, ' ') - formatted = formatted.gsub(/\s/, '') - formatted -end - -def self.format_name_lowercase(coin) - format_name(coin).downcase -end - -def self.format_name_uppercase(coin) - format_name(coin).upcase -end - -def self.generate_file(templateFile, folder, fileName, coin) - @coin = coin - name = format_name(coin) - path = File.expand_path(templateFile, File.join(File.dirname(__FILE__), '..', 'lib', 'templates')) - template = ERB.new(File.read(path), nil, '-') - result = template.result(binding) - - FileUtils.mkdir_p folder - path = File.join(folder, fileName) - File.write(path, result) - puts "Generated file " + path -end - -def self.insert_coin_type(coin) - target_file = "include/TrustWalletCore/TWCoinType.h" - target_line = " TWCoinType#{format_name(coin)} = #{coin['coinId']},\n" - if insert_target_line(target_file, target_line, "};\n") - insert_blockchain_type(coin) - end -end - -def insert_blockchain_type(coin) - target_file = "include/TrustWalletCore/TWBlockchain.h" - line_number = File.readlines(target_file).count + 2 # add offset because of removed blockchain enum type - target_line = " TWBlockchain#{coin['blockchain']} = #{line_number - 17}, " + $flag_comment + "\n" - insert_target_line(target_file, target_line, "};\n") -end - -def insert_coin_entry(coin) - target_file = "src/Coin.cpp" - entryName = coin['blockchain'] - target_line = "#include \"#{entryName}/Entry.h\"" + $flag_comment + "\n" - insert_target_line(target_file, target_line, "// end_of_coin_includes_marker_do_not_modify\n") - target_line = "#{entryName}::Entry #{entryName}DP;" + $flag_comment + "\n" - insert_target_line(target_file, target_line, "// end_of_coin_dipatcher_declarations_marker_do_not_modify\n") - target_line = " case TWBlockchain#{entryName}: entry = &#{entryName}DP; break;" + $flag_comment + "\n" - insert_target_line(target_file, target_line, " // end_of_coin_dipatcher_switch_marker_do_not_modify\n") -end - -def self.insert_target_line(target_file, target_line, original_line) - lines = File.readlines(target_file) - index = lines.index(target_line) - if !index.nil? - puts "Line is already present, file: #{target_file} line: #{target_line}" - return true - end - index = lines.index(original_line) - if index.nil? - puts "WARNING: Could not find line! file: #{target_file} line: #{original_line}" - return false - end - lines.insert(index, target_line) - File.open(target_file, "w+") do |f| - f.puts(lines) - end - puts "Updated file: #{target_file} new line: #{target_line}" - return true -end +require 'coin_skeleton_gen' command_line_args = ARGV if command_line_args.length < 1 @@ -99,49 +17,5 @@ if command_line_args.length < 1 end coin_id = command_line_args[0] -puts "New coin template for coin '#{coin_id}' requested" - -json_string = File.read('registry.json') -coins = JSON.parse(json_string).sort_by { |x| x['name'] } - -entity = EntityDecl.new(name: "New" + coin_id, is_struct: false, comment: '') -file = "new"+ coin_id - -generator = CodeGenerator.new(entities: [entity], files: [file], output_folder: ".") - -@coins = coins - -coin_test_gen = CoinTestGen.new() - -# Find coin in list of coins, by Id -coinSelect = coins.select {|c| c['id'] == coin_id} -if coinSelect.length() == 0 - puts "Error: coin #{coin_id} not found!" - return -end -coin = coinSelect.first -name = format_name(coin) - - -insert_coin_type(coin) -insert_coin_entry(coin) - -generate_file("newcoin/Address.h.erb", "src/#{name}", "Address.h", coin) -generate_file("newcoin/Address.cpp.erb", "src/#{name}", "Address.cpp", coin) -generate_file("newcoin/Entry.h.erb", "src/#{name}", "Entry.h", coin) -generate_file("newcoin/Entry.cpp.erb", "src/#{name}", "Entry.cpp", coin) -generate_file("newcoin/Proto.erb", "src/proto", "#{name}.proto", coin) -generate_file("newcoin/Signer.h.erb", "src/#{name}", "Signer.h", coin) -generate_file("newcoin/Signer.cpp.erb", "src/#{name}", "Signer.cpp", coin) - -generate_file("newcoin/AddressTests.cpp.erb", "tests/chains/#{name}", "AddressTests.cpp", coin) -generate_file("newcoin/SignerTests.cpp.erb", "tests/chains/#{name}", "SignerTests.cpp", coin) -generate_file("newcoin/TWAddressTests.cpp.erb", "tests/chains/#{name}", "TWAnyAddressTests.cpp", coin) -generate_file("newcoin/TWSignerTests.cpp.erb", "tests/chains/#{name}", "TWAnySignerTests.cpp", coin) -generate_file("newcoin/AddressTests.kt.erb", "android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/#{format_name_lowercase(coin)}", "Test#{name}Address.kt", coin) -generate_file("newcoin/SignerTests.kt.erb", "android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/#{format_name_lowercase(coin)}", "Test#{name}Signer.kt", coin) -generate_file("newcoin/Tests.swift.erb", "swift/Tests/Blockchains", "#{name}Tests.swift", coin) - -coin_test_gen.generate_coin_test_file(coin, 'TWCoinTypeTests.cpp.erb', true) -puts "please tools/generate-files to generate Swift/Java/Protobuf files" +generate_skeleton(coin_id, "") diff --git a/codegen/bin/newevmchain b/codegen/bin/newevmchain new file mode 100755 index 00000000000..e5fed2a97fb --- /dev/null +++ b/codegen/bin/newevmchain @@ -0,0 +1,21 @@ +#!/usr/bin/env ruby + +# Sript for creating new skeleton files for a new EVM chain, subset of newcoin +# 1. Add relevant entry to registry.json (in order to minimize merge conflict, don't add at the very end) +# 2. Invoke this script with the id of the coin, e.g.: codegen/bin/newevmchain ethereumclone + +require 'fileutils' + +CurrentDir = File.dirname(__FILE__) +$LOAD_PATH.unshift(File.join(CurrentDir, '..', 'lib')) +require 'coin_skeleton_gen' + +command_line_args = ARGV +if command_line_args.length < 1 + puts "Usage: newevmchain " + return +end + +coin_id = command_line_args[0] + +generate_skeleton(coin_id, "evm") diff --git a/codegen/lib/coin_skeleton_gen.rb b/codegen/lib/coin_skeleton_gen.rb new file mode 100755 index 00000000000..c8adec9d8be --- /dev/null +++ b/codegen/lib/coin_skeleton_gen.rb @@ -0,0 +1,142 @@ +# frozen_string_literal: true + +require 'erb' +require 'fileutils' +require 'json' + +require 'entity_decl' +require 'code_generator' +require 'coin_test_gen' + +# Coin template generation + +$flag_comment = " // TODO remove if the blockchain already exists, or just remove this comment if not" + +# Transforms a coin name to a C++ name +def self.format_name(coin) + formatted = coin['name'] + formatted = formatted.gsub(/-/, ' ') + formatted = formatted.gsub(/\./, ' ') + formatted = formatted.gsub(/\s/, '') + formatted +end + +def self.format_name_lowercase(coin) +format_name(coin).downcase +end + +def self.format_name_uppercase(coin) +format_name(coin).upcase +end + +def self.generate_file(templateFile, folder, fileName, coin) + @coin = coin + name = format_name(coin) + path = File.expand_path(templateFile, File.join(File.dirname(__FILE__), '..', 'lib', 'templates')) + template = ERB.new(File.read(path), nil, '-') + result = template.result(binding) + + FileUtils.mkdir_p folder + path = File.join(folder, fileName) + File.write(path, result) + puts "Generated file " + path +end + +def self.insert_coin_type(coin, mode) + target_file = "include/TrustWalletCore/TWCoinType.h" + target_line = " TWCoinType#{format_name(coin)} = #{coin['coinId']},\n" + if insert_target_line(target_file, target_line, "};\n") + if (mode != "evm") + insert_blockchain_type(coin) + end + end +end + +def insert_blockchain_type(coin) + target_file = "include/TrustWalletCore/TWBlockchain.h" + line_number = File.readlines(target_file).count + 2 # add offset because of removed blockchain enum type + target_line = " TWBlockchain#{coin['blockchain']} = #{line_number - 17}, " + $flag_comment + "\n" + insert_target_line(target_file, target_line, "};\n") +end + +def insert_coin_entry(coin) + target_file = "src/Coin.cpp" + entryName = coin['blockchain'] + target_line = "#include \"#{entryName}/Entry.h\"" + $flag_comment + "\n" + insert_target_line(target_file, target_line, "// end_of_coin_includes_marker_do_not_modify\n") + target_line = "#{entryName}::Entry #{entryName}DP;" + $flag_comment + "\n" + insert_target_line(target_file, target_line, "// end_of_coin_dipatcher_declarations_marker_do_not_modify\n") + target_line = " case TWBlockchain#{entryName}: entry = &#{entryName}DP; break;" + $flag_comment + "\n" + insert_target_line(target_file, target_line, " // end_of_coin_dipatcher_switch_marker_do_not_modify\n") +end + +def self.insert_target_line(target_file, target_line, original_line) + lines = File.readlines(target_file) + index = lines.index(target_line) + if !index.nil? + puts "Line is already present, file: #{target_file} line: #{target_line}" + return true + end + index = lines.index(original_line) + if index.nil? + puts "WARNING: Could not find line! file: #{target_file} line: #{original_line}" + return false + end + lines.insert(index, target_line) + File.open(target_file, "w+") do |f| + f.puts(lines) + end + puts "Updated file: #{target_file} new line: #{target_line}" + return true +end + +def generate_skeleton(coin_id, mode) + puts "New coin template for coin '#{coin_id}' #{mode} requested" + + json_string = File.read('registry.json') + coins = JSON.parse(json_string).sort_by { |x| x['name'] } + + entity = EntityDecl.new(name: "New" + coin_id, is_struct: false, comment: '') + file = "new"+ coin_id + + generator = CodeGenerator.new(entities: [entity], files: [file], output_folder: ".") + + @coins = coins + + coin_test_gen = CoinTestGen.new() + + # Find coin in list of coins, by Id + coinSelect = coins.select {|c| c['id'] == coin_id} + if coinSelect.length() == 0 + puts "Error: coin #{coin_id} not found!" + return + end + coin = coinSelect.first + name = format_name(coin) + + + insert_coin_type(coin, mode) + if (mode != "evm") + insert_coin_entry(coin) + + generate_file("newcoin/Address.h.erb", "src/#{name}", "Address.h", coin) + generate_file("newcoin/Address.cpp.erb", "src/#{name}", "Address.cpp", coin) + generate_file("newcoin/Entry.h.erb", "src/#{name}", "Entry.h", coin) + generate_file("newcoin/Entry.cpp.erb", "src/#{name}", "Entry.cpp", coin) + generate_file("newcoin/Proto.erb", "src/proto", "#{name}.proto", coin) + generate_file("newcoin/Signer.h.erb", "src/#{name}", "Signer.h", coin) + generate_file("newcoin/Signer.cpp.erb", "src/#{name}", "Signer.cpp", coin) + + generate_file("newcoin/AddressTests.cpp.erb", "tests/chains/#{name}", "AddressTests.cpp", coin) + generate_file("newcoin/SignerTests.cpp.erb", "tests/chains/#{name}", "SignerTests.cpp", coin) + generate_file("newcoin/TWAddressTests.cpp.erb", "tests/chains/#{name}", "TWAnyAddressTests.cpp", coin) + generate_file("newcoin/TWSignerTests.cpp.erb", "tests/chains/#{name}", "TWAnySignerTests.cpp", coin) + generate_file("newcoin/AddressTests.kt.erb", "android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/#{format_name_lowercase(coin)}", "Test#{name}Address.kt", coin) + generate_file("newcoin/SignerTests.kt.erb", "android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/#{format_name_lowercase(coin)}", "Test#{name}Signer.kt", coin) + generate_file("newcoin/Tests.swift.erb", "swift/Tests/Blockchains", "#{name}Tests.swift", coin) + end + + coin_test_gen.generate_coin_test_file(coin, 'TWCoinTypeTests.cpp.erb', true) + + puts "please tools/generate-files to generate Swift/Java/Protobuf files" +end From df1b2236fad8ed62fb5551b3d373af164880afce Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 16 Dec 2022 15:37:11 +0100 Subject: [PATCH 158/497] [ThorSwap]: full DOGE/BCH/LTC support (#2798) --- src/THORChain/Swap.cpp | 33 ++++- src/THORChain/Swap.h | 5 +- tests/chains/THORChain/SwapTests.cpp | 193 +++++++++++++++++++++++++++ 3 files changed, 223 insertions(+), 8 deletions(-) diff --git a/src/THORChain/Swap.cpp b/src/THORChain/Swap.cpp index 829f104ba69..e23c4ec999a 100644 --- a/src/THORChain/Swap.cpp +++ b/src/THORChain/Swap.cpp @@ -50,6 +50,12 @@ TWCoinType chainCoinType(Chain chain) { return TWCoinTypeBinance; case Chain::BTC: return TWCoinTypeBitcoin; + case Chain::DOGE: + return TWCoinTypeDogecoin; + case Chain::BCH: + return TWCoinTypeBitcoinCash; + case Chain::LTC: + return TWCoinTypeLitecoin; case Chain::THOR: default: return TWCoinTypeTHORChain; @@ -64,6 +70,12 @@ std::string chainName(Chain chain) { return "BNB"; case Chain::BTC: return "BTC"; + case Chain::DOGE: + return "DOGE"; + case Chain::BCH: + return "BCH"; + case Chain::LTC: + return "LTC"; case Chain::THOR: default: return "THOR"; @@ -89,8 +101,11 @@ SwapBundled SwapBuilder::build(bool shortened) { const auto memo = this->buildMemo(shortened); switch (fromChain) { - case Chain::BTC: { - return buildBitcoin(fromAmountNum, memo); + case Chain::BTC: + case Chain::DOGE: + case Chain::BCH: + case Chain::LTC: { + return buildBitcoin(fromAmountNum, memo, fromChain); case Chain::BNB: return buildBinance(mFromAsset, fromAmountNum, memo); case Chain::ETH: @@ -110,12 +125,15 @@ std::string SwapBuilder::buildMemo(bool shortened) noexcept { const auto& toSymbol = mToAsset.symbol(); const auto toCoinToken = (!toTokenId.empty() && toTokenId != "0x0000000000000000000000000000000000000000") ? toTokenId : toSymbol; std::stringstream memo; - memo << prefix + ":" + chainName(toChain) + "." + toCoinToken + ":" + mToAddress + ":" + std::to_string(toAmountLimitNum); + memo << prefix + ":" + chainName(toChain) + "." + toCoinToken + ":" + mToAddress; + if (toAmountLimitNum > 0) { + memo << ":" << std::to_string(toAmountLimitNum); + } if (mAffFeeAddress.has_value() || mAffFeeRate.has_value() || mExtraMemo.has_value()) { memo << ":"; if (mAffFeeAddress.has_value()) { - memo << mAffFeeAddress.value(); + memo << mAffFeeAddress.value(); } if (mAffFeeRate.has_value() || mExtraMemo.has_value()) { memo << ":"; @@ -131,11 +149,12 @@ std::string SwapBuilder::buildMemo(bool shortened) noexcept { return memo.str(); } -SwapBundled SwapBuilder::buildBitcoin(uint64_t amount, const std::string& memo) { +SwapBundled SwapBuilder::buildBitcoin(uint64_t amount, const std::string& memo, Chain fromChain) { auto input = Bitcoin::Proto::SigningInput(); Data out; // Following fields must be set afterwards, before signing ... - input.set_hash_type(TWBitcoinSigHashTypeAll); + auto coinType = chainCoinType(fromChain); + input.set_hash_type(Bitcoin::hashTypeForCoin(coinType)); input.set_byte_fee(1); input.set_use_max_amount(false); // private_key[] @@ -146,7 +165,7 @@ SwapBundled SwapBuilder::buildBitcoin(uint64_t amount, const std::string& memo) input.set_amount(static_cast(amount)); input.set_to_address(mVaultAddress); input.set_change_address(mFromAddress); - input.set_coin_type(TWCoinTypeBitcoin); + input.set_coin_type(coinType); input.set_output_op_return(memo); auto serialized = input.SerializeAsString(); diff --git a/src/THORChain/Swap.h b/src/THORChain/Swap.h index bd4d253319b..504553567ef 100644 --- a/src/THORChain/Swap.h +++ b/src/THORChain/Swap.h @@ -21,6 +21,9 @@ enum Chain { BTC = 1, ETH = 2, BNB = 3, + DOGE = 4, + BCH = 5, + LTC = 6 }; using SwapErrorCode = int; @@ -44,7 +47,7 @@ class SwapBuilder { std::optional mAffFeeRate{std::nullopt}; std::optional mExtraMemo{std::nullopt}; - SwapBundled buildBitcoin(uint64_t amount, const std::string& memo); + SwapBundled buildBitcoin(uint64_t amount, const std::string& memo, Chain fromChain); SwapBundled buildBinance(Proto::Asset fromAsset, uint64_t amount, const std::string& memo); SwapBundled buildEth(uint64_t amount, const std::string& memo); diff --git a/tests/chains/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp index 591ed6b9e07..54bb152bb3c 100644 --- a/tests/chains/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -107,6 +107,199 @@ TEST(THORChainSwap, SwapBtcEth) { ); } +TEST(THORChainSwap, SwapDogeBusd) { + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::DOGE)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BNB)); + toAsset.set_symbol("BNB"); + toAsset.set_token_id("BUSD-BD1"); + + auto vaultDoge = "DExct9oTfqr7pfnbP2hkCHP1Z2eUDgqXya"; + auto fromAddressDoge = "DKftkYCtCyYxQy2TRAuAzQXoyKDdYsEBnw"; + auto toAddressBnb = "bnb1s4kallxngpyspzm6nrezkml9rgyw6kxpw4fhr2"; + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(fromAddressDoge) + .toAddress(toAddressBnb) + .vault(vaultDoge) + .fromAmount("10000000000") + .toAmountLimit("789627468") + .affFeeAddress("t") + .affFeeRate("0") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "08011080c8afa025180122224445786374396f546671723770666e625032686b434850315a3265554467715879612a22444b66746b5943744379597851793254524175417a51586f794b4464597345426e7750036a473d3a424e422e425553442d4244313a626e623173346b616c6c786e67707973707a6d366e72657a6b6d6c3972677977366b78707734666872323a3738393632373436383a743a30"); + + auto tx = Bitcoin::Proto::SigningInput(); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); + + // check fields + EXPECT_EQ(tx.amount(), 10000000000); + EXPECT_EQ(tx.to_address(), vaultDoge); + EXPECT_EQ(tx.change_address(), fromAddressDoge); + EXPECT_EQ(tx.output_op_return(), "=:BNB.BUSD-BD1:bnb1s4kallxngpyspzm6nrezkml9rgyw6kxpw4fhr2:789627468:t:0"); + EXPECT_EQ(tx.coin_type(), TWCoinTypeDogecoin); + EXPECT_EQ(tx.private_key_size(), 0); + EXPECT_FALSE(tx.has_plan()); + + // + auto dogeKey = parse_hex("3785864c91ed408ebaeae473962a471eb4d68ce998c2957e8e5f6be7a525f2d7"); + tx.add_private_key(dogeKey.data(), dogeKey.size()); + tx.set_byte_fee(1000); + auto& utxo = *tx.add_utxo(); + Data previousUTXOHash = parse_hex("9989c36afdd1755a679226875425b368816031186c0f1b4a363ab2ef6d0a2fe8"); + std::reverse(previousUTXOHash.begin(), previousUTXOHash.end()); + utxo.mutable_out_point()->set_hash(previousUTXOHash.data(), previousUTXOHash.size()); + utxo.mutable_out_point()->set_index(1); + utxo.mutable_out_point()->set_sequence(UINT32_MAX - 3); + auto utxoScript = Bitcoin::Script::lockScriptForAddress(fromAddressDoge, TWCoinTypeDogecoin); + utxo.set_script(utxoScript.bytes.data(), utxoScript.bytes.size()); + utxo.set_amount(16845776096); + tx.set_use_max_amount(false); + + // sign and encode resulting input + Bitcoin::Proto::SigningOutput output; + ANY_SIGN(tx, TWCoinTypeDogecoin); + EXPECT_EQ(output.error(), 0); + EXPECT_EQ(hex(output.encoded()), "0100000001e82f0a6defb23a364a1b0f6c1831608168b32554872692675a75d1fd6ac38999010000006b4830450221008660de3d3123a9e6831517265fb84c4fb2bfc4b98366dbfb4b63bc78a5812cce02201a0673af15edab604d9cd89f0e2842ccdd973e107ff9cd08dcf45d8c0b27c5dd0121039535d01e184b4a6d624e7ab007612e2558697fbed29274e6474f17e70d31ce5afcffffff0300e40b54020000001976a9146bb602e5e8eca75c7f6f25f766254658581db71688ac40490698010000001976a9149f64d0c07876a1dbce40cdce328bc7ecd8182b2288ac0000000000000000496a473d3a424e422e425553442d4244313a626e623173346b616c6c786e67707973707a6d366e72657a6b6d6c3972677977366b78707734666872323a3738393632373436383a743a3000000000"); + + // similar real transaction: + // https://viewblock.io/thorchain/tx/E7588A6A4C6B9DBA8B9AD8B0834655F9D9E5861744B5493E711623E320B981A5 + // https://dogechain.info/tx/e7588a6a4c6b9dba8b9ad8b0834655f9d9e5861744b5493e711623e320b981a5 + // https://binance.mintscan.io/txs/A5943D315BFD501DD5FC212F5A505772A20DDB154A8B5760A9897ABB8114CBDB +} + +TEST(THORChainSwap, SwapLtcBusd) { + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::LTC)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BNB)); + toAsset.set_symbol("BNB"); + toAsset.set_token_id("BUSD-BD1"); + + auto vaultLTC = "ltc1qmca5runvg3hygarulu34evdulcdfda7z7zquhn"; + auto fromAddressLTC = "ltc1qyu9qvkukx99r6yadxlk3t2x78a7dxe73s3r4x3"; + auto toAddressBnb = "bnb1s4kallxngpyspzm6nrezkml9rgyw6kxpw4fhr2"; + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(fromAddressLTC) + .toAddress(toAddressBnb) + .vault(vaultLTC) + .fromAmount("15000000") + .toAmountLimit("977240514") + .affFeeAddress("t") + .affFeeRate("0") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "080110c0c393071801222b6c746331716d63613572756e7667336879676172756c753334657664756c6364666461377a377a7175686e2a2b6c7463317179753971766b756b7839397236796164786c6b3374327837386137647865373373337234783350026a473d3a424e422e425553442d4244313a626e623173346b616c6c786e67707973707a6d366e72657a6b6d6c3972677977366b78707734666872323a3937373234303531343a743a30"); + + auto tx = Bitcoin::Proto::SigningInput(); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); + + // check fields + EXPECT_EQ(tx.amount(), 15000000); + EXPECT_EQ(tx.to_address(), vaultLTC); + EXPECT_EQ(tx.change_address(), fromAddressLTC); + EXPECT_EQ(tx.output_op_return(), "=:BNB.BUSD-BD1:bnb1s4kallxngpyspzm6nrezkml9rgyw6kxpw4fhr2:977240514:t:0"); + EXPECT_EQ(tx.coin_type(), TWCoinTypeLitecoin); + EXPECT_EQ(tx.private_key_size(), 0); + EXPECT_FALSE(tx.has_plan()); + + // + auto ltcKey = parse_hex("6affb3d4e2c4f5a23b711e67ca94d0bd93550e203f5c8258df74cc62282d1494"); + tx.add_private_key(ltcKey.data(), ltcKey.size()); + tx.set_byte_fee(140); + auto& utxo = *tx.add_utxo(); + Data previousUTXOHash = parse_hex("6e71e6da1898584ccf92c362db3d7c16326f9daae6687132c69abfdb043cc749"); + std::reverse(previousUTXOHash.begin(), previousUTXOHash.end()); + utxo.mutable_out_point()->set_hash(previousUTXOHash.data(), previousUTXOHash.size()); + utxo.mutable_out_point()->set_index(0); + utxo.mutable_out_point()->set_sequence(UINT32_MAX - 3); + auto utxoScript = Bitcoin::Script::lockScriptForAddress(fromAddressLTC, TWCoinTypeLitecoin); + utxo.set_script(utxoScript.bytes.data(), utxoScript.bytes.size()); + utxo.set_amount(34183600); + tx.set_use_max_amount(false); + + // sign and encode resulting input + Bitcoin::Proto::SigningOutput output; + ANY_SIGN(tx, TWCoinTypeLitecoin); + EXPECT_EQ(output.error(), 0); + EXPECT_EQ(hex(output.encoded()), "0100000000010149c73c04dbbf9ac6327168e6aa9d6f32167c3ddb62c392cf4c589818dae6716e0000000000fcffffff03c0e1e40000000000160014de3b41f26c446e44747cff235cb1bcfe1a96f7c2fc3d240100000000160014270a065b96314a3d13ad37ed15a8de3f7cd367d10000000000000000496a473d3a424e422e425553442d4244313a626e623173346b616c6c786e67707973707a6d366e72657a6b6d6c3972677977366b78707734666872323a3937373234303531343a743a3002483045022100fb9df5ef12c26648a50af298c5319ec52ea0287aa1405e07d817c606bb17a23502206520b087a9155a7d8c04b54b8ee3405fad9c3d22cf2c7cac06197ce555d56077012103acefb7d95b8c1da28f17400740d7e1124dbee3cfbe55646deb28198d570ea26b00000000"); + + // https://viewblock.io/thorchain/tx/FBB450335ED839C5FE3DCB9CBC0999DA6E6E52B787D1B165D3FA47E6273CCF5F + // https://blockchair.com/litecoin/transaction/fbb450335ed839c5fe3dcb9cbc0999da6e6e52b787d1b165d3fa47e6273ccf5f + // https://binance.mintscan.io/txs/7071DF040641D9C62EAA5D7AE5CDAC0C408FE64406261EC32417BD919684707C +} + +TEST(THORChainSwap, SwapBchBusd) { + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::BCH)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BNB)); + toAsset.set_symbol("BNB"); + toAsset.set_token_id("BUSD-BD1"); + + auto vaultBCH = "qpsfh5xvk7mgf9e6kl4e045nm6awl5hmks9x7h5ad6"; + auto fromAddressBCH = "qr50u7hy3xcr3j0w9j5nfx2gevjqgfm42ykc2hqgy4"; + auto toAddressBnb = "bnb1s4kallxngpyspzm6nrezkml9rgyw6kxpw4fhr2"; + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(fromAddressBCH) + .toAddress(toAddressBnb) + .vault(vaultBCH) + .fromAmount("10000000") + .toAmountLimit("977240514") + .affFeeAddress("t") + .affFeeRate("0") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "08411080ade2041801222a71707366683578766b376d67663965366b6c34653034356e6d3661776c35686d6b7339783768356164362a2a717235307537687933786372336a3077396a356e6678326765766a7167666d3432796b633268716779345091016a473d3a424e422e425553442d4244313a626e623173346b616c6c786e67707973707a6d366e72657a6b6d6c3972677977366b78707734666872323a3937373234303531343a743a30"); + + auto tx = Bitcoin::Proto::SigningInput(); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); + + // check fields + EXPECT_EQ(tx.amount(), 10000000); + EXPECT_EQ(tx.to_address(), vaultBCH); + EXPECT_EQ(tx.change_address(), fromAddressBCH); + EXPECT_EQ(tx.output_op_return(), "=:BNB.BUSD-BD1:bnb1s4kallxngpyspzm6nrezkml9rgyw6kxpw4fhr2:977240514:t:0"); + EXPECT_EQ(tx.coin_type(), TWCoinTypeBitcoinCash); + EXPECT_EQ(tx.private_key_size(), 0); + EXPECT_FALSE(tx.has_plan()); + + // + auto bchKey = parse_hex("1a3b0105a08908734ed0525f4c6fadca068514cdeb732d7ebca5b0fcbe6952a7"); + tx.add_private_key(bchKey.data(), bchKey.size()); + tx.set_byte_fee(3); + auto& utxo = *tx.add_utxo(); + Data previousUTXOHash = parse_hex("651e5d3a60f8110a6cfb745005168bdfcaf21e7f2f4371873a24b5cd894564da"); + std::reverse(previousUTXOHash.begin(), previousUTXOHash.end()); + utxo.mutable_out_point()->set_hash(previousUTXOHash.data(), previousUTXOHash.size()); + utxo.mutable_out_point()->set_index(1); + utxo.mutable_out_point()->set_sequence(UINT32_MAX - 3); + auto utxoScript = Bitcoin::Script::lockScriptForAddress(fromAddressBCH, TWCoinTypeBitcoinCash); + utxo.set_script(utxoScript.bytes.data(), utxoScript.bytes.size()); + utxo.set_amount(14118938); + tx.set_use_max_amount(false); + + // sign and encode resulting input + Bitcoin::Proto::SigningOutput output; + ANY_SIGN(tx, TWCoinTypeBitcoinCash); + EXPECT_EQ(output.error(), 0); + EXPECT_EQ(hex(output.encoded()), "0100000001da644589cdb5243a8771432f7f1ef2cadf8b16055074fb6c0a11f8603a5d1e65010000006a4730440220392fab53b86e02bef19638077fd378dd713dd6b1968d07f4507e28feb022d52a02200240bb2f2e8b8eb7673c4bc69b485e28a0d56c735d84e3f794c303c1b71759e941210393dc5157b5879cd602f25529437e01b3d4892a4b9b8d9efcaa640d842b27438efcffffff0380969800000000001976a914609bd0ccb7b684973ab7eb97d693debaefd2fbb488ac8ed63e00000000001976a914e8fe7ae489b038c9ee2ca9349948cb240427755188ac0000000000000000496a473d3a424e422e425553442d4244313a626e623173346b616c6c786e67707973707a6d366e72657a6b6d6c3972677977366b78707734666872323a3937373234303531343a743a3000000000"); + + // https://viewblock.io/thorchain/tx/B8AA6F2BFD09D7AC510BFCDA417903B2DDBEE0E9811821640D9C304B9B382B9B + // https://blockchair.com/bitcoin-cash/transaction/b8aa6f2bfd09d7ac510bfcda417903b2ddbee0e9811821640d9c304b9b382b9b + // https://binance.mintscan.io/txs/F4CD6554934E85D72269399607A7ADF8A92378C2287C164CC97CB57E8348B090 +} + TEST(THORChainSwap, SwapBtcBnb) { Proto::Asset fromAsset; fromAsset.set_chain(static_cast(Chain::BTC)); From 0fd392a29721c8ddd2f6392b549c751c0e2aa6b8 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 21 Dec 2022 11:44:40 +0100 Subject: [PATCH 159/497] [Immutable X]: Complete implementation (#2729) --- .../ethereum/TestEthereumMessageSigner.kt | 27 + .../starkex/TestStarkExMessageSigner.kt | 27 + .../core/app/utils/TestHDWallet.kt | 41 +- .../core/app/utils/TestPrivateKey.kt | 18 + .../core/app/utils/TestPublicKey.kt | 16 +- include/TrustWalletCore/TWCurve.h | 3 +- include/TrustWalletCore/TWEthereumEip2645.h | 28 + .../TrustWalletCore/TWEthereumMessageSigner.h | 41 + include/TrustWalletCore/TWHDWallet.h | 1 + include/TrustWalletCore/TWPublicKeyType.h | 1 + .../TrustWalletCore/TWStarkExMessageSigner.h | 40 + include/TrustWalletCore/TWStarkWare.h | 27 + rust/Cargo.lock | 866 ++++++++++++++++++ rust/Cargo.toml | 3 + rust/src/lib.rs | 1 + rust/src/starknet/mod.rs | 53 ++ src/Ethereum/EIP191.cpp | 38 + src/Ethereum/EIP191.h | 31 + src/Ethereum/EIP2645.cpp | 37 + src/Ethereum/EIP2645.h | 15 + src/HDWallet.cpp | 206 +++-- src/HDWallet.h | 17 +- src/HexCoding.h | 51 +- src/ImmutableX/Constants.h | 24 + src/ImmutableX/StarkKey.cpp | 83 ++ src/ImmutableX/StarkKey.h | 32 + src/Keystore/StoredKey.cpp | 20 +- src/Keystore/StoredKey.h | 16 +- src/PrivateKey.cpp | 18 +- src/PublicKey.cpp | 6 + src/PublicKey.h | 3 + src/StarkEx/MessageSigner.cpp | 23 + src/StarkEx/MessageSigner.h | 28 + src/XRP/Transaction.cpp | 5 +- src/interface/TWEthereumEip2645.cpp | 18 + src/interface/TWEthereumMessageSigner.cpp | 22 + src/interface/TWHDWallet.cpp | 4 +- src/interface/TWStarkExMessageSigner.cpp | 22 + src/interface/TWStarkWare.cpp | 17 + swift/Tests/Blockchains/EthereumTests.swift | 11 +- swift/Tests/Blockchains/StarkExTests.swift | 19 + swift/Tests/HDWalletTests.swift | 32 + swift/Tests/PrivateKeyTests.swift | 16 + swift/Tests/PublicKeyTests.swift | 10 + tests/chains/Ethereum/EIP191Tests.cpp | 37 + tests/chains/Ethereum/SignerTests.cpp | 4 +- tests/chains/ImmutableX/StarkKeyTests.cpp | 108 +++ tests/chains/StarkEx/MessageSignerTests.cpp | 37 + .../common/HDWallet/HDWalletInternalTests.cpp | 2 +- tests/common/HDWallet/HDWalletTests.cpp | 192 +++- tests/interface/TWHDWalletTests.cpp | 45 + walletconsole/lib/Address.cpp | 6 +- 52 files changed, 2289 insertions(+), 159 deletions(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumMessageSigner.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/starkex/TestStarkExMessageSigner.kt create mode 100644 include/TrustWalletCore/TWEthereumEip2645.h create mode 100644 include/TrustWalletCore/TWEthereumMessageSigner.h create mode 100644 include/TrustWalletCore/TWStarkExMessageSigner.h create mode 100644 include/TrustWalletCore/TWStarkWare.h create mode 100644 rust/src/starknet/mod.rs create mode 100644 src/Ethereum/EIP191.cpp create mode 100644 src/Ethereum/EIP191.h create mode 100644 src/Ethereum/EIP2645.cpp create mode 100644 src/Ethereum/EIP2645.h create mode 100644 src/ImmutableX/Constants.h create mode 100644 src/ImmutableX/StarkKey.cpp create mode 100644 src/ImmutableX/StarkKey.h create mode 100644 src/StarkEx/MessageSigner.cpp create mode 100644 src/StarkEx/MessageSigner.h create mode 100644 src/interface/TWEthereumEip2645.cpp create mode 100644 src/interface/TWEthereumMessageSigner.cpp create mode 100644 src/interface/TWStarkExMessageSigner.cpp create mode 100644 src/interface/TWStarkWare.cpp create mode 100644 swift/Tests/Blockchains/StarkExTests.swift create mode 100644 tests/chains/Ethereum/EIP191Tests.cpp create mode 100644 tests/chains/ImmutableX/StarkKeyTests.cpp create mode 100644 tests/chains/StarkEx/MessageSignerTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumMessageSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumMessageSigner.kt new file mode 100644 index 00000000000..0f0aae9efc4 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumMessageSigner.kt @@ -0,0 +1,27 @@ +package com.trustwallet.core.app.blockchains.ethereum + +import com.trustwallet.core.app.utils.Numeric +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import wallet.core.jni.CoinType +import wallet.core.jni.EthereumMessageSigner +import wallet.core.jni.PrivateKey + +class TestEthereumMessageSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testEthereumSignAndVerifyMessage() { + val data = Numeric.hexStringToByteArray("3b0a61f46fdae924007146eacb6db6642de7a5603ad843ec58e10331d89d4b84") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKey(CoinType.ETHEREUM) + val msg = "Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3" + val signature = EthereumMessageSigner.signMessage(privateKey, msg) + assertEquals(signature, "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01"); + assertTrue(EthereumMessageSigner.verifyMessage(publicKey, msg, signature)) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/starkex/TestStarkExMessageSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/starkex/TestStarkExMessageSigner.kt new file mode 100644 index 00000000000..d68cd722b80 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/starkex/TestStarkExMessageSigner.kt @@ -0,0 +1,27 @@ +package com.trustwallet.core.app.blockchains.starkex + +import com.trustwallet.core.app.utils.Numeric +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import wallet.core.jni.PrivateKey +import wallet.core.jni.PublicKeyType +import wallet.core.jni.StarkExMessageSigner + +class TestStarkExMessageSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testStarkExSignAndVerifyMessage() { + val data = Numeric.hexStringToByteArray("04be51a04e718c202e4dca60c2b72958252024cfc1070c090dd0f170298249de") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKeyByType(PublicKeyType.STARKEX) + val msg = "463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf" + val signature = StarkExMessageSigner.signMessage(privateKey, msg) + assertEquals(signature, "04cf5f21333dd189ada3c0f2a51430d733501a9b1d5e07905273c1938cfb261e05b6013d74adde403e8953743a338c8d414bb96bf69d2ca1a91a85ed2700a528"); + assertTrue(StarkExMessageSigner.verifyMessage(publicKey, msg, signature)) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt index ed1c171aa6b..07c91d0829b 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt @@ -8,19 +8,13 @@ package com.trustwallet.core.app.utils import com.trustwallet.core.app.utils.Numeric import com.trustwallet.core.app.utils.toHex -import wallet.core.jni.CoinType -import wallet.core.jni.Curve -import wallet.core.jni.Derivation -import wallet.core.jni.HDVersion -import wallet.core.jni.HDWallet -import wallet.core.jni.Mnemonic -import wallet.core.jni.Purpose import java.security.InvalidParameterException import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Assert.fail import org.junit.Test +import wallet.core.jni.* class TestHDWallet { init { @@ -31,6 +25,39 @@ class TestHDWallet { "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal" val password = "TREZOR" + @Test + fun testCreateFromMnemonicImmutableXMainnetFromSignature() { + // Successfully register: https://api.x.immutable.com/v1/users/0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37 + val hd = HDWallet("obscure opera favorite shuffle mail tip age debate dirt pact cement loyal", "") + val derivationPath = EthereumEip2645.getPath("0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37", "starkex", "immutablex", "1") + assertEquals(derivationPath, "m/2645'/579218131'/211006541'/2124474935'/1609799702'/1") + + // Retrieve eth private key + val ethPrivateKey = hd.getKeyForCoin(CoinType.ETHEREUM) + assertEquals(Numeric.toHexString(ethPrivateKey.data()), "0x03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d") + + // Retrieve StarkKey DerivationPath + val starkDerivationPath = DerivationPath(derivationPath) + + // Retrieve Stark Private key part + val ethMsg = "Only sign this request if you’ve initiated an action with Immutable X." + val ethSignature = EthereumMessageSigner.signMessage(ethPrivateKey, ethMsg) + assertEquals(ethSignature, "18b1be8b78807d3326e28bc286d7ee3d068dcd90b1949ce1d25c1f99825f26e70992c5eb7f44f76b202aceded00d74f771ed751f2fe538eec01e338164914fe001") + val starkPrivateKey = StarkWare.getStarkKeyFromSignature(starkDerivationPath, ethSignature) + val starkPublicKey = starkPrivateKey.getPublicKeyByType(PublicKeyType.STARKEX) + assertEquals(Numeric.toHexString(starkPrivateKey.data()), "0x04be51a04e718c202e4dca60c2b72958252024cfc1070c090dd0f170298249de") + assertEquals(Numeric.toHexString(starkPublicKey.data()), "0x00e5b9b11f8372610ef35d647a1dcaba1a4010716588d591189b27bf3c2d5095") + + // Account register + val ethMsgToRegister = "Only sign this key linking request from Immutable X" + val ethSignatureToRegister = EthereumMessageSigner.signMessage(ethPrivateKey, ethMsgToRegister) + assertEquals(ethSignatureToRegister, "646da4160f7fc9205e6f502fb7691a0bf63ecbb74bbb653465cd62388dd9f56325ab1e4a9aba99b1661e3e6251b42822855a71e60017b310b9f90e990a12e1dc01") + val starkMsg = "463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf" + val starkSignature = StarkExMessageSigner.signMessage(starkPrivateKey, starkMsg) + assertEquals(starkSignature, "04cf5f21333dd189ada3c0f2a51430d733501a9b1d5e07905273c1938cfb261e05b6013d74adde403e8953743a338c8d414bb96bf69d2ca1a91a85ed2700a528") + assertTrue(StarkExMessageSigner.verifyMessage(starkPublicKey, starkMsg, starkSignature)) + } + @Test fun testCreateFromMnemonic() { val hd = HDWallet(words, password) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPrivateKey.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPrivateKey.kt index 4b6b4908db8..aeb9239e671 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPrivateKey.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPrivateKey.kt @@ -19,6 +19,24 @@ class TestPrivateKey { assertTrue(data.size == 32); } + @Test + fun testCreateStarkKey() { + val data = Numeric.hexStringToByteArray("06cf0a8bf113352eb863157a45c5e5567abb34f8d32cddafd2c22aa803f4892c") + assertTrue(PrivateKey.isValid(data, Curve.STARKEX)) + var privateKey = PrivateKey(data) + var pubKey = privateKey.getPublicKeyByType(PublicKeyType.STARKEX) + assertEquals(pubKey.data().toHex(), "0x02d2bbdc1adaf887b0027cdde2113cfd81c60493aa6dc15d7887ddf1a82bc831") + } + + @Test + fun testCreateStarkKeySigning() { + val data = Numeric.hexStringToByteArray("0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79") + var privateKey = PrivateKey(data) + val digest = Numeric.hexStringToByteArray("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76") + val signature = privateKey.sign(digest, Curve.STARKEX) + assertEquals(signature.toHex(), "0x061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a") + } + @Test fun testInvalid() { val bytes = Numeric.hexStringToByteArray("deadbeaf") diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPublicKey.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPublicKey.kt index dbd57dc1425..bfecc51014e 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPublicKey.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestPublicKey.kt @@ -4,10 +4,7 @@ import com.trustwallet.core.app.utils.toHexBytes import com.trustwallet.core.app.utils.toHex import org.junit.Assert.* import org.junit.Test -import wallet.core.jni.Curve -import wallet.core.jni.Hash -import wallet.core.jni.PrivateKey -import wallet.core.jni.PublicKey +import wallet.core.jni.* class TestPublicKey { @@ -28,6 +25,17 @@ class TestPublicKey { val publicKey = privateKey?.getPublicKeySecp256k1(true) assertEquals("0x0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1", publicKey?.data()?.toHex()) } + + @Test + fun testVerifyStarkey() { + val data = Numeric.hexStringToByteArray("02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159") + val publicKey = PublicKey(data, PublicKeyType.STARKEX) + var signature = Numeric.hexStringToByteArray("061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a") + val hash = Numeric.hexStringToByteArray("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76") + assertTrue(publicKey.verify(signature, hash)) + signature = Numeric.hexStringToByteArray("061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9b") + assertFalse(publicKey.verify(signature, hash)) + } @Test fun testSign() { diff --git a/include/TrustWalletCore/TWCurve.h b/include/TrustWalletCore/TWCurve.h index 79d2891aa40..36f0edbd7f6 100644 --- a/include/TrustWalletCore/TWCurve.h +++ b/include/TrustWalletCore/TWCurve.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -19,6 +19,7 @@ enum TWCurve { TWCurveCurve25519 /* "curve25519" */, TWCurveNIST256p1 /* "nist256p1" */, TWCurveED25519ExtendedCardano /* "ed25519-cardano-seed" */, + TWCurveStarkex /* "starkex" */, TWCurveNone }; diff --git a/include/TrustWalletCore/TWEthereumEip2645.h b/include/TrustWalletCore/TWEthereumEip2645.h new file mode 100644 index 00000000000..f6315908c33 --- /dev/null +++ b/include/TrustWalletCore/TWEthereumEip2645.h @@ -0,0 +1,28 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" +#include "TWString.h" + +TW_EXTERN_C_BEGIN + +TW_EXPORT_CLASS +struct TWEthereumEip2645; + +/// Generate a layer 2 eip2645 derivation path from eth address, layer, application and given index. +/// +/// \param wallet non-null TWHDWallet +/// \param ethAddress non-null Ethereum address +/// \param layer non-null layer 2 name (E.G starkex) +/// \param application non-null layer 2 application (E.G immutablex) +/// \param index non-null layer 2 index (E.G 1) +/// \return a valid eip2645 layer 2 derivation path as a string +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumEip2645GetPath(TWString* _Nonnull ethAddress, TWString* _Nonnull layer, TWString* _Nonnull application, TWString* _Nonnull index); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWEthereumMessageSigner.h b/include/TrustWalletCore/TWEthereumMessageSigner.h new file mode 100644 index 00000000000..1fb230b143f --- /dev/null +++ b/include/TrustWalletCore/TWEthereumMessageSigner.h @@ -0,0 +1,41 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" +#include "TWPrivateKey.h" +#include "TWPublicKey.h" + +TW_EXTERN_C_BEGIN + +/// Ethereum message signing and verification. +/// +/// Ethereum and some other wallets support a message signing & verification format, to create a proof (a signature) +/// that someone has access to the private keys of a specific address. +TW_EXPORT_CLASS +struct TWEthereumMessageSigner; + +/// Sign a message. +/// +/// \param privateKey: the private key used for signing +/// \param message: A custom message which is input to the signing. +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message); + +/// Verify signature for a message. +/// +/// \param pubKey: pubKey that will verify and recover the message from the signature +/// \param message: the message signed (without prefix) +/// \param signature: in Hex-encoded form. +/// \returns false on any invalid input (does not throw), true if the message can be recovered from the signature +TW_EXPORT_STATIC_METHOD +bool TWEthereumMessageSignerVerifyMessage(const struct TWPublicKey* _Nonnull pubKey, TWString* _Nonnull message, TWString* _Nonnull signature); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWHDWallet.h b/include/TrustWalletCore/TWHDWallet.h index a6261f57a7b..84b951ddc4f 100644 --- a/include/TrustWalletCore/TWHDWallet.h +++ b/include/TrustWalletCore/TWHDWallet.h @@ -11,6 +11,7 @@ #include "TWCurve.h" #include "TWData.h" #include "TWDerivation.h" +#include "TWDerivationPath.h" #include "TWHDVersion.h" #include "TWPrivateKey.h" #include "TWPublicKey.h" diff --git a/include/TrustWalletCore/TWPublicKeyType.h b/include/TrustWalletCore/TWPublicKeyType.h index e9d0e53b347..c5ee21c5f74 100644 --- a/include/TrustWalletCore/TWPublicKeyType.h +++ b/include/TrustWalletCore/TWPublicKeyType.h @@ -21,6 +21,7 @@ enum TWPublicKeyType { TWPublicKeyTypeED25519Blake2b = 5, TWPublicKeyTypeCURVE25519 = 6, TWPublicKeyTypeED25519Cardano = 7, + TWPublicKeyTypeStarkex = 8, }; TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWStarkExMessageSigner.h b/include/TrustWalletCore/TWStarkExMessageSigner.h new file mode 100644 index 00000000000..a7569171c39 --- /dev/null +++ b/include/TrustWalletCore/TWStarkExMessageSigner.h @@ -0,0 +1,40 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" +#include "TWPrivateKey.h" + +TW_EXTERN_C_BEGIN + +/// StarkEx message signing and verification. +/// +/// StarkEx and some other wallets support a message signing & verification format, to create a proof (a signature) +/// that someone has access to the private keys of a specific address. +TW_EXPORT_CLASS +struct TWStarkExMessageSigner; + +/// Sign a message. +/// +/// \param privateKey: the private key used for signing +/// \param message: A custom hex message which is input to the signing. +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWStarkExMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message); + +/// Verify signature for a message. +/// +/// \param pubKey: pubKey that will verify and recover the message from the signature +/// \param message: the message signed (without prefix) in hex +/// \param signature: in Hex-encoded form. +/// \returns false on any invalid input (does not throw), true if the message can be recovered from the signature +TW_EXPORT_STATIC_METHOD +bool TWStarkExMessageSignerVerifyMessage(const struct TWPublicKey* _Nonnull pubKey, TWString* _Nonnull message, TWString* _Nonnull signature); + +TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWStarkWare.h b/include/TrustWalletCore/TWStarkWare.h new file mode 100644 index 00000000000..0990d67be86 --- /dev/null +++ b/include/TrustWalletCore/TWStarkWare.h @@ -0,0 +1,27 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" +#include "TWPrivateKey.h" +#include "TWString.h" +#include "TWDerivationPath.h" + +TW_EXTERN_C_BEGIN + +TW_EXPORT_CLASS +struct TWStarkWare; + +/// Generates the private stark key at the given derivation path from a valid eth signature +/// +/// \param derivationPath non-null StarkEx Derivation path +/// \param signature valid eth signature +/// \return The private key for the specified derivation path/signature +TW_EXPORT_STATIC_METHOD +struct TWPrivateKey* _Nonnull TWStarkWareGetStarkKeyFromSignature(const struct TWDerivationPath* _Nonnull derivationPath, TWString* _Nonnull signature); + +TW_EXTERN_C_END diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 18607412aba..00747873f1b 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -8,6 +8,95 @@ version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std", + "digest 0.9.0", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "async-trait" +version = "0.1.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "bcs" version = "0.1.4" @@ -18,12 +107,239 @@ dependencies = [ "thiserror", ] +[[package]] +name = "bitvec" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer 0.10.3", + "crypto-common", +] + +[[package]] +name = "ethbloom" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb684ac8fa8f6c5759f788862bb22ec6fe3cb392f6bfd08e3c64b603661e3f8" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05136f7057fe789f06e6d41d07b34e6f70d8c86e5693b60f97aaa6553553bdaf" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.8" @@ -31,8 +347,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -41,12 +359,99 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "impl-codec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] + [[package]] name = "libc" version = "0.2.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + [[package]] name = "move-core-types" version = "0.0.4" @@ -62,18 +467,120 @@ dependencies = [ "serde_bytes", ] +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + [[package]] name = "once_cell" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parity-scale-codec" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "paste" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" + +[[package]] +name = "pest" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8" +dependencies = [ + "thiserror", + "ucd-trie", +] + [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "primitive-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +dependencies = [ + "once_cell", + "thiserror", + "toml", +] + [[package]] name = "proc-macro2" version = "1.0.47" @@ -92,6 +599,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" + [[package]] name = "rand" version = "0.8.5" @@ -142,6 +655,66 @@ dependencies = [ "syn", ] +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac", + "zeroize", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.147" @@ -171,6 +744,143 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha3" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +dependencies = [ + "digest 0.10.6", + "keccak", +] + +[[package]] +name = "starknet-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95540acef038bfdf3c91da323cedf0fd335f73899152cabdf407033fc7560713" +dependencies = [ + "base64", + "ethereum-types", + "hex", + "serde", + "serde_json", + "serde_with", + "sha3", + "starknet-crypto", + "starknet-ff", + "thiserror", +] + +[[package]] +name = "starknet-crypto" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d5ba05430fcd7c107ad9e4433bb3958722b13d97a44fd07a18dcf0eb6da667" +dependencies = [ + "crypto-bigint", + "hex", + "hmac", + "num-bigint", + "num-integer", + "num-traits", + "rfc6979", + "sha2", + "starknet-ff", + "thiserror", + "zeroize", +] + +[[package]] +name = "starknet-ff" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a80865f37a0dcd198f427356d939f1495144c26ed5123b1418ef33a63f82655" +dependencies = [ + "ark-ff", + "crypto-bigint", + "getrandom", + "hex", + "serde", + "thiserror", +] + +[[package]] +name = "starknet-signers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8199e756cc1ba3a8cd8287368b2bbd3bf7a876e98b3eea8abc5e851ee58bc5" +dependencies = [ + "async-trait", + "starknet-core", + "starknet-crypto", + "thiserror", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.103" @@ -182,6 +892,24 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "thiserror" version = "1.0.37" @@ -202,12 +930,66 @@ dependencies = [ "syn", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unicode-ident" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "wallet-core-rs" version = "0.1.0" @@ -215,6 +997,9 @@ dependencies = [ "bcs", "hex", "move-core-types", + "starknet-crypto", + "starknet-ff", + "starknet-signers", ] [[package]] @@ -222,3 +1007,84 @@ name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 9a75f71be9c..b3a7546634b 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -11,6 +11,9 @@ crate-type = ["staticlib"] # Creates static lib [dependencies] move-core-types = { git = "https://github.com/move-language/move", rev = "f7137eabc2046f76fdad3ded2c51e03a3b1fbd01", features = ["address32"] } +starknet-crypto = "0.1.0" +starknet-ff = "0.1.0" +starknet-signers = "0.1.0" bcs = "0.1.4" hex = "0.4.3" diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 4f3c0712189..01bae1bc0ae 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -6,3 +6,4 @@ pub mod move_parser; pub mod memory; +pub mod starknet; diff --git a/rust/src/starknet/mod.rs b/rust/src/starknet/mod.rs new file mode 100644 index 00000000000..9da51860024 --- /dev/null +++ b/rust/src/starknet/mod.rs @@ -0,0 +1,53 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +use std::ffi::{c_char, CStr}; +use starknet_crypto::{FieldElement, get_public_key, Signature}; +use starknet_signers::{SigningKey, VerifyingKey}; +use crate::memory; + +pub fn field_element_from_be_hex(hex: &str) -> FieldElement { + let decoded = hex::decode(hex.trim_start_matches("0x")).unwrap(); + + if decoded.len() > 32 { + panic!("hex string too long"); + } + + let mut buffer = [0u8; 32]; + buffer[(32 - decoded.len())..].copy_from_slice(&decoded[..]); + + FieldElement::from_bytes_be(&buffer).unwrap() +} + +#[no_mangle] +pub extern fn starknet_pubkey_from_private(priv_key: *const c_char) -> *const c_char { + let s = unsafe { CStr::from_ptr(priv_key).to_str().unwrap() }; + let private_key = field_element_from_be_hex(s); + let hx = format!("{:#02x}", get_public_key(&private_key)); + memory::c_string_standalone(hx) +} + +#[no_mangle] +pub extern fn starknet_sign(priv_key: *const c_char, hash: *const c_char) -> *const c_char { + let s = unsafe { CStr::from_ptr(priv_key).to_str().unwrap() }; + let private_key = field_element_from_be_hex(s); + let h = unsafe { CStr::from_ptr(hash).to_str().unwrap() }; + let hash_field = field_element_from_be_hex(h); + let signing_key = SigningKey::from_secret_scalar(private_key); + let signature = signing_key.sign(&hash_field).unwrap(); + let hx = format!("{}", signature); + memory::c_string_standalone(hx) +} + +#[no_mangle] +pub extern fn starknet_verify(pub_key: *const c_char, hash: *const c_char, r: *const c_char, s: *const c_char) -> bool { + let pub_key = unsafe { field_element_from_be_hex(CStr::from_ptr(pub_key).to_str().unwrap()) }; + let hash = unsafe { field_element_from_be_hex(CStr::from_ptr(hash).to_str().unwrap()) }; + let r = unsafe { field_element_from_be_hex(CStr::from_ptr(r).to_str().unwrap()) }; + let s = unsafe { field_element_from_be_hex(CStr::from_ptr(s).to_str().unwrap()) }; + let verifying_key = VerifyingKey::from_scalar(pub_key); + verifying_key.verify(&hash, &Signature { r, s }).unwrap_or(false) +} diff --git a/src/Ethereum/EIP191.cpp b/src/Ethereum/EIP191.cpp new file mode 100644 index 00000000000..309c61c959c --- /dev/null +++ b/src/Ethereum/EIP191.cpp @@ -0,0 +1,38 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "EIP191.h" +#include "HexCoding.h" +#include +#include + +namespace TW::Ethereum::internal { + +Data generateMessage(const std::string& message) { + std::string prefix(1, MessageSigner::EthereumPrefix); + std::stringstream ss; + ss << prefix << MessageSigner::MessagePrefix << std::to_string(message.size()) << message; + Data signableMessage = Hash::keccak256(data(ss.str())); + return signableMessage; +} + +} // namespace TW::Ethereum::internal + +namespace TW::Ethereum { + +std::string MessageSigner::signMessage(const PrivateKey& privateKey, const std::string& message) { + auto signableMessage = internal::generateMessage(message); + return hex(privateKey.sign(signableMessage, TWCurveSECP256k1)); +} + +bool MessageSigner::verifyMessage(const PublicKey& publicKey, const std::string& message, const std::string& signature) noexcept { + auto msg = internal::generateMessage(message); + auto rawSignature = parse_hex(signature); + auto recovered = publicKey.recover(rawSignature, msg); + return recovered == publicKey && publicKey.verify(rawSignature, msg); +} + +} // namespace TW::Ethereum diff --git a/src/Ethereum/EIP191.h b/src/Ethereum/EIP191.h new file mode 100644 index 00000000000..c1267ab0452 --- /dev/null +++ b/src/Ethereum/EIP191.h @@ -0,0 +1,31 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include + +namespace TW::Ethereum { + +class MessageSigner { +public: + /// Sign a message following EIP-191 + /// \param privateKey the private key to sign with + /// \param message message to sign + /// \return hex signed message + static std::string signMessage(const PrivateKey& privateKey, const std::string& message); + /// Verify a message following EIP-191 + /// \param publicKey publickey to verify the signed message + /// \param message message to be verified as a string + /// \param signature signature to verify the message against + /// \return true if the message match the signature, false otherwise + static bool verifyMessage(const PublicKey& publicKey, const std::string& message, const std::string& signature) noexcept; + static constexpr auto MessagePrefix = "Ethereum Signed Message:\n"; + static constexpr std::uint8_t EthereumPrefix{0x19}; +}; + +} // namespace TW::Ethereum diff --git a/src/Ethereum/EIP2645.cpp b/src/Ethereum/EIP2645.cpp new file mode 100644 index 00000000000..9a601643999 --- /dev/null +++ b/src/Ethereum/EIP2645.cpp @@ -0,0 +1,37 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include +#include + +#include + +namespace TW::Ethereum::internal { + +static std::string getIntFromBits(const std::string& hexString, std::size_t from, std::optional length = std::nullopt) { + const auto data = hex_str_to_bin_str(hexString); + const auto sub = data.substr(data.size() - from, length.value_or(std::string::npos)); + return std::to_string(std::stoll(sub, nullptr, 2)); +} + +} // namespace TW::Ethereum::internal + +namespace TW::Ethereum { + +// https://docs.starkware.co/starkex/key-derivation.html +std::string accountPathFromAddress(const std::string& ethAddress, const std::string& layer, const std::string& application, const std::string& index) noexcept { + using namespace internal; + std::stringstream out; + const auto layerHash = getIntFromBits(hex(Hash::sha256(data(layer))), 31); + const auto applicationHash = getIntFromBits(hex(Hash::sha256(data(application))), 31); + const auto ethAddress1 = getIntFromBits(ethAddress.substr(2), 31); + const auto ethAddress2 = getIntFromBits(ethAddress.substr(2), 62, 31); + out << "m/2645'/" << layerHash << "'/" << applicationHash << "'/" << ethAddress1 << "'/" << ethAddress2 << "'/" << index; + return out.str(); +} + +} // namespace TW::Ethereum diff --git a/src/Ethereum/EIP2645.h b/src/Ethereum/EIP2645.h new file mode 100644 index 00000000000..3dd582a4381 --- /dev/null +++ b/src/Ethereum/EIP2645.h @@ -0,0 +1,15 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include + +namespace TW::Ethereum { + +std::string accountPathFromAddress(const std::string& ethAddress, const std::string& layer, const std::string& application, const std::string& index) noexcept;; + +} // namespace TW::Ethereum diff --git a/src/HDWallet.cpp b/src/HDWallet.cpp index db73dc18f9b..682bfcddc62 100644 --- a/src/HDWallet.cpp +++ b/src/HDWallet.cpp @@ -11,6 +11,7 @@ #include "Bitcoin/CashAddress.h" #include "Bitcoin/SegwitAddress.h" #include "Coin.h" +#include "ImmutableX/StarkKey.h" #include "Mnemonic.h" #include "memory/memzero_wrapper.h" @@ -34,15 +35,34 @@ namespace { uint32_t fingerprint(HDNode* node, Hash::Hasher hasher); std::string serialize(const HDNode* node, uint32_t fingerprint, uint32_t version, bool use_public, Hash::Hasher hasher); bool deserialize(const std::string& extended, TWCurve curve, Hash::Hasher hasher, HDNode* node); -HDNode getNode(const HDWallet& wallet, TWCurve curve, const DerivationPath& derivationPath); -HDNode getMasterNode(const HDWallet& wallet, TWCurve curve); - const char* curveName(TWCurve curve); } // namespace const int MnemonicBufLength = Mnemonic::MaxWords * (BIP39_MAX_WORD_LENGTH + 3) + 20; // some extra slack -HDWallet::HDWallet(int strength, const std::string& passphrase) +template +HDWallet::HDWallet(const Data& seed) { + std::copy_n(seed.begin(), seedSize, this->seed.begin()); +} + +template +void HDWallet::updateSeedAndEntropy(bool check) { + assert(!check || Mnemonic::isValid(mnemonic)); // precondition + + // generate seed from mnemonic + mnemonic_to_seed(mnemonic.c_str(), passphrase.c_str(), seed.data(), nullptr); + + // generate entropy bits from mnemonic + Data entropyRaw((Mnemonic::MaxWords * Mnemonic::BitsPerWord) / 8); + // entropy is truncated to fully bytes, 4 bytes for each 3 words (=33 bits) + auto entropyBytes = mnemonic_to_bits(mnemonic.c_str(), entropyRaw.data()) / 33 * 4; + // copy to truncate + entropy = data(entropyRaw.data(), entropyBytes); + assert(!check || entropy.size() > 10); +} + +template +HDWallet::HDWallet(int strength, const std::string& passphrase) : passphrase(passphrase) { char buf[MnemonicBufLength]; const char* mnemonic_chars = mnemonic_generate(strength, buf, MnemonicBufLength); @@ -54,7 +74,8 @@ HDWallet::HDWallet(int strength, const std::string& passphrase) updateSeedAndEntropy(); } -HDWallet::HDWallet(const std::string& mnemonic, const std::string& passphrase, const bool check) +template +HDWallet::HDWallet(const std::string& mnemonic, const std::string& passphrase, const bool check) : mnemonic(mnemonic), passphrase(passphrase) { if (mnemonic.length() == 0 || (check && !Mnemonic::isValid(mnemonic))) { @@ -63,7 +84,8 @@ HDWallet::HDWallet(const std::string& mnemonic, const std::string& passphrase, c updateSeedAndEntropy(check); } -HDWallet::HDWallet(const Data& entropy, const std::string& passphrase) +template +HDWallet::HDWallet(const Data& entropy, const std::string& passphrase) : passphrase(passphrase) { char buf[MnemonicBufLength]; const char* mnemonic_chars = mnemonic_from_data(entropy.data(), static_cast(entropy.size()), buf, MnemonicBufLength); @@ -75,59 +97,80 @@ HDWallet::HDWallet(const Data& entropy, const std::string& passphrase) updateSeedAndEntropy(); } -HDWallet::~HDWallet() { +template +HDWallet::~HDWallet() { std::fill(seed.begin(), seed.end(), 0); std::fill(mnemonic.begin(), mnemonic.end(), 0); std::fill(passphrase.begin(), passphrase.end(), 0); } -void HDWallet::updateSeedAndEntropy(bool check) { - assert(!check || Mnemonic::isValid(mnemonic)); // precondition - - // generate seed from mnemonic - mnemonic_to_seed(mnemonic.c_str(), passphrase.c_str(), seed.data(), nullptr); +template +static HDNode getMasterNode(const HDWallet& wallet, TWCurve curve) { + const auto privateKeyType = PrivateKey::getType(curve); + HDNode node; + switch (privateKeyType) { + case TWPrivateKeyTypeCardano: { + // Derives the root Cardano HDNode from a passphrase and the entropy encoded in + // a BIP-0039 mnemonic using the Icarus derivation (V2) scheme + const auto entropy = wallet.getEntropy(); + uint8_t secret[CARDANO_SECRET_LENGTH]; + secret_from_entropy_cardano_icarus((const uint8_t*)"", 0, entropy.data(), int(entropy.size()), secret, nullptr); + hdnode_from_secret_cardano(secret, &node); + TW::memzero(secret, CARDANO_SECRET_LENGTH); + break; + } + case TWPrivateKeyTypeDefault: + default: + hdnode_from_seed(wallet.getSeed().data(), HDWallet::mSeedSize, curveName(curve), &node); + break; + } + return node; +} - // generate entropy bits from mnemonic - Data entropyRaw((Mnemonic::MaxWords * Mnemonic::BitsPerWord) / 8); - // entropy is truncated to fully bytes, 4 bytes for each 3 words (=33 bits) - auto entropyBytes = mnemonic_to_bits(mnemonic.c_str(), entropyRaw.data()) / 33 * 4; - // copy to truncate - entropy = data(entropyRaw.data(), entropyBytes); - assert(!check || entropy.size() > 10); +template +static HDNode getNode(const HDWallet& wallet, TWCurve curve, const DerivationPath& derivationPath) { + const auto privateKeyType = PrivateKey::getType(curve); + auto node = getMasterNode(wallet, curve); + for (auto& index : derivationPath.indices) { + switch (privateKeyType) { + case TWPrivateKeyTypeCardano: + hdnode_private_ckd_cardano(&node, index.derivationIndex()); + break; + case TWPrivateKeyTypeDefault: + default: + hdnode_private_ckd(&node, index.derivationIndex()); + break; + } + } + return node; } -PrivateKey HDWallet::getMasterKey(TWCurve curve) const { +template +PrivateKey HDWallet::getMasterKey(TWCurve curve) const { auto node = getMasterNode(*this, curve); auto data = Data(node.private_key, node.private_key + PrivateKey::_size); return PrivateKey(data); } -PrivateKey HDWallet::getMasterKeyExtension(TWCurve curve) const { +template +PrivateKey HDWallet::getMasterKeyExtension(TWCurve curve) const { auto node = getMasterNode(*this, curve); auto data = Data(node.private_key_extension, node.private_key_extension + PrivateKey::_size); return PrivateKey(data); } -PrivateKey HDWallet::getKey(TWCoinType coin, TWDerivation derivation) const { - const auto path = TW::derivationPath(coin, derivation); - return getKey(coin, path); -} - -DerivationPath HDWallet::cardanoStakingDerivationPath(const DerivationPath& path) { +template +DerivationPath HDWallet::cardanoStakingDerivationPath(const DerivationPath& path) { DerivationPath stakingPath = path; stakingPath.indices[3].value = 2; stakingPath.indices[4].value = 0; return stakingPath; } -PrivateKey HDWallet::getKey(TWCoinType coin, const DerivationPath& derivationPath) const { - const auto curve = TWCoinTypeCurve(coin); - return getKeyByCurve(curve, derivationPath); -} - -PrivateKey HDWallet::getKeyByCurve(TWCurve curve, const DerivationPath& derivationPath) const { +template +PrivateKey HDWallet::getKeyByCurve(TWCurve curve, const DerivationPath& derivationPath) const { const auto privateKeyType = PrivateKey::getType(curve); - auto node = getNode(*this, curve, derivationPath); + auto node = getNode(*this, curve, derivationPath); switch (privateKeyType) { case TWPrivateKeyTypeCardano: { if (derivationPath.indices.size() < 4 || derivationPath.indices[3].value > 1) { @@ -149,32 +192,50 @@ PrivateKey HDWallet::getKeyByCurve(TWCurve curve, const DerivationPath& derivati TW::memzero(&node); return PrivateKey(pkData, extData, chainCode, pkData2, extData2, chainCode2); } - case TWPrivateKeyTypeDefault: default: // default path auto data = Data(node.private_key, node.private_key + PrivateKey::_size); TW::memzero(&node); + if (curve == TWCurveStarkex) { + return ImmutableX::getPrivateKeyFromEthPrivKey(PrivateKey(data)); + } return PrivateKey(data); } } -std::string HDWallet::getRootKey(TWCoinType coin, TWHDVersion version) const { +template +PrivateKey HDWallet::getKey(TWCoinType coin, const DerivationPath& derivationPath) const { const auto curve = TWCoinTypeCurve(coin); - auto node = getMasterNode(*this, curve); - return serialize(&node, 0, version, false, base58Hasher(coin)); + return getKeyByCurve(curve, derivationPath); } -std::string HDWallet::deriveAddress(TWCoinType coin) const { - return deriveAddress(coin, TWDerivationDefault); +template +PrivateKey HDWallet::getKey(TWCoinType coin, TWDerivation derivation) const { + const auto path = TW::derivationPath(coin, derivation); + return getKey(coin, path); } -std::string HDWallet::deriveAddress(TWCoinType coin, TWDerivation derivation) const { +template +std::string HDWallet::getRootKey(TWCoinType coin, TWHDVersion version) const { + const auto curve = TWCoinTypeCurve(coin); + auto node = getMasterNode(*this, curve); + return serialize(&node, 0, version, false, base58Hasher(coin)); +} + +template +std::string HDWallet::deriveAddress(TWCoinType coin, TWDerivation derivation) const { const auto derivationPath = TW::derivationPath(coin, derivation); return TW::deriveAddress(coin, getKey(coin, derivationPath), derivation); } -std::string HDWallet::getExtendedPrivateKeyAccount(TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version, uint32_t account) const { +template +std::string HDWallet::deriveAddress(TWCoinType coin) const { + return deriveAddress(coin, TWDerivationDefault); +} + +template +std::string HDWallet::getExtendedPrivateKeyAccount(TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version, uint32_t account) const { if (version == TWHDVersionNone) { return ""; } @@ -188,7 +249,8 @@ std::string HDWallet::getExtendedPrivateKeyAccount(TWPurpose purpose, TWCoinType return serialize(&node, fingerprintValue, version, false, base58Hasher(coin)); } -std::string HDWallet::getExtendedPublicKeyAccount(TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version, uint32_t account) const { +template +std::string HDWallet::getExtendedPublicKeyAccount(TWPurpose purpose, TWCoinType coin, TWDerivation derivation, TWHDVersion version, uint32_t account) const { if (version == TWHDVersionNone) { return ""; } @@ -203,7 +265,8 @@ std::string HDWallet::getExtendedPublicKeyAccount(TWPurpose purpose, TWCoinType return serialize(&node, fingerprintValue, version, true, base58Hasher(coin)); } -std::optional HDWallet::getPublicKeyFromExtended(const std::string& extended, TWCoinType coin, const DerivationPath& path) { +template +std::optional HDWallet::getPublicKeyFromExtended(const std::string& extended, TWCoinType coin, const DerivationPath& path) { const auto curve = TW::curve(coin); const auto hasher = TW::base58Hasher(coin); @@ -239,7 +302,8 @@ std::optional HDWallet::getPublicKeyFromExtended(const std::string& e return {}; } -std::optional HDWallet::getPrivateKeyFromExtended(const std::string& extended, TWCoinType coin, const DerivationPath& path) { +template +std::optional HDWallet::getPrivateKeyFromExtended(const std::string& extended, TWCoinType coin, const DerivationPath& path) { const auto curve = TW::curve(coin); const auto hasher = TW::base58Hasher(coin); @@ -253,6 +317,13 @@ std::optional HDWallet::getPrivateKeyFromExtended(const std::string& return PrivateKey(Data(node.private_key, node.private_key + 32)); } +template +PrivateKey HDWallet::bip32DeriveRawSeed(TWCoinType coin, const Data& seed, const DerivationPath& path) { + const auto curve = TWCoinTypeCurve(coin); + auto wallet = HDWallet(seed); + return wallet.getKeyByCurve(curve, path); +} + namespace { uint32_t fingerprint(HDNode* node, Hash::Hasher hasher) { @@ -311,47 +382,9 @@ bool deserialize(const std::string& extended, TWCurve curve, Hash::Hasher hasher return true; } -HDNode getNode(const HDWallet& wallet, TWCurve curve, const DerivationPath& derivationPath) { - const auto privateKeyType = PrivateKey::getType(curve); - auto node = getMasterNode(wallet, curve); - for (auto& index : derivationPath.indices) { - switch (privateKeyType) { - case TWPrivateKeyTypeCardano: - hdnode_private_ckd_cardano(&node, index.derivationIndex()); - break; - case TWPrivateKeyTypeDefault: - default: - hdnode_private_ckd(&node, index.derivationIndex()); - break; - } - } - return node; -} - -HDNode getMasterNode(const HDWallet& wallet, TWCurve curve) { - const auto privateKeyType = PrivateKey::getType(curve); - HDNode node; - switch (privateKeyType) { - case TWPrivateKeyTypeCardano: { - // Derives the root Cardano HDNode from a passphrase and the entropy encoded in - // a BIP-0039 mnemonic using the Icarus derivation (V2) scheme - const auto entropy = wallet.getEntropy(); - uint8_t secret[CARDANO_SECRET_LENGTH]; - secret_from_entropy_cardano_icarus((const uint8_t*)"", 0, entropy.data(), int(entropy.size()), secret, nullptr); - hdnode_from_secret_cardano(secret, &node); - TW::memzero(secret, CARDANO_SECRET_LENGTH); - break; - } - case TWPrivateKeyTypeDefault: - default: - hdnode_from_seed(wallet.getSeed().data(), HDWallet::seedSize, curveName(curve), &node); - break; - } - return node; -} - const char* curveName(TWCurve curve) { switch (curve) { + case TWCurveStarkex: case TWCurveSECP256k1: return SECP256K1_NAME; case TWCurveED25519: @@ -371,3 +404,8 @@ const char* curveName(TWCurve curve) { } } // namespace + +namespace TW { +template class HDWallet<32>; +template class HDWallet<64>; +} // namespace TW diff --git a/src/HDWallet.h b/src/HDWallet.h index 0579591c82e..38c928e451b 100644 --- a/src/HDWallet.h +++ b/src/HDWallet.h @@ -24,9 +24,10 @@ namespace TW { +template class HDWallet { public: - static constexpr size_t seedSize = 64; + static constexpr size_t mSeedSize = seedSize; static constexpr size_t maxMnemomincSize = 240; static constexpr size_t maxExtendedKeySize = 128; @@ -43,13 +44,16 @@ class HDWallet { /// Entropy is the binary 1-to-1 representation of the mnemonic (11 bits from each word) TW::Data entropy; - public: +public: const std::array& getSeed() const { return seed; } const std::string& getMnemonic() const { return mnemonic; } const std::string& getPassphrase() const { return passphrase; } const TW::Data& getEntropy() const { return entropy; } public: + /// Initializes an HDWallet from given seed. + HDWallet(const Data& seed); + /// Initializes a new random HDWallet with the provided strength in bits. /// Throws on invalid strength. HDWallet(int strength, const std::string& passphrase); @@ -125,6 +129,13 @@ class HDWallet { /// Computes the private key from an extended private key representation. static std::optional getPrivateKeyFromExtended(const std::string& extended, TWCoinType coin, const DerivationPath& path); + /// Derive the given seed for the given coin, with the given Derivation path + /// \param coin Coin to be used in order to retrieve the curve type + /// \param seed Custom seed to be used for the derivation, can be a mnemonic seed as well as an ethereum signature seed + /// \param path The derivation path to use + /// \return The computed private key + static PrivateKey bip32DeriveRawSeed(TWCoinType coin, const Data& seed, const DerivationPath& path); + private: void updateSeedAndEntropy(bool check = true); @@ -136,5 +147,5 @@ class HDWallet { /// Wrapper for C interface. struct TWHDWallet { - TW::HDWallet impl; + TW::HDWallet<> impl; }; diff --git a/src/HexCoding.h b/src/HexCoding.h index 6a12f0e2456..8cf121ae3e0 100644 --- a/src/HexCoding.h +++ b/src/HexCoding.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -23,8 +24,7 @@ template inline std::string hex(const Iter begin, const Iter end) { static constexpr std::array hexmap = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; std::string result; result.reserve((end - begin) * 2); @@ -94,4 +94,51 @@ inline Data parse_hex(const std::string& string, bool padLeft = false) { return parse_hex(string.begin(), string.end()); } +inline const char* hex_char_to_bin(char c) { + switch (toupper(c)) { + case '0': + return "0000"; + case '1': + return "0001"; + case '2': + return "0010"; + case '3': + return "0011"; + case '4': + return "0100"; + case '5': + return "0101"; + case '6': + return "0110"; + case '7': + return "0111"; + case '8': + return "1000"; + case '9': + return "1001"; + case 'A': + return "1010"; + case 'B': + return "1011"; + case 'C': + return "1100"; + case 'D': + return "1101"; + case 'E': + return "1110"; + case 'F': + return "1111"; + default: + return ""; + } +} + +inline std::string hex_str_to_bin_str(const std::string& hex) { + std::stringstream ss; + for (auto&& c: hex) { + ss << hex_char_to_bin(c); + } + return ss.str(); +} + } // namespace TW diff --git a/src/ImmutableX/Constants.h b/src/ImmutableX/Constants.h new file mode 100644 index 00000000000..f70a3565475 --- /dev/null +++ b/src/ImmutableX/Constants.h @@ -0,0 +1,24 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "uint256.h" + +namespace TW::ImmutableX { + +namespace internal { +inline constexpr const char* gLayer = "starkex"; +inline constexpr const char* gApplication = "immutablex"; +inline constexpr const char* gIndex = "1"; +inline const int256_t gStarkCurveA(1); +inline const int256_t gStarkCurveB("3141592653589793238462643383279502884197169399375105820974944592307816406665"); +inline const int256_t gStarkCurveN("3618502788666131213697322783095070105526743751716087489154079457884512865583"); +inline const int256_t gStarkCurveP("3618502788666131213697322783095070105623107215331596699973092056135872020481"); +inline const int256_t gStarkDeriveBias("112173586448650067624617006275947173271329056303198712163776463194419898833073"); +} // namespace internal + +} // namespace TW::ImmutableX diff --git a/src/ImmutableX/StarkKey.cpp b/src/ImmutableX/StarkKey.cpp new file mode 100644 index 00000000000..b2bd205f735 --- /dev/null +++ b/src/ImmutableX/StarkKey.cpp @@ -0,0 +1,83 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace TW::ImmutableX { + +uint256_t hashKeyWithIndex(const Data& seed, std::size_t index) { + auto data = seed; + data.push_back(static_cast(index)); + auto out = Hash::sha256(data); + return load(out); +} + +std::string grindKey(const Data& seed) { + std::size_t index{0}; + int256_t key = hashKeyWithIndex(seed, index); + while (key >= internal::gStarkDeriveBias) { + key = hashKeyWithIndex(store(uint256_t(key)), index); + index += 1; + } + auto finalKey = key % internal::gStarkCurveN; + std::stringstream ss; + ss << std::hex << finalKey; + return ss.str(); +} + +PrivateKey getPrivateKeyFromSeed(const Data& seed, const DerivationPath& path) { + auto key = HDWallet<32>::bip32DeriveRawSeed(TWCoinTypeEthereum, seed, path); + auto data = parse_hex(grindKey(key.bytes), true); + return PrivateKey(data); +} + +PrivateKey getPrivateKeyFromEthPrivKey(const PrivateKey& ethPrivKey) { + return PrivateKey(parse_hex(ImmutableX::grindKey(ethPrivKey.bytes), true)); +} + +PrivateKey getPrivateKeyFromRawSignature(const Data& signature, const DerivationPath& derivationPath) { + using namespace internal; + //auto data = parse_hex(signature); + auto ethSignature = Ethereum::Signer::signatureDataToStructSimple(signature); + auto seed = store(ethSignature.s); + return getPrivateKeyFromSeed(seed, derivationPath); +} + +Data getPublicKeyFromPrivateKey(const Data& privateKey) { + auto pubKey = starknet_pubkey_from_private(hex(privateKey).c_str()); + std::string pubKeyStr = pubKey; + free_string(pubKey); + return parse_hex(pubKeyStr, true); +} + +Data sign(const Data& privateKey, const Data& digest) { + auto privKeyStr = hex(privateKey); + auto hexDigest = hex(digest); + auto resultSignature = starknet_sign(privKeyStr.c_str(), hexDigest.c_str()); + auto toReturn = parse_hex(resultSignature); + free_string(resultSignature); + return toReturn; +} + +bool verify(const Data& pubKey, const Data& signature, const Data& digest) { + if (signature.size() != 64) { + return false; + } + auto r = hex(subData(signature, 0, 32)); + auto s = hex(subData(signature, 32)); + auto pubKeyStr = hex(pubKey); + auto digestStr = hex(digest); + return starknet_verify(pubKeyStr.c_str(), digestStr.c_str(), r.c_str(), s.c_str()); +} + +} // namespace TW::ImmutableX diff --git a/src/ImmutableX/StarkKey.h b/src/ImmutableX/StarkKey.h new file mode 100644 index 00000000000..2bbeab1d7d2 --- /dev/null +++ b/src/ImmutableX/StarkKey.h @@ -0,0 +1,32 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "uint256.h" +#include +#include +#include + +namespace TW::ImmutableX { + +uint256_t hashKeyWithIndex(const Data& seed, std::size_t index); + +std::string grindKey(const Data& seed); + +PrivateKey getPrivateKeyFromSeed(const std::string& seed, const DerivationPath& path); + +PrivateKey getPrivateKeyFromEthPrivKey(const PrivateKey& ethPrivKey); + +PrivateKey getPrivateKeyFromRawSignature(const Data& signature, const DerivationPath& derivationPath); + +Data getPublicKeyFromPrivateKey(const Data& privateKey); + +Data sign(const Data &privateKey, const Data& digest); + +bool verify(const Data &pubKey, const Data& signature, const Data& digest); + +} // namespace TW::ImmutableX diff --git a/src/Keystore/StoredKey.cpp b/src/Keystore/StoredKey.cpp index 9b761186ce4..bc6d9597981 100644 --- a/src/Keystore/StoredKey.cpp +++ b/src/Keystore/StoredKey.cpp @@ -36,7 +36,7 @@ StoredKey StoredKey::createWithMnemonic(const std::string& name, const Data& pas } StoredKey StoredKey::createWithMnemonicRandom(const std::string& name, const Data& password, TWStoredKeyEncryptionLevel encryptionLevel, TWStoredKeyEncryption encryption) { - const auto wallet = TW::HDWallet(128, ""); + const auto wallet = TW::HDWallet<>(128, ""); const auto& mnemonic = wallet.getMnemonic(); assert(Mnemonic::isValid(mnemonic)); Data mnemonicData = TW::Data(mnemonic.begin(), mnemonic.end()); @@ -77,13 +77,13 @@ StoredKey::StoredKey(StoredKeyType type, std::string name, const Data& password, id = boost::lexical_cast(gen()); } -const HDWallet StoredKey::wallet(const Data& password) const { +const HDWallet<> StoredKey::wallet(const Data& password) const { if (type != StoredKeyType::mnemonicPhrase) { throw std::invalid_argument("Invalid account requested."); } const auto data = payload.decrypt(password); const auto mnemonic = std::string(reinterpret_cast(data.data()), data.size()); - return HDWallet(mnemonic, ""); + return HDWallet<>(mnemonic, ""); } std::vector StoredKey::getAccounts(TWCoinType coin) const { @@ -96,7 +96,7 @@ std::vector StoredKey::getAccounts(TWCoinType coin) const { return result; } -std::optional StoredKey::getDefaultAccount(TWCoinType coin, const HDWallet* wallet) const { +std::optional StoredKey::getDefaultAccount(TWCoinType coin, const HDWallet<>* wallet) const { // there are multiple, try to look for default if (wallet != nullptr) { const auto address = wallet->deriveAddress(coin); @@ -115,7 +115,7 @@ std::optional StoredKey::getDefaultAccount(TWCoinType coin, const HDWal return std::nullopt; } -std::optional StoredKey::getDefaultAccountOrAny(TWCoinType coin, const HDWallet* wallet) const { +std::optional StoredKey::getDefaultAccountOrAny(TWCoinType coin, const HDWallet<>* wallet) const { const auto defaultAccount = getDefaultAccount(coin, wallet); if (defaultAccount.has_value()) { return defaultAccount; @@ -137,13 +137,13 @@ std::optional StoredKey::getAccount(TWCoinType coin, const std::string& return std::nullopt; } -std::optional StoredKey::getAccount(TWCoinType coin, TWDerivation derivation, const HDWallet& wallet) const { +std::optional StoredKey::getAccount(TWCoinType coin, TWDerivation derivation, const HDWallet<>& wallet) const { // obtain address const auto address = wallet.deriveAddress(coin, derivation); return getAccount(coin, address); } -Account StoredKey::fillAddressIfMissing(Account& account, const HDWallet* wallet) const { +Account StoredKey::fillAddressIfMissing(Account& account, const HDWallet<>* wallet) const { if (account.address.empty() && wallet != nullptr) { account.address = wallet->deriveAddress(account.coin, account.derivation); } @@ -155,7 +155,7 @@ Account StoredKey::fillAddressIfMissing(Account& account, const HDWallet* wallet return account; } -std::optional StoredKey::account(TWCoinType coin, const HDWallet* wallet) { +std::optional StoredKey::account(TWCoinType coin, const HDWallet<>* wallet) { const auto account = getDefaultAccountOrAny(coin, wallet); if (account.has_value()) { Account accountLval = account.value(); @@ -177,7 +177,7 @@ std::optional StoredKey::account(TWCoinType coin, const HDWallet* return accounts.back(); } -Account StoredKey::account(TWCoinType coin, TWDerivation derivation, const HDWallet& wallet) { +Account StoredKey::account(TWCoinType coin, TWDerivation derivation, const HDWallet<>& wallet) { const auto coinAccount = getAccount(coin, derivation, wallet); if (coinAccount.has_value()) { Account accountLval = coinAccount.value(); @@ -199,7 +199,7 @@ std::optional StoredKey::account(TWCoinType coin) const { return getDefaultAccountOrAny(coin, nullptr); } -std::optional StoredKey::account(TWCoinType coin, TWDerivation derivation, const HDWallet& wallet) const { +std::optional StoredKey::account(TWCoinType coin, TWDerivation derivation, const HDWallet<>& wallet) const { const auto account = getAccount(coin, derivation, wallet); if (account.has_value()) { Account accountLval = account.value(); diff --git a/src/Keystore/StoredKey.h b/src/Keystore/StoredKey.h index 58a5dca3f77..7ff5e071276 100644 --- a/src/Keystore/StoredKey.h +++ b/src/Keystore/StoredKey.h @@ -70,25 +70,25 @@ class StoredKey { /// Returns the HDWallet for this key. /// /// @throws std::invalid_argument if this key is of a type other than `mnemonicPhrase`. - const HDWallet wallet(const Data& password) const; + const HDWallet<> wallet(const Data& password) const; /// Returns all the accounts for a specific coin: 0, 1, or more. std::vector getAccounts(TWCoinType coin) const; /// If found, returns the account for a specific coin. In case of muliple accounts, the default derivation is returned, or the first one is returned. /// If none exists, and wallet is not null, an account is created (with default derivation). - std::optional account(TWCoinType coin, const HDWallet* wallet); + std::optional account(TWCoinType coin, const HDWallet<>* wallet); /// If found, returns the account for a specific coin and derivation. In case of muliple accounts, the first one is returned. /// If none exists, an account is created. - Account account(TWCoinType coin, TWDerivation derivation, const HDWallet& wallet); + Account account(TWCoinType coin, TWDerivation derivation, const HDWallet<>& wallet); /// Returns the account for a specific coin if it exists. /// In case of muliple accounts, the default derivation is returned, or the first one is returned. std::optional account(TWCoinType coin) const; /// Returns the account for a specific coin and derivation, if it exists. - std::optional account(TWCoinType coin, TWDerivation derivation, const HDWallet& wallet) const; + std::optional account(TWCoinType coin, TWDerivation derivation, const HDWallet<>& wallet) const; /// Add an account with aribitrary address/derivation path. Discouraged, use account() versions. /// Address must be unique (for a coin). @@ -157,20 +157,20 @@ class StoredKey { /// Find default account for coin, if exists. If multiple exist, default is returned. /// Optional wallet is needed to derive default address - std::optional getDefaultAccount(TWCoinType coin, const HDWallet* wallet) const; + std::optional getDefaultAccount(TWCoinType coin, const HDWallet<>* wallet) const; /// Find account for coin, if exists. If multiple exist, default is returned, or any. /// Optional wallet is needed to derive default address - std::optional getDefaultAccountOrAny(TWCoinType coin, const HDWallet* wallet) const; + std::optional getDefaultAccountOrAny(TWCoinType coin, const HDWallet<>* wallet) const; /// Find account by coin+address (should be one, if multiple, first is returned) std::optional getAccount(TWCoinType coin, const std::string& address) const; /// Find account by coin+derivation (should be one, if multiple, first is returned) - std::optional getAccount(TWCoinType coin, TWDerivation derivation, const HDWallet& wallet) const; + std::optional getAccount(TWCoinType coin, TWDerivation derivation, const HDWallet<>& wallet) const; /// Re-derive account address if missing - Account fillAddressIfMissing(Account& account, const HDWallet* wallet) const; + Account fillAddressIfMissing(Account& account, const HDWallet<>* wallet) const; }; } // namespace TW::Keystore diff --git a/src/PrivateKey.cpp b/src/PrivateKey.cpp index 898953100ed..b11cd18fadb 100644 --- a/src/PrivateKey.cpp +++ b/src/PrivateKey.cpp @@ -6,6 +6,7 @@ #include "PrivateKey.h" +#include "HexCoding.h" #include "PublicKey.h" #include @@ -18,6 +19,7 @@ #include #include #include +#include #include @@ -152,12 +154,21 @@ PublicKey PrivateKey::getPublicKey(TWPublicKeyType type) const { append(result, secondChainCode()); } break; - case TWPublicKeyTypeCURVE25519: + case TWPublicKeyTypeCURVE25519: { result.resize(PublicKey::ed25519Size); PublicKey ed25519PublicKey = getPublicKey(TWPublicKeyTypeED25519); ed25519_pk_to_curve25519(result.data(), ed25519PublicKey.bytes.data()); break; } + + case TWPublicKeyTypeStarkex: { + result = ImmutableX::getPublicKeyFromPrivateKey(this->bytes); + if (result.size() == PublicKey::starkexSize - 1) { + result.insert(result.begin(), 0); + } + break; + } + } return PublicKey(result, type); } @@ -223,6 +234,11 @@ Data PrivateKey::sign(const Data& digest, TWCurve curve) const { result.resize(65); success = ecdsa_sign_digest_checked(&nist256p1, key().data(), digest.data(), digest.size(), result.data(), result.data() + 64, nullptr) == 0; } break; + case TWCurveStarkex: { + result = ImmutableX::sign(this->bytes, digest); + success = true; + break; + } case TWCurveNone: default: break; diff --git a/src/PublicKey.cpp b/src/PublicKey.cpp index 0fcd53c3a3b..c002c4d1320 100644 --- a/src/PublicKey.cpp +++ b/src/PublicKey.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -41,6 +42,8 @@ bool PublicKey::isValid(const Data& data, enum TWPublicKeyType type) { case TWPublicKeyTypeSECP256k1Extended: case TWPublicKeyTypeNIST256p1Extended: return size == secp256k1ExtendedSize && data[0] == 0x04; + case TWPublicKeyTypeStarkex: + return size == starkexSize; default: return false; } @@ -55,6 +58,7 @@ PublicKey::PublicKey(const Data& data, enum TWPublicKeyType type) throw std::invalid_argument("Invalid public key data"); } switch (type) { + case TWPublicKeyTypeStarkex: case TWPublicKeyTypeSECP256k1: case TWPublicKeyTypeNIST256p1: case TWPublicKeyTypeSECP256k1Extended: @@ -158,6 +162,8 @@ bool PublicKey::verify(const Data& signature, const Data& message) const { verifyBuffer[63] &= 127; return ed25519_sign_open(message.data(), message.size(), ed25519PublicKey.data(), verifyBuffer.data()) == 0; } + case TWPublicKeyTypeStarkex: + return ImmutableX::verify(this->bytes, signature, message); default: throw std::logic_error("Not yet implemented"); } diff --git a/src/PublicKey.h b/src/PublicKey.h index 111f0fdf306..d5698c6e89d 100644 --- a/src/PublicKey.h +++ b/src/PublicKey.h @@ -24,6 +24,9 @@ class PublicKey { /// The number of bytes in an ed25519 public key. static const size_t ed25519Size = 32; + /// The number of bytes in an starkex public key. + static const size_t starkexSize = 32; + /// The number of bytes in a Cardano public key (two ed25519 public key + chain code). static const size_t cardanoKeySize = 2 * 2 * 32; diff --git a/src/StarkEx/MessageSigner.cpp b/src/StarkEx/MessageSigner.cpp new file mode 100644 index 00000000000..b6c5b96cb5c --- /dev/null +++ b/src/StarkEx/MessageSigner.cpp @@ -0,0 +1,23 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include + +namespace TW::StarkEx { + +std::string MessageSigner::signMessage(const TW::PrivateKey& privateKey, const std::string& message) { + auto digest = parse_hex(message, true); + return hex(privateKey.sign(digest, TWCurveStarkex)); +} + +bool MessageSigner::verifyMessage(const PublicKey& publicKey, const std::string& message, const std::string& signature) noexcept { + auto starkSignature = parse_hex(signature, true); + auto digest = parse_hex(message, true); + return publicKey.verify(starkSignature, digest); +} + +} // namespace TW::StarkEx diff --git a/src/StarkEx/MessageSigner.h b/src/StarkEx/MessageSigner.h new file mode 100644 index 00000000000..1face6ccc08 --- /dev/null +++ b/src/StarkEx/MessageSigner.h @@ -0,0 +1,28 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include + +namespace TW::StarkEx { +class MessageSigner { +public: + /// Sign a message following StarkEx Curve + /// \param privateKey the private key to sign with + /// \param message hex message to sign + /// \return hex signed message + static std::string signMessage(const PrivateKey& privateKey, const std::string& message);; + + /// Verify a message following EIP-191 + /// \param publicKey publickey to verify the signed message + /// \param message message to be verified as a string + /// \param signature signature to verify the message against + /// \return true if the message match the signature, false otherwise + static bool verifyMessage(const PublicKey& publicKey, const std::string& message, const std::string& signature) noexcept;; +}; +} diff --git a/src/XRP/Transaction.cpp b/src/XRP/Transaction.cpp index 25b6625aaef..2358fb723a3 100644 --- a/src/XRP/Transaction.cpp +++ b/src/XRP/Transaction.cpp @@ -9,6 +9,7 @@ #include "../BinaryCoding.h" #include +#include #include #include @@ -168,8 +169,8 @@ Data Transaction::serializeCurrencyAmount(const CurrencyAmount& currency_amount) return Data(); } - int64_t min_mantissa = (uint64_t)pow(10, 15); - int64_t max_mantissa = (uint64_t)pow(10, 16) - 1; + int64_t min_mantissa = (uint64_t)std::pow(10, 15); + int64_t max_mantissa = (uint64_t)std::pow(10, 16) - 1; int32_t min_exp = -96; int32_t max_exp = 80; diff --git a/src/interface/TWEthereumEip2645.cpp b/src/interface/TWEthereumEip2645.cpp new file mode 100644 index 00000000000..21a9082573a --- /dev/null +++ b/src/interface/TWEthereumEip2645.cpp @@ -0,0 +1,18 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include "Ethereum/EIP2645.h" + +#include + +TWString* TWEthereumEip2645GetPath(TWString* ethAddress, TWString* layer, TWString* application, TWString* index) { + const auto& ethAddressStr = *reinterpret_cast(ethAddress); + const auto& layerStr = *reinterpret_cast(layer); + const auto& applicationStr = *reinterpret_cast(application); + const auto& indexStr = *reinterpret_cast(index); + return new std::string(TW::Ethereum::accountPathFromAddress(ethAddressStr, layerStr, applicationStr, indexStr)); +} diff --git a/src/interface/TWEthereumMessageSigner.cpp b/src/interface/TWEthereumMessageSigner.cpp new file mode 100644 index 00000000000..19e1d6e3705 --- /dev/null +++ b/src/interface/TWEthereumMessageSigner.cpp @@ -0,0 +1,22 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include + +#include "Ethereum/EIP191.h" + +TWString* _Nonnull TWEthereumMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message) { + try { + const auto signature = TW::Ethereum::MessageSigner::signMessage(privateKey->impl, TWStringUTF8Bytes(message)); + return TWStringCreateWithUTF8Bytes(signature.c_str()); + } catch (...) { + return TWStringCreateWithUTF8Bytes(""); + } +} + +bool TWEthereumMessageSignerVerifyMessage(const struct TWPublicKey* _Nonnull publicKey, TWString* _Nonnull message, TWString* _Nonnull signature) { + return TW::Ethereum::MessageSigner::verifyMessage(publicKey->impl, TWStringUTF8Bytes(message), TWStringUTF8Bytes(signature)); +} diff --git a/src/interface/TWHDWallet.cpp b/src/interface/TWHDWallet.cpp index 630b0613110..3be263eb5ee 100644 --- a/src/interface/TWHDWallet.cpp +++ b/src/interface/TWHDWallet.cpp @@ -51,7 +51,7 @@ void TWHDWalletDelete(struct TWHDWallet *wallet) { } TWData *_Nonnull TWHDWalletSeed(struct TWHDWallet *_Nonnull wallet) { - return TWDataCreateWithBytes(wallet->impl.getSeed().data(), HDWallet::seedSize); + return TWDataCreateWithBytes(wallet->impl.getSeed().data(), HDWallet<>::mSeedSize); } TWString *_Nonnull TWHDWalletMnemonic(struct TWHDWallet *_Nonnull wallet){ @@ -129,7 +129,7 @@ TWString *_Nonnull TWHDWalletGetExtendedPublicKeyDerivation(struct TWHDWallet *w TWPublicKey *TWHDWalletGetPublicKeyFromExtended(TWString *_Nonnull extended, enum TWCoinType coin, TWString *_Nonnull derivationPath) { const auto derivationPathObject = DerivationPath(*reinterpret_cast(derivationPath)); - auto publicKey = HDWallet::getPublicKeyFromExtended(*reinterpret_cast(extended), coin, derivationPathObject); + auto publicKey = HDWallet<>::getPublicKeyFromExtended(*reinterpret_cast(extended), coin, derivationPathObject); if (!publicKey) { return nullptr; } diff --git a/src/interface/TWStarkExMessageSigner.cpp b/src/interface/TWStarkExMessageSigner.cpp new file mode 100644 index 00000000000..04502acf234 --- /dev/null +++ b/src/interface/TWStarkExMessageSigner.cpp @@ -0,0 +1,22 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include + +#include "StarkEx/MessageSigner.h" + +TWString* _Nonnull TWStarkExMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message) { + try { + const auto signature = TW::StarkEx::MessageSigner::signMessage(privateKey->impl, TWStringUTF8Bytes(message)); + return TWStringCreateWithUTF8Bytes(signature.c_str()); + } catch (...) { + return TWStringCreateWithUTF8Bytes(""); + } +} + +bool TWStarkExMessageSignerVerifyMessage(const struct TWPublicKey* _Nonnull publicKey, TWString* _Nonnull message, TWString* _Nonnull signature) { + return TW::StarkEx::MessageSigner::verifyMessage(publicKey->impl, TWStringUTF8Bytes(message), TWStringUTF8Bytes(signature)); +} diff --git a/src/interface/TWStarkWare.cpp b/src/interface/TWStarkWare.cpp new file mode 100644 index 00000000000..ede9644fa04 --- /dev/null +++ b/src/interface/TWStarkWare.cpp @@ -0,0 +1,17 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include +#include +#include +#include + +struct TWPrivateKey* TWStarkWareGetStarkKeyFromSignature(const struct TWDerivationPath* derivationPath, TWString* signature) { + using namespace TW; + const auto& ethSignatureStr = *reinterpret_cast(signature); + return new TWPrivateKey{ ImmutableX::getPrivateKeyFromRawSignature(parse_hex(ethSignatureStr), derivationPath->impl)}; +} diff --git a/swift/Tests/Blockchains/EthereumTests.swift b/swift/Tests/Blockchains/EthereumTests.swift index c3091e428b6..e53e1cdebb1 100644 --- a/swift/Tests/Blockchains/EthereumTests.swift +++ b/swift/Tests/Blockchains/EthereumTests.swift @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -274,4 +274,13 @@ class EthereumTests: XCTestCase { XCTAssertEqual(ethAddress, "0xa4531dE99E22B2166d340E7221669DF565c52024") XCTAssertEqual(btcAddress, "bc1q97jc0jdgsyvvhxydxxd6np8sa920c39l3qpscf") } + + func testMessageAndVerifySigner() { + let privateKey = PrivateKey(data: Data(hexString: "3b0a61f46fdae924007146eacb6db6642de7a5603ad843ec58e10331d89d4b84")!)! + let msg = "Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3" + let signature = EthereumMessageSigner.signMessage(privateKey: privateKey, message: msg) + XCTAssertEqual(signature, "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01") + let pubKey = privateKey.getPublicKey(coinType: .ethereum) + XCTAssertTrue(EthereumMessageSigner.verifyMessage(pubKey: pubKey, message: msg, signature: signature)) + } } diff --git a/swift/Tests/Blockchains/StarkExTests.swift b/swift/Tests/Blockchains/StarkExTests.swift new file mode 100644 index 00000000000..88e868ab10c --- /dev/null +++ b/swift/Tests/Blockchains/StarkExTests.swift @@ -0,0 +1,19 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import XCTest +import WalletCore + +class StarkExTests: XCTestCase { + func testMessageAndVerifySigner() { + let privateKey = PrivateKey(data: Data(hexString: "04be51a04e718c202e4dca60c2b72958252024cfc1070c090dd0f170298249de")!)! + let msg = "463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf" + let signature = StarkExMessageSigner.signMessage(privateKey: privateKey, message: msg) + XCTAssertEqual(signature, "04cf5f21333dd189ada3c0f2a51430d733501a9b1d5e07905273c1938cfb261e05b6013d74adde403e8953743a338c8d414bb96bf69d2ca1a91a85ed2700a528") + let pubKey = privateKey.getPublicKeyByType(pubkeyType: .starkex) + XCTAssertTrue(StarkExMessageSigner.verifyMessage(pubKey: pubKey, message: msg, signature: signature)) + } +} diff --git a/swift/Tests/HDWalletTests.swift b/swift/Tests/HDWalletTests.swift index cc832c55a7e..6dccac4705f 100644 --- a/swift/Tests/HDWalletTests.swift +++ b/swift/Tests/HDWalletTests.swift @@ -12,6 +12,38 @@ extension HDWallet { } class HDWalletTests: XCTestCase { + + func testFromMnemonicImmutableXMainnetFromSignature() { + let wallet = HDWallet(mnemonic: "obscure opera favorite shuffle mail tip age debate dirt pact cement loyal", passphrase: "")! + let starkDerivationPath = EthereumEip2645.getPath(ethAddress: "0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37", layer: "starkex", application: "immutablex", index: "1") + XCTAssertEqual(starkDerivationPath, "m/2645'/579218131'/211006541'/2124474935'/1609799702'/1") + + // Retrieve eth private key + let ethPrivateKey = wallet.getKeyForCoin(coin: CoinType.ethereum) + XCTAssertEqual(ethPrivateKey.data.hexString, "03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d"); + + // StarkKey Derivation Path + let derivationPath = DerivationPath(string: starkDerivationPath)! + + // Retrieve Stark Private key part + let ethMsg = "Only sign this request if you’ve initiated an action with Immutable X." + let ethSignature = EthereumMessageSigner.signMessage(privateKey: ethPrivateKey, message: ethMsg) + XCTAssertEqual(ethSignature, "18b1be8b78807d3326e28bc286d7ee3d068dcd90b1949ce1d25c1f99825f26e70992c5eb7f44f76b202aceded00d74f771ed751f2fe538eec01e338164914fe001") + let starkPrivateKey = StarkWare.getStarkKeyFromSignature(derivationPath: derivationPath, signature: ethSignature) + XCTAssertEqual(starkPrivateKey.data.hexString, "04be51a04e718c202e4dca60c2b72958252024cfc1070c090dd0f170298249de") + let starkPublicKey = starkPrivateKey.getPublicKeyByType(pubkeyType: .starkex) + XCTAssertEqual(starkPublicKey.data.hexString, "00e5b9b11f8372610ef35d647a1dcaba1a4010716588d591189b27bf3c2d5095") + + // Account Register + let ethMsgToRegister = "Only sign this key linking request from Immutable X" + let ethSignatureToRegister = EthereumMessageSigner.signMessage(privateKey: ethPrivateKey, message: ethMsgToRegister) + XCTAssertEqual(ethSignatureToRegister, "646da4160f7fc9205e6f502fb7691a0bf63ecbb74bbb653465cd62388dd9f56325ab1e4a9aba99b1661e3e6251b42822855a71e60017b310b9f90e990a12e1dc01") + let starkMsg = "463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf" + let starkSignature = StarkExMessageSigner.signMessage(privateKey: starkPrivateKey, message: starkMsg) + XCTAssertEqual(starkSignature, "04cf5f21333dd189ada3c0f2a51430d733501a9b1d5e07905273c1938cfb261e05b6013d74adde403e8953743a338c8d414bb96bf69d2ca1a91a85ed2700a528") + XCTAssertTrue(StarkExMessageSigner.verifyMessage(pubKey: starkPublicKey, message: starkMsg, signature: starkSignature)) + } + func testCreateFromMnemonic() { let wallet = HDWallet.test diff --git a/swift/Tests/PrivateKeyTests.swift b/swift/Tests/PrivateKeyTests.swift index ae363969f17..bc9ae7e13ff 100644 --- a/swift/Tests/PrivateKeyTests.swift +++ b/swift/Tests/PrivateKeyTests.swift @@ -20,6 +20,22 @@ class PrivateKeyTests: XCTestCase { let privateKey = PrivateKey(data: Data(hexString: "0xdeadbeef")!) XCTAssertNil(privateKey) } + + func testStarkKeyCreation() { + let data = Data(hexString: "06cf0a8bf113352eb863157a45c5e5567abb34f8d32cddafd2c22aa803f4892c")! + XCTAssertTrue(PrivateKey.isValid(data: data, curve: .starkex)) + let privateKey = PrivateKey(data: data)! + let pubKey = privateKey.getPublicKeyByType(pubkeyType: .starkex) + XCTAssertEqual(pubKey.data.hexString, "02d2bbdc1adaf887b0027cdde2113cfd81c60493aa6dc15d7887ddf1a82bc831") + } + + func testStarkKeySigning() { + let data = Data(hexString: "0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79")! + let privateKey = PrivateKey(data: data)! + let digest = Data(hexString: "06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76")! + let signature = privateKey.sign(digest: digest, curve: .starkex)! + XCTAssertEqual(signature.hexString, "061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a") + } func testIsValidString() { let data = Data(hexString: "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5")! diff --git a/swift/Tests/PublicKeyTests.swift b/swift/Tests/PublicKeyTests.swift index b6844ea38c8..5819e3d3ed0 100644 --- a/swift/Tests/PublicKeyTests.swift +++ b/swift/Tests/PublicKeyTests.swift @@ -35,4 +35,14 @@ class PublicKeyTests: XCTestCase { XCTAssertTrue(result2) XCTAssertTrue(result3) } + + func testVerifyStarkey() { + let data = Data(hexString: "02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159")! + let publicKey = PublicKey(data: data, type: .starkex)! + let signature = Data(hexString: "061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a")! + let hash = Data(hexString: "06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76")! + XCTAssertTrue(publicKey.verify(signature: signature, message: hash)) + let invalidSignature = Data(hexString: "061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9b")! + XCTAssertFalse(publicKey.verify(signature: invalidSignature, message: hash)) + } } diff --git a/tests/chains/Ethereum/EIP191Tests.cpp b/tests/chains/Ethereum/EIP191Tests.cpp new file mode 100644 index 00000000000..38c937479d1 --- /dev/null +++ b/tests/chains/Ethereum/EIP191Tests.cpp @@ -0,0 +1,37 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include +#include +#include +#include +#include "TestUtilities.h" + +#include + +namespace TW::Ethereum { + TEST(EthereumEip191, signMessageAndVerify) { + PrivateKey ethKey(parse_hex("3b0a61f46fdae924007146eacb6db6642de7a5603ad843ec58e10331d89d4b84")); + auto msg = "Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3"; + auto signature = Ethereum::MessageSigner::signMessage(ethKey, msg); + ASSERT_EQ(signature, "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01"); + auto pubKey = ethKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended); + ASSERT_TRUE(Ethereum::MessageSigner::verifyMessage(pubKey, msg, signature)); + } + + TEST(TWEthereumMessageSigner, SignAndVerify) { + const auto privKeyData = "3b0a61f46fdae924007146eacb6db6642de7a5603ad843ec58e10331d89d4b84"; + const auto privateKey = WRAP(TWPrivateKey, TWPrivateKeyCreateWithData(DATA(privKeyData).get())); + const auto message = STRING("Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3"); + + const auto pubKey = TWPrivateKeyGetPublicKey(privateKey.get(), TWCoinTypeEthereum); + const auto signature = WRAPS(TWEthereumMessageSignerSignMessage(privateKey.get(), message.get())); + EXPECT_EQ(std::string(TWStringUTF8Bytes(signature.get())), "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01"); + EXPECT_TRUE(TWEthereumMessageSignerVerifyMessage(pubKey, message.get(), signature.get())); + delete pubKey; + } +} diff --git a/tests/chains/Ethereum/SignerTests.cpp b/tests/chains/Ethereum/SignerTests.cpp index 0899ff812c0..cbb9fb38e91 100644 --- a/tests/chains/Ethereum/SignerTests.cpp +++ b/tests/chains/Ethereum/SignerTests.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2021 Trust Wallet. +// Copyright © 2017-2022 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,6 +7,7 @@ #include "Ethereum/Address.h" #include "Ethereum/RLP.h" #include "Ethereum/Signer.h" +#include "Ethereum/EIP191.h" #include "Ethereum/Transaction.h" #include "HexCoding.h" @@ -16,7 +17,6 @@ namespace TW::Ethereum { using boost::multiprecision::uint256_t; - TEST(EthereumTransaction, encodeTransactionNonTyped) { const auto transaction = TransactionNonTyped::buildERC20Transfer( /* nonce: */ 0, diff --git a/tests/chains/ImmutableX/StarkKeyTests.cpp b/tests/chains/ImmutableX/StarkKeyTests.cpp new file mode 100644 index 00000000000..677c3ef5d34 --- /dev/null +++ b/tests/chains/ImmutableX/StarkKeyTests.cpp @@ -0,0 +1,108 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Ethereum/EIP2645.h" +#include "Ethereum/Signer.h" +#include "HexCoding.h" +#include "ImmutableX/Constants.h" +#include "ImmutableX/StarkKey.h" +#include + +namespace TW::ImmutableX::tests { + +TEST(ImmutableX, PathFromAddress) { + // https://github.com/immutable/imx-core-sdk-swift/blob/main/Tests/ImmutableXCoreTests/Crypto/Stark/StarkKeyTests.swift#L30 + auto res = Ethereum::accountPathFromAddress("0xa76e3eeb2f7143165618ab8feaabcd395b6fac7f", internal::gLayer, internal::gApplication, internal::gIndex); + ASSERT_EQ(res, "m/2645'/579218131'/211006541'/1534045311'/1431804530'/1"); +} + +TEST(ImmutableX, ExtraGrinding) { + using namespace internal; + std::string signature = "0x6d1550458c7a9a1257d73adbcf0fabc12f4497e970d9fa62dd88bf7d9e12719148c96225c1402d8707fd061b1aae2222bdf13571dfc82b3aa9974039f247f2b81b"; + std::string address = "0xa4864d977b944315389d1765ffa7e66F74ee8cd7"; + auto data = parse_hex(signature); + auto path = DerivationPath(Ethereum::accountPathFromAddress(address, gLayer, gApplication, gIndex)); + auto privKey = ImmutableX::getPrivateKeyFromRawSignature(parse_hex(signature), path); + auto pubKey = hexEncoded(getPublicKeyFromPrivateKey(privKey.bytes)); + ASSERT_EQ(pubKey, "0x035919acd61e97b3ecdc75ff8beed8d1803f7ea3cad2937926ae59cc3f8070d4"); +} + +TEST(ImmutableX, GrindKey) { + auto seed = parse_hex("86F3E7293141F20A8BAFF320E8EE4ACCB9D4A4BF2B4D295E8CEE784DB46E0519"); + auto res = grindKey(seed); + ASSERT_EQ(res, "5c8c8683596c732541a59e03007b2d30dbbbb873556fe65b5fb63c16688f941"); +} + +TEST(ImmutableX, GetPrivateKeySignature) { + std::string signature = "0x21fbf0696d5e0aa2ef41a2b4ffb623bcaf070461d61cf7251c74161f82fec3a4370854bc0a34b3ab487c1bc021cd318c734c51ae29374f2beb0e6f2dd49b4bf41c"; + auto data = parse_hex(signature); + auto ethSignature = Ethereum::Signer::signatureDataToStructSimple(data); + auto seed = store(ethSignature.r); + auto result = grindKey(seed); + ASSERT_EQ(result, "766f11e90cd7c7b43085b56da35c781f8c067ac0d578eabdceebc4886435bda"); +} + +TEST(ImmutableX, GetPrivateKeyFromSignature) { + using namespace internal; + std::string address = "0xa76e3eeb2f7143165618ab8feaabcd395b6fac7f"; + std::string signature = "0x5a263fad6f17f23e7c7ea833d058f3656d3fe464baf13f6f5ccba9a2466ba2ce4c4a250231bcac7beb165aec4c9b049b4ba40ad8dd287dc79b92b1ffcf20cdcf1b"; + auto path = DerivationPath(Ethereum::accountPathFromAddress(address, gLayer, gApplication, gIndex)); + auto privKey = ImmutableX::getPrivateKeyFromRawSignature(parse_hex(signature), path); + ASSERT_EQ(hex(privKey.bytes), "058ab7989d625b1a690400dcbe6e070627adedceff7bd196e58d4791026a8afe"); + ASSERT_TRUE(PrivateKey::isValid(privKey.bytes)); +} + +TEST(ImmutableX, GetPublicKeyFromPrivateKey) { + auto privKey = parse_hex("058ab7989d625b1a690400dcbe6e070627adedceff7bd196e58d4791026a8afe", true); + auto pubKey = hexEncoded(getPublicKeyFromPrivateKey(privKey)); + ASSERT_EQ(pubKey, "0x02a4c7332c55d6c1c510d24272d1db82878f2302f05b53bcc38695ed5f78fffd"); + + { + auto priv = PrivateKey(parse_hex("058ab7989d625b1a690400dcbe6e070627adedceff7bd196e58d4791026a8afe")); + auto pub = priv.getPublicKey(TWPublicKeyTypeStarkex); + ASSERT_EQ(hexEncoded(pub.bytes), "0x02a4c7332c55d6c1c510d24272d1db82878f2302f05b53bcc38695ed5f78fffd"); + } +} + +TEST(ImmutableX, SimpleSign) { + auto privKey = parse_hex("0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79"); + auto digest = parse_hex("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76"); + auto signature = hex(ImmutableX::sign(privKey, digest)); + auto expectedSignature = "061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a"; + ASSERT_EQ(signature.size(), 128ULL); + ASSERT_EQ(signature.substr(0, 64), "061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f"); + ASSERT_EQ(signature.substr(64, 64), "04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a"); + ASSERT_EQ(signature, expectedSignature); + + { + PrivateKey priv(privKey); + auto result = hex(priv.sign(digest, TWCurveStarkex)); + ASSERT_EQ(result, expectedSignature); + } +} + +TEST(ImmutableX, VerifySign) { + // valid + { + auto pubKeyData = parse_hex("02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159"); + auto hash = parse_hex("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76"); + auto signature = parse_hex("061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a"); + ASSERT_TRUE(verify(pubKeyData, signature, hash)); + auto pubKey = PublicKey(pubKeyData, TWPublicKeyTypeStarkex); + ASSERT_TRUE(pubKey.verify(signature, hash)); + } + // invalid + { + auto pubKeyData = parse_hex("02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159"); + auto hash = parse_hex("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76"); + auto signature = parse_hex("061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9b"); + ASSERT_FALSE(verify(pubKeyData, signature, hash)); + auto pubKey = PublicKey(pubKeyData, TWPublicKeyTypeStarkex); + ASSERT_FALSE(pubKey.verify(signature, hash)); + } +} + +} // namespace TW::ImmutableX::tests diff --git a/tests/chains/StarkEx/MessageSignerTests.cpp b/tests/chains/StarkEx/MessageSignerTests.cpp new file mode 100644 index 00000000000..1399ce24ca7 --- /dev/null +++ b/tests/chains/StarkEx/MessageSignerTests.cpp @@ -0,0 +1,37 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include +#include +#include +#include "TestUtilities.h" +#include + +namespace TW::StarkEx::tests { + +TEST(StarkExMessageSigner, SignAndVerify) { + PrivateKey starkPrivKey(parse_hex("04be51a04e718c202e4dca60c2b72958252024cfc1070c090dd0f170298249de", true)); + auto starkPubKey = starkPrivKey.getPublicKey(TWPublicKeyTypeStarkex); + auto starkMsg = "463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf"; + auto starkSignature = StarkEx::MessageSigner::signMessage(starkPrivKey, starkMsg); + ASSERT_EQ(starkSignature, "04cf5f21333dd189ada3c0f2a51430d733501a9b1d5e07905273c1938cfb261e05b6013d74adde403e8953743a338c8d414bb96bf69d2ca1a91a85ed2700a528"); + ASSERT_TRUE(StarkEx::MessageSigner::verifyMessage(starkPubKey, starkMsg, starkSignature)); +} + +TEST(TWStarkExMessageSigner, SignAndVerify) { + const auto privKeyData = "04be51a04e718c202e4dca60c2b72958252024cfc1070c090dd0f170298249de"; + const auto privateKey = WRAP(TWPrivateKey, TWPrivateKeyCreateWithData(DATA(privKeyData).get())); + const auto message = STRING("463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf"); + + const auto pubKey = TWPrivateKeyGetPublicKeyByType(privateKey.get(), TWPublicKeyTypeStarkex); + const auto signature = WRAPS(TWStarkExMessageSignerSignMessage(privateKey.get(), message.get())); + EXPECT_EQ(std::string(TWStringUTF8Bytes(signature.get())), "04cf5f21333dd189ada3c0f2a51430d733501a9b1d5e07905273c1938cfb261e05b6013d74adde403e8953743a338c8d414bb96bf69d2ca1a91a85ed2700a528"); + EXPECT_TRUE(TWStarkExMessageSignerVerifyMessage(pubKey, message.get(), signature.get())); + delete pubKey; +} + +} diff --git a/tests/common/HDWallet/HDWalletInternalTests.cpp b/tests/common/HDWallet/HDWalletInternalTests.cpp index 1f27ad22cca..c4393e4affa 100644 --- a/tests/common/HDWallet/HDWalletInternalTests.cpp +++ b/tests/common/HDWallet/HDWalletInternalTests.cpp @@ -61,7 +61,7 @@ TEST(HDWalletInternal, SquareDerivationRoutes) { // getMasterNode auto masterNode = HDNode(); - hdnode_from_seed(wallet.getSeed().data(), HDWallet::seedSize, SECP256K1_NAME, &masterNode); + hdnode_from_seed(wallet.getSeed().data(), HDWallet<>::mSeedSize, SECP256K1_NAME, &masterNode); auto node0 = masterNode; // getNode diff --git a/tests/common/HDWallet/HDWalletTests.cpp b/tests/common/HDWallet/HDWalletTests.cpp index 3e70073773f..f783dffb7e1 100644 --- a/tests/common/HDWallet/HDWalletTests.cpp +++ b/tests/common/HDWallet/HDWalletTests.cpp @@ -4,20 +4,25 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include "HDWallet.h" -#include "Mnemonic.h" +#include "Base58.h" #include "Bitcoin/Address.h" #include "Bitcoin/CashAddress.h" #include "Bitcoin/SegwitAddress.h" +#include "Coin.h" #include "Ethereum/Address.h" +#include "Ethereum/Signer.h" +#include "Ethereum/EIP191.h" +#include "Ethereum/EIP2645.h" +#include "HDWallet.h" +#include "Hash.h" #include "Hedera/DER.h" -#include "NEAR/Address.h" #include "HexCoding.h" +#include "ImmutableX/StarkKey.h" +#include "Mnemonic.h" +#include "NEAR/Address.h" #include "PublicKey.h" -#include "Hash.h" -#include "Base58.h" -#include "Coin.h" #include "TestUtilities.h" +#include "StarkEx/MessageSigner.h" #include @@ -57,7 +62,7 @@ TEST(HDWallet, createFromMnemonic) { EXPECT_EQ(hex(wallet.getEntropy()), "ba5821e8c356c05ba5f025d9532fe0f21f65d594"); EXPECT_EQ(hex(wallet.getSeed()), "143cd5fc27ae46eb423efebc41610473f5e24a80f2ca2e2fa7bf167e537f58f4c68310ae487fce82e25bad29bab2530cf77fd724a5ebfc05a45872773d7ee2d6"); } - { // empty passphrase + { // empty passphrase HDWallet wallet = HDWallet(mnemonic1, ""); EXPECT_EQ(wallet.getMnemonic(), mnemonic1); EXPECT_EQ(wallet.getPassphrase(), ""); @@ -67,37 +72,37 @@ TEST(HDWallet, createFromMnemonic) { } TEST(HDWallet, entropyLength_createFromMnemonic) { - { // 12 words + { // 12 words HDWallet wallet = HDWallet("oil oil oil oil oil oil oil oil oil oil oil oil", ""); EXPECT_EQ(wallet.getEntropy().size(), 16ul); EXPECT_EQ(hex(wallet.getEntropy()), "99d33a674ce99d33a674ce99d33a674c"); } - { // 12 words, from https://github.com/trezor/python-mnemonic/blob/master/vectors.json + { // 12 words, from https://github.com/trezor/python-mnemonic/blob/master/vectors.json HDWallet wallet = HDWallet("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", ""); EXPECT_EQ(wallet.getEntropy().size(), 16ul); EXPECT_EQ(hex(wallet.getEntropy()), "00000000000000000000000000000000"); } - { // 15 words + { // 15 words HDWallet wallet = HDWallet("history step cheap card humble screen raise seek robot slot coral roof spoil wreck caution", ""); EXPECT_EQ(wallet.getEntropy().size(), 20ul); EXPECT_EQ(hex(wallet.getEntropy()), "6c3aac9b9146ef832c4e18bb3980c0dddd25fc49"); } - { // 18 words + { // 18 words HDWallet wallet = HDWallet("caught hockey split gun symbol code payment copy broccoli silly shed secret stove tell citizen staff photo high", ""); EXPECT_EQ(wallet.getEntropy().size(), 24ul); EXPECT_EQ(hex(wallet.getEntropy()), "246d8f48b3fdc65a2869801c791715614d6bbd8a56a0a3ad"); } - { // 21 words + { // 21 words HDWallet wallet = HDWallet("diary shine country alpha bridge coast loan hungry hip media sell crucial swarm share gospel lake visa coin dizzy physical basket", ""); EXPECT_EQ(wallet.getEntropy().size(), 28ul); EXPECT_EQ(hex(wallet.getEntropy()), "3d58bcc40381bc59a0c37a6bf14f0d9a3db78a5933e5f4a5ad00d1f1"); } - { // 24 words + { // 24 words HDWallet wallet = HDWallet("poet spider smile swift roof pilot subject save hand diet ice universe over brown inspire ugly wide economy symbol shove episode patient plug swamp", ""); EXPECT_EQ(wallet.getEntropy().size(), 32ul); EXPECT_EQ(hex(wallet.getEntropy()), "a73a3732edebbb49f5fdfe68c7b5c0f6e9de3a1d5760faa8c771e384bf4229b6"); } - { // 24 words, from https://github.com/trezor/python-mnemonic/blob/master/vectors.json + { // 24 words, from https://github.com/trezor/python-mnemonic/blob/master/vectors.json HDWallet wallet = HDWallet("letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", ""); EXPECT_EQ(wallet.getEntropy().size(), 32ul); EXPECT_EQ(hex(wallet.getEntropy()), "8080808080808080808080808080808080808080808080808080808080808080"); @@ -151,7 +156,7 @@ TEST(HDWallet, recreateFromEntropy) { TEST(HDWallet, privateKeyFromXPRV) { const std::string xprv = "xprv9yqEgpMG2KCjvotCxaiMkzmKJpDXz2xZi3yUe4XsURvo9DUbPySW1qRbdeDLiSxZt88hESHUhm2AAe2EqfWM9ucdQzH3xv1HoKoLDqHMK9n"; - auto privateKey = HDWallet::getPrivateKeyFromExtended(xprv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoinCash), 0, 0, 3)); + auto privateKey = HDWallet<>::getPrivateKeyFromExtended(xprv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoinCash), 0, 0, 3)); ASSERT_TRUE(privateKey); auto publicKey = privateKey->getPublicKey(TWPublicKeyTypeSECP256k1); auto address = Bitcoin::BitcoinCashAddress(publicKey); @@ -162,7 +167,7 @@ TEST(HDWallet, privateKeyFromXPRV) { TEST(HDWallet, privateKeyFromXPRV_Invalid) { const std::string xprv = "xprv9y0000"; - auto privateKey = HDWallet::getPrivateKeyFromExtended(xprv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoinCash), 0, 0, 3)); + auto privateKey = HDWallet<>::getPrivateKeyFromExtended(xprv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoinCash), 0, 0, 3)); ASSERT_FALSE(privateKey); } @@ -170,13 +175,13 @@ TEST(HDWallet, privateKeyFromXPRV_InvalidVersion) { { // Version bytes (first 4) are invalid, 0x00000000 const std::string xprv = "11117pE7xwz2GARukXY8Vj2ge4ozfX4HLgy5ztnJXjr5btzJE8EbtPhZwrcPWAodW2aFeYiXkXjSxJYm5QrnhSKFXDgACcFdMqGns9VLqESCq3"; - auto privateKey = HDWallet::getPrivateKeyFromExtended(xprv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoinCash), 0, 0, 3)); + auto privateKey = HDWallet<>::getPrivateKeyFromExtended(xprv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoinCash), 0, 0, 3)); ASSERT_FALSE(privateKey); } { // Version bytes (first 4) are invalid, 0xdeadbeef const std::string xprv = "pGoh3VZXR4mTkT4bfqj4paog12KmHkAWkdLY8HNsZagD1ihVccygLr1ioLBhVQsny47uEh5swP3KScFc4JJrazx1Y7xvzmH2y5AseLgVMwomBTg2"; - auto privateKey = HDWallet::getPrivateKeyFromExtended(xprv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoinCash), 0, 0, 3)); + auto privateKey = HDWallet<>::getPrivateKeyFromExtended(xprv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoinCash), 0, 0, 3)); ASSERT_FALSE(privateKey); } } @@ -184,20 +189,20 @@ TEST(HDWallet, privateKeyFromXPRV_InvalidVersion) { TEST(HDWallet, privateKeyFromExtended_InvalidCurve) { // invalid coin & curve, should fail const std::string xprv = "xprv9yqEgpMG2KCjvotCxaiMkzmKJpDXz2xZi3yUe4XsURvo9DUbPySW1qRbdeDLiSxZt88hESHUhm2AAe2EqfWM9ucdQzH3xv1HoKoLDqHMK9n"; - auto privateKey = HDWallet::getPrivateKeyFromExtended(xprv, TWCoinType(123456), DerivationPath(TWPurposeBIP44, 123456, 0, 0, 0)); + auto privateKey = HDWallet<>::getPrivateKeyFromExtended(xprv, TWCoinType(123456), DerivationPath(TWPurposeBIP44, 123456, 0, 0, 0)); ASSERT_FALSE(privateKey); } TEST(HDWallet, privateKeyFromXPRV_Invalid45) { // 45th byte is not 0 const std::string xprv = "xprv9yqEgpMG2KCjvotCxaiMkzmKJpDXz2xZi3yUe4XsURvo9DUbPySW1qRbhw2dJ8QexahgVSfkjxU4FgmN4GLGN3Ui8oLqC6433CeyPUNVHHh"; - auto privateKey = HDWallet::getPrivateKeyFromExtended(xprv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoinCash), 0, 0, 3)); + auto privateKey = HDWallet<>::getPrivateKeyFromExtended(xprv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoinCash), 0, 0, 3)); ASSERT_FALSE(privateKey); } TEST(HDWallet, privateKeyFromMptv) { const std::string mptv = "Mtpv7SkyM349Svcf1WiRtB5hC91ZZkVsGuv3kz1V7tThGxBFBzBLFnw6LpaSvwpHHuy8dAfMBqpBvaSAHzbffvhj2TwfojQxM7Ppm3CzW67AFL5"; - auto privateKey = HDWallet::getPrivateKeyFromExtended(mptv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoinCash), 0, 0, 4)); + auto privateKey = HDWallet<>::getPrivateKeyFromExtended(mptv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoinCash), 0, 0, 4)); auto publicKey = privateKey->getPublicKey(TWPublicKeyTypeSECP256k1); auto witness = Data{0x00, 0x14}; @@ -216,7 +221,7 @@ TEST(HDWallet, privateKeyFromMptv) { TEST(HDWallet, privateKeyFromZprv) { const std::string zprv = "zprvAdzGEQ44z4WPLNCRpDaup2RumWxLGgR8PQ9UVsSmJigXsHVDaHK1b6qGM2u9PmxB2Gx264ctAz4yRoN3Xwf1HZmKcn6vmjqwsawF4WqQjfd"; - auto privateKey = HDWallet::getPrivateKeyFromExtended(zprv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoin), 0, 0, 5)); + auto privateKey = HDWallet<>::getPrivateKeyFromExtended(zprv, TWCoinTypeBitcoinCash, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeBitcoin), 0, 0, 5)); auto publicKey = privateKey->getPublicKey(TWPublicKeyTypeSECP256k1); auto address = Bitcoin::SegwitAddress(publicKey, "bc"); @@ -226,7 +231,7 @@ TEST(HDWallet, privateKeyFromZprv) { TEST(HDWallet, privateKeyFromDGRV) { const std::string dgpv = "dgpv595jAJYGBLanByCJXRzrWBZFVXdNisfuPmKRDquCQcwBbwKbeR21AtkETf4EpjBsfsK3kDZgMqhcuky1B9PrT5nxiEcjghxpUVYviHXuCmc"; - auto privateKey = HDWallet::getPrivateKeyFromExtended(dgpv, TWCoinTypeDogecoin, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeDogecoin), 0, 0, 1)); + auto privateKey = HDWallet<>::getPrivateKeyFromExtended(dgpv, TWCoinTypeDogecoin, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeDogecoin), 0, 0, 1)); auto publicKey = privateKey->getPublicKey(TWPublicKeyTypeSECP256k1); auto address = Bitcoin::Address(publicKey, TW::p2pkhPrefix(TWCoinTypeDogecoin)); @@ -236,7 +241,7 @@ TEST(HDWallet, privateKeyFromDGRV) { TEST(HDWallet, privateKeyFromXPRVForDGB) { const std::string xprvForDgb = "xprv9ynLofyuR3uCqCMJADwzBaPnXB53EVe5oLujvPfdvCxae3NzgEpYjZMgcUeS8EUeYfYVLG61ZgPXm9TZWiwBnLVCgd551vCwpXC19hX3mFJ"; - auto privateKey = HDWallet::getPrivateKeyFromExtended(xprvForDgb, TWCoinTypeDigiByte, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeDigiByte), 0, 0, 1)); + auto privateKey = HDWallet<>::getPrivateKeyFromExtended(xprvForDgb, TWCoinTypeDigiByte, DerivationPath(TWPurposeBIP44, TWCoinTypeSlip44Id(TWCoinTypeDigiByte), 0, 0, 1)); auto publicKey = privateKey->getPublicKey(TWPublicKeyTypeSECP256k1); auto address = Bitcoin::Address(publicKey, TW::p2pkhPrefix(TWCoinTypeDigiByte)); @@ -264,7 +269,7 @@ TEST(HDWallet, Bip39Vectors) { // BIP39 test vectors, from https://github.com/trezor/python-mnemonic/blob/master/vectors.json const auto passphrase = "TREZOR"; const auto vectors = getVectors(); - for (const auto& v: vectors) { + for (const auto& v : vectors) { const std::string entropy = v[0]; const std::string mnemonic = v[1]; const std::string seed = v[2]; @@ -293,7 +298,7 @@ TEST(HDWallet, getExtendedPrivateKey) { const auto purpose = TWPurposeBIP44; const auto coin = TWCoinTypeBitcoin; const auto hdVersion = TWHDVersionZPRV; - + // default const auto extPubKey1 = wallet.getExtendedPrivateKey(purpose, coin, hdVersion); EXPECT_EQ(extPubKey1, "zprvAcwsTZNaY1f7rfwsy5GseSDStYBrxwtsBZDkb3iyuQUs4NF6n58BuH7Xj54RuaSCWtU5CiQzuYQgFgqr1HokgKcVAeGeXokhJUAJeP3VmvY"); @@ -313,7 +318,7 @@ TEST(HDWallet, getExtendedPublicKey) { const auto coin = TWCoinTypeBitcoin; const auto hdVersion = TWHDVersionZPUB; const auto derivation = TWDerivationDefault; - + // default const auto extPubKey1 = wallet.getExtendedPublicKey(purpose, coin, hdVersion); EXPECT_EQ(extPubKey1, "zpub6qwDs4uUNPDR5A2M56ot1aABSa2MNQciYn9MPS8bTk1qwAaFKcSST5S1aLidvPp9twqpaumG7vikR2vHhBXjp5oGgHyMvWK3AtUkfeEgyns"); @@ -457,6 +462,137 @@ TEST(HDWallet, HederaKey) { } } +TEST(HDWallet, FromSeedStark) { + std::string signature = "0x5a263fad6f17f23e7c7ea833d058f3656d3fe464baf13f6f5ccba9a2466ba2ce4c4a250231bcac7beb165aec4c9b049b4ba40ad8dd287dc79b92b1ffcf20cdcf1b"; + auto data = parse_hex(signature); + auto ethSignature = Ethereum::Signer::signatureDataToStructSimple(data); + auto seed = store(ethSignature.s); + ASSERT_EQ(ethSignature.s, uint256_t("34506778598894488719068064129252410649539581100963007245393949841529394744783")); + auto derivationPath = DerivationPath("m/2645'/579218131'/211006541'/1534045311'/1431804530'/1"); + auto key = HDWallet<32>::bip32DeriveRawSeed(TWCoinTypeEthereum, seed, derivationPath); + ASSERT_EQ(hex(key.bytes), "57384e99059bb1c0e51d70f0fca22d18d7191398dd39d6b9b4e0521174b2377a"); + auto addr = Ethereum::Address(key.getPublicKey(TWPublicKeyTypeSECP256k1Extended)).string(); + ASSERT_EQ(addr, "0x47bbe762944B089315ac50c9ca762F4B4884B965"); +} + +TEST(HDWallet, FromMnemonicStark) { + // https://github.com/starkware-libs/starkware-crypto-utils/blob/d3a1e655105afd66ebc07f88a179a3042407cc7b/test/js/key_derivation.spec.js#L20 + const auto mnemonic = "range mountain blast problem vibrant void vivid doctor cluster enough melody salt layer language laptop boat major space monkey unit glimpse pause change vibrant"; + const auto ethAddress = "0xA4864D977b944315389d1765Ffa7E66F74eE8cD7"; + HDWallet wallet = HDWallet(mnemonic, ""); + auto derivationPath = DerivationPath(Ethereum::accountPathFromAddress(ethAddress, "starkex", "starkdeployement", "0")); + ASSERT_EQ(derivationPath.string(), "m/2645'/579218131'/891216374'/1961790679'/2135936222'/0"); + + // ETH + { + auto ethPrivKey = wallet.getKey(TWCoinTypeEthereum, DerivationPath("m/44'/60'/0'/0/0")); + auto ethAddressFromPub = Ethereum::Address(ethPrivKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended)).string(); + ASSERT_EQ(ethAddressFromPub, ethAddress); + } + + // Stark + { + auto starkPrivKey = wallet.getKeyByCurve(TWCurveStarkex, DerivationPath(derivationPath)); + auto starkPubKey = hex(starkPrivKey.getPublicKey(TWPublicKeyTypeStarkex).bytes); + ASSERT_EQ(hex(starkPrivKey.bytes), "06cf0a8bf113352eb863157a45c5e5567abb34f8d32cddafd2c22aa803f4892c"); + ASSERT_EQ(starkPubKey, "02d2bbdc1adaf887b0027cdde2113cfd81c60493aa6dc15d7887ddf1a82bc831"); + } +} + +TEST(HDWallet, FromMnemonicImmutableX) { + // Successfully register the user: https://api.sandbox.x.immutable.com/v1/users/0x1A817D0cC495C8157E4C734c48a1e840473CBCa1 + const auto mnemonic = "owner erupt swamp room swift final allow unaware hint identify figure cotton"; + const auto ethAddress = "0x1A817D0cC495C8157E4C734c48a1e840473CBCa1"; + HDWallet wallet = HDWallet(mnemonic, ""); + auto derivationPath = DerivationPath(Ethereum::accountPathFromAddress(ethAddress, "starkex", "immutablex", "1")); + ASSERT_EQ(derivationPath.string(), "m/2645'/579218131'/211006541'/1195162785'/289656960'/1"); + + // ETH + { + auto ethPrivKey = wallet.getKey(TWCoinTypeEthereum, DerivationPath("m/44'/60'/0'/0/0")); + ASSERT_EQ(hex(ethPrivKey.bytes), "a84f129929f6effe3fd541bcaa8a13d80714cd93c205682bea8b9e0cfc28a2ad"); + auto ethAddressFromPub = Ethereum::Address(ethPrivKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended)).string(); + ASSERT_EQ(ethAddressFromPub, ethAddress); + } + + // Stark + { + auto starkPrivKey = wallet.getKeyByCurve(TWCurveStarkex, DerivationPath(derivationPath)); + auto starkPubKey = starkPrivKey.getPublicKey(TWPublicKeyTypeStarkex); + ASSERT_EQ(hex(starkPrivKey.bytes), "02d037bb9c1302295c2f9fa66bcc4ab8e353a3140600a390598777d69c1bc71a"); + ASSERT_EQ(hex(starkPubKey.bytes), "006c061ea4195769058e0e2e14cd747619a866954a412e15fa2241fdf49438cf"); + + auto starkMsg = "28419a504c5b1c83df4fdcbf7f5f36a7d5cfa8148aff2d33aed2f40a64e7ea0"; + auto starkSignature = StarkEx::MessageSigner::signMessage(starkPrivKey, starkMsg); + ASSERT_EQ(starkSignature, "077cae8f00327a2072d3ca8b31725263f61303dc0142a631561d33cb2b4cb221008d659541d59f1589b0e714ddc0a5bee77faddf093f96d529b6c55c0bffd45d"); + ASSERT_TRUE(StarkEx::MessageSigner::verifyMessage(starkPubKey, starkMsg, starkSignature)); + } +} + +TEST(HDWallet, FromMnemonicImmutableXMainnet) { + const auto mnemonic = "ocean seven canyon push fiscal banana music guess arrange edit glance school"; + const auto ethAddress = "0x39E652fE9458D391737058b0dd5eCC6ec910A7dd"; + HDWallet wallet = HDWallet(mnemonic, ""); + auto derivationPath = DerivationPath(Ethereum::accountPathFromAddress(ethAddress, "starkex", "immutablex", "1")); + ASSERT_EQ(derivationPath.string(), "m/2645'/579218131'/211006541'/1225828317'/985503965'/1"); + + // ETH + { + auto ethPrivKey = wallet.getKey(TWCoinTypeEthereum, DerivationPath("m/44'/60'/0'/0/0")); + ASSERT_EQ(hex(ethPrivKey.bytes), "3b0a61f46fdae924007146eacb6db6642de7a5603ad843ec58e10331d89d4b84"); + auto ethAddressFromPub = Ethereum::Address(ethPrivKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended)).string(); + ASSERT_EQ(ethAddressFromPub, ethAddress); + + std::string tosign = "Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3"; + auto hexEthSignature = Ethereum::MessageSigner::signMessage(ethPrivKey, tosign); + + ASSERT_EQ(hexEthSignature, "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01"); + } + + // Stark + { + auto starkPrivKey = wallet.getKeyByCurve(TWCurveStarkex, DerivationPath(derivationPath)); + auto starkPubKey = starkPrivKey.getPublicKey(TWPublicKeyTypeStarkex); + ASSERT_EQ(hex(starkPrivKey.bytes), "070128376c2cfd21e7475708049d00c83d7ab65f15368e28730bf1684dee8370"); + ASSERT_EQ(hex(starkPubKey.bytes), "00453ca02b347f80e5ddfc4caf254852fc05b172b37bca8f7e28600631d12dfe"); + + auto starkMsg = "76b66c453cd1b812032ff206a28df59f6abe41e805b9f1c48a1c4afe780756c"; + auto starkSignature = StarkEx::MessageSigner::signMessage(starkPrivKey, starkMsg); + ASSERT_EQ(starkSignature, "070ad88f79650fbdc152affd738d4ec29888bed554ea74f9ad8ca7031ef300b50597f4a62752336db06e6d37dfc18047fdd40804f5fd19cebfda8cac91e4f178"); + ASSERT_TRUE(StarkEx::MessageSigner::verifyMessage(starkPubKey, starkMsg, starkSignature)); + } +} + +TEST(HDWallet, FromMnemonicImmutableXMainnetFromSignature) { + // Successfully register: https://api.x.immutable.com/v1/users/0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37 + const auto mnemonic = "obscure opera favorite shuffle mail tip age debate dirt pact cement loyal"; + const auto ethAddress = "0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37"; + HDWallet wallet = HDWallet(mnemonic, ""); + auto derivationPath = DerivationPath(Ethereum::accountPathFromAddress(ethAddress, "starkex", "immutablex", "1")); + ASSERT_EQ(derivationPath.string(), "m/2645'/579218131'/211006541'/2124474935'/1609799702'/1"); + + // ETH + stark + { + auto ethPrivKey = wallet.getKey(TWCoinTypeEthereum, DerivationPath("m/44'/60'/0'/0/0")); + ASSERT_EQ(hex(ethPrivKey.bytes), "03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d"); + auto ethAddressFromPub = Ethereum::Address(ethPrivKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended)).string(); + ASSERT_EQ(ethAddressFromPub, ethAddress); + auto signature = Ethereum::MessageSigner::signMessage(ethPrivKey, "Only sign this request if you’ve initiated an action with Immutable X."); + ASSERT_EQ(signature, "18b1be8b78807d3326e28bc286d7ee3d068dcd90b1949ce1d25c1f99825f26e70992c5eb7f44f76b202aceded00d74f771ed751f2fe538eec01e338164914fe001"); + auto starkPrivKey = ImmutableX::getPrivateKeyFromRawSignature(parse_hex(signature), DerivationPath(derivationPath)); + auto starkPubKey = starkPrivKey.getPublicKey(TWPublicKeyTypeStarkex); + ASSERT_EQ(hex(starkPrivKey.bytes), "04be51a04e718c202e4dca60c2b72958252024cfc1070c090dd0f170298249de"); + ASSERT_EQ(hex(starkPubKey.bytes), "00e5b9b11f8372610ef35d647a1dcaba1a4010716588d591189b27bf3c2d5095"); + auto signatureToSend = Ethereum::MessageSigner::signMessage(ethPrivKey, "Only sign this key linking request from Immutable X"); + ASSERT_EQ(signatureToSend, "646da4160f7fc9205e6f502fb7691a0bf63ecbb74bbb653465cd62388dd9f56325ab1e4a9aba99b1661e3e6251b42822855a71e60017b310b9f90e990a12e1dc01"); + + auto starkMsg = "463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf"; + auto starkSignature = StarkEx::MessageSigner::signMessage(starkPrivKey, starkMsg); + ASSERT_EQ(starkSignature, "04cf5f21333dd189ada3c0f2a51430d733501a9b1d5e07905273c1938cfb261e05b6013d74adde403e8953743a338c8d414bb96bf69d2ca1a91a85ed2700a528"); + ASSERT_TRUE(StarkEx::MessageSigner::verifyMessage(starkPubKey, starkMsg, starkSignature)); + } +} + TEST(HDWallet, NearKey) { const auto derivPath = "m/44'/397'/0'"; HDWallet wallet = HDWallet("owner erupt swamp room swift final allow unaware hint identify figure cotton", ""); @@ -469,4 +605,4 @@ TEST(HDWallet, NearKey) { } } -} // namespace +} // namespace TW::HDWalletTests diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp index d34edd03468..9cbf538898b 100644 --- a/tests/interface/TWHDWalletTests.cpp +++ b/tests/interface/TWHDWalletTests.cpp @@ -17,6 +17,10 @@ #include #include #include +#include +#include +#include +#include #include #include "HexCoding.h" @@ -498,6 +502,47 @@ TEST(HDWallet, GetKeyByCurve) { assertHexEqual(privateKeyData2, "a13df52d5a5b438bbf921bbf86276e4347fe8e2f2ed74feaaee12b77d6d26f86"); } +TEST(TWHDWallet, FromMnemonicImmutableXMainnetFromSignature) { + // Successfully register: https://api.x.immutable.com/v1/users/0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37 + const auto mnemonic = STRING("obscure opera favorite shuffle mail tip age debate dirt pact cement loyal"); + const auto ethAddress = STRING("0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37"); + const auto layer = STRING("starkex"); + const auto application = STRING("immutablex"); + const auto index = STRING("1"); + const auto ethDerivationPath = STRING("m/44'/60'/0'/0/0"); + auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(mnemonic.get(), STRING("").get())); + auto derivationPath = WRAPS(TWEthereumEip2645GetPath(ethAddress.get(), layer.get(), application.get(), index.get())); + assertStringsEqual(derivationPath, "m/2645'/579218131'/211006541'/2124474935'/1609799702'/1"); + + // Retrieve eth private key + auto ethPrivateKey = WRAP(TWPrivateKey, TWHDWalletGetKey(wallet.get(), TWCoinTypeEthereum, ethDerivationPath.get())); + const auto ethPrivateKeyData = WRAPD(TWPrivateKeyData(ethPrivateKey.get())); + assertHexEqual(ethPrivateKeyData, "03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d"); + + // StarkKey Derivation Path + const auto starkDerivationPath = WRAP(TWDerivationPath, TWDerivationPathCreateWithString(derivationPath.get())); + + // Retrieve Stark Private key part + const auto ethMsg = STRING("Only sign this request if you’ve initiated an action with Immutable X."); + const auto ethSignature = WRAPS(TWEthereumMessageSignerSignMessage(ethPrivateKey.get(), ethMsg.get())); + assertStringsEqual(ethSignature, "18b1be8b78807d3326e28bc286d7ee3d068dcd90b1949ce1d25c1f99825f26e70992c5eb7f44f76b202aceded00d74f771ed751f2fe538eec01e338164914fe001"); + const auto starkPrivateKey = WRAP(TWPrivateKey, TWStarkWareGetStarkKeyFromSignature(starkDerivationPath.get(), ethSignature.get())); + const auto starkPrivateKeyData = WRAPD(TWPrivateKeyData(starkPrivateKey.get())); + const auto starkPubKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyByType(starkPrivateKey.get(), TWPublicKeyTypeStarkex)); + const auto starkPublicKeyData = WRAPD(TWPublicKeyData(starkPubKey.get())); + assertHexEqual(starkPrivateKeyData, "04be51a04e718c202e4dca60c2b72958252024cfc1070c090dd0f170298249de"); + assertHexEqual(starkPublicKeyData, "00e5b9b11f8372610ef35d647a1dcaba1a4010716588d591189b27bf3c2d5095"); + + // Account register + const auto ethMsgToRegister = STRING("Only sign this key linking request from Immutable X"); + const auto ethSignatureToRegister = WRAPS(TWEthereumMessageSignerSignMessage(ethPrivateKey.get(), ethMsgToRegister.get())); + assertStringsEqual(ethSignatureToRegister, "646da4160f7fc9205e6f502fb7691a0bf63ecbb74bbb653465cd62388dd9f56325ab1e4a9aba99b1661e3e6251b42822855a71e60017b310b9f90e990a12e1dc01"); + const auto starkMsg = STRING("463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf"); + const auto starkSignature = WRAPS(TWStarkExMessageSignerSignMessage(starkPrivateKey.get(), starkMsg.get())); + assertStringsEqual(starkSignature, "04cf5f21333dd189ada3c0f2a51430d733501a9b1d5e07905273c1938cfb261e05b6013d74adde403e8953743a338c8d414bb96bf69d2ca1a91a85ed2700a528"); + ASSERT_TRUE(TWStarkExMessageSignerVerifyMessage(starkPubKey.get(), starkMsg.get(), starkSignature.get())); +} + TEST(TWHDWallet, Derive_XpubPub_vs_PrivPub) { // Test different routes for deriving address from mnemonic, result should be the same: // - Direct: mnemonic -> seed -> privateKey -> publicKey -> address diff --git a/walletconsole/lib/Address.cpp b/walletconsole/lib/Address.cpp index 7a082f7413c..6aab3c60ca4 100644 --- a/walletconsole/lib/Address.cpp +++ b/walletconsole/lib/Address.cpp @@ -29,7 +29,7 @@ bool Address::addrPub(const string& coinid, const string& pubkey_in, string& res pubDat = parse_hex(pubkey_in); } catch (exception& ex) { _out << "Error: could not parse public key data" << endl; - return false; + return false; } auto ctype = (TWCoinType)coin.c; PublicKey pubKey = PublicKey(pubDat, (TWPublicKeyType)coin.pubKeyType); @@ -45,7 +45,7 @@ bool Address::addrPri(const string& coinid, const string& prikey_in, string& res priDat = parse_hex(prikey_in); } catch (exception& ex) { _out << "Error: could not parse private key data" << endl; - return false; + return false; } auto ctype = (TWCoinType)coin.c; PrivateKey priKey = PrivateKey(priDat); @@ -108,7 +108,7 @@ bool Address::deriveFromXpubIndex(const string& coinid, const string& xpub, cons dp.setChange(0); dp.setAddress(index); - const auto publicKey = HDWallet::getPublicKeyFromExtended(xpub, ctype, dp); + const auto publicKey = HDWallet<>::getPublicKeyFromExtended(xpub, ctype, dp); if (!publicKey) { return false; } res = TW::deriveAddress(ctype, publicKey.value()); return true; From 9e00215b287a4b2e8de0cf31a3ff4eb25fef9179 Mon Sep 17 00:00:00 2001 From: Joao Cordeiro Date: Fri, 23 Dec 2022 11:05:05 +0000 Subject: [PATCH 160/497] Updated docker build (#2809) * Update libssl version to 1.1.1 for docker build * Install rust during docker build * Switch curl to wget to keep consistency with rest of Dockerfile * Install cbindgen on docker build * Add missing include --- Dockerfile | 9 ++++++++- src/Ethereum/EIP2645.cpp | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index fae3ef89269..ee2bff16772 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,7 @@ RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc | apt-key && apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main' -RUN wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb && dpkg -i ./libssl1.1_1.1.0g-2ubuntu4_amd64.deb +RUN wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2.16_amd64.deb && dpkg -i ./libssl1.1_1.1.1f-1ubuntu2.16_amd64.deb # Install required packages for dev RUN apt-get update \ && apt-get install -y \ @@ -39,6 +39,13 @@ RUN apt-get update \ ENV CC=/usr/bin/clang-14 ENV CXX=/usr/bin/clang++-14 +# Install rust +RUN wget "https://sh.rustup.rs" -O rustup.sh \ + && sh rustup.sh -y +ENV PATH="/root/.cargo/bin:${PATH}" +RUN cargo install --force cbindgen \ + && rustup target add wasm32-unknown-emscripten + # ↑ Setup build environment # ↓ Build and compile wallet core diff --git a/src/Ethereum/EIP2645.cpp b/src/Ethereum/EIP2645.cpp index 9a601643999..c5e1bc72f93 100644 --- a/src/Ethereum/EIP2645.cpp +++ b/src/Ethereum/EIP2645.cpp @@ -8,6 +8,7 @@ #include #include +#include #include namespace TW::Ethereum::internal { From 3ef2428a9841301c1296bde104eb2fe4d96a5035 Mon Sep 17 00:00:00 2001 From: Peng Huang Date: Fri, 30 Dec 2022 04:55:51 -0500 Subject: [PATCH 161/497] Change several classes to structs (#2826) --- include/TrustWalletCore/TWBitcoinMessageSigner.h | 2 +- include/TrustWalletCore/TWEthereumEip2645.h | 2 +- include/TrustWalletCore/TWEthereumMessageSigner.h | 2 +- include/TrustWalletCore/TWStarkExMessageSigner.h | 2 +- include/TrustWalletCore/TWStarkWare.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/TrustWalletCore/TWBitcoinMessageSigner.h b/include/TrustWalletCore/TWBitcoinMessageSigner.h index d0fcd2e17bd..8cfe84f14da 100644 --- a/include/TrustWalletCore/TWBitcoinMessageSigner.h +++ b/include/TrustWalletCore/TWBitcoinMessageSigner.h @@ -18,7 +18,7 @@ TW_EXTERN_C_BEGIN /// Bitcoin Core and some other wallets support a message signing & verification format, to create a proof (a signature) /// that someone has access to the private keys of a specific address. /// This feature currently works on old legacy addresses only. -TW_EXPORT_CLASS +TW_EXPORT_STRUCT struct TWBitcoinMessageSigner; /// Sign a message. diff --git a/include/TrustWalletCore/TWEthereumEip2645.h b/include/TrustWalletCore/TWEthereumEip2645.h index f6315908c33..95678fa8be6 100644 --- a/include/TrustWalletCore/TWEthereumEip2645.h +++ b/include/TrustWalletCore/TWEthereumEip2645.h @@ -11,7 +11,7 @@ TW_EXTERN_C_BEGIN -TW_EXPORT_CLASS +TW_EXPORT_STRUCT struct TWEthereumEip2645; /// Generate a layer 2 eip2645 derivation path from eth address, layer, application and given index. diff --git a/include/TrustWalletCore/TWEthereumMessageSigner.h b/include/TrustWalletCore/TWEthereumMessageSigner.h index 1fb230b143f..e33a3e3dad1 100644 --- a/include/TrustWalletCore/TWEthereumMessageSigner.h +++ b/include/TrustWalletCore/TWEthereumMessageSigner.h @@ -18,7 +18,7 @@ TW_EXTERN_C_BEGIN /// /// Ethereum and some other wallets support a message signing & verification format, to create a proof (a signature) /// that someone has access to the private keys of a specific address. -TW_EXPORT_CLASS +TW_EXPORT_STRUCT struct TWEthereumMessageSigner; /// Sign a message. diff --git a/include/TrustWalletCore/TWStarkExMessageSigner.h b/include/TrustWalletCore/TWStarkExMessageSigner.h index a7569171c39..ea012369795 100644 --- a/include/TrustWalletCore/TWStarkExMessageSigner.h +++ b/include/TrustWalletCore/TWStarkExMessageSigner.h @@ -17,7 +17,7 @@ TW_EXTERN_C_BEGIN /// /// StarkEx and some other wallets support a message signing & verification format, to create a proof (a signature) /// that someone has access to the private keys of a specific address. -TW_EXPORT_CLASS +TW_EXPORT_STRUCT struct TWStarkExMessageSigner; /// Sign a message. diff --git a/include/TrustWalletCore/TWStarkWare.h b/include/TrustWalletCore/TWStarkWare.h index 0990d67be86..593876c16f3 100644 --- a/include/TrustWalletCore/TWStarkWare.h +++ b/include/TrustWalletCore/TWStarkWare.h @@ -13,7 +13,7 @@ TW_EXTERN_C_BEGIN -TW_EXPORT_CLASS +TW_EXPORT_STRUCT struct TWStarkWare; /// Generates the private stark key at the given derivation path from a valid eth signature From 42408e5d394617e278e597950b18a4173a9a620c Mon Sep 17 00:00:00 2001 From: Ayush Bherwani Date: Fri, 6 Jan 2023 14:16:48 +0530 Subject: [PATCH 162/497] Agoric Support (#2824) --- .../blockchains/CoinAddressDerivationTests.kt | 1 + .../blockchains/agoric/TestAgoricAddress.kt | 32 +++++++++ .../blockchains/agoric/TestAgoricSigner.kt | 68 +++++++++++++++++++ docs/registry.md | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 31 +++++++++ swift/Tests/Blockchains/AgoricTests.swift | 63 +++++++++++++++++ swift/Tests/CoinAddressDerivationTests.swift | 4 +- tests/chains/Agoric/AddressTests.cpp | 43 ++++++++++++ tests/chains/Agoric/TWCoinTypeTests.cpp | 37 ++++++++++ tests/common/CoinAddressDerivationTests.cpp | 3 + 11 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricAddress.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricSigner.kt create mode 100644 swift/Tests/Blockchains/AgoricTests.swift create mode 100644 tests/chains/Agoric/AddressTests.cpp create mode 100644 tests/chains/Agoric/TWCoinTypeTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 8d60a752d44..b3384921873 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -108,5 +108,6 @@ class CoinAddressDerivationTests { APTOS -> assertEquals("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", address) HEDERA -> assertEquals("0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5", address) SECRET -> assertEquals("secret1f69sk5033zcdr2p2yf3xjehn7xvgdeq09d2llh", address) + AGORIC -> assertEquals("agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5", address) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricAddress.kt new file mode 100644 index 00000000000..9cabca65f15 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricAddress.kt @@ -0,0 +1,32 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.agoric + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestAgoricAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + + val key = PrivateKey("037048190544fa57651452f477c096de4f3073e7835cf3845b04602563a73f73".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(true) + val address = AnyAddress(pubkey, CoinType.AGORIC) + val expected = AnyAddress("agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5", CoinType.AGORIC) + + assertEquals(pubkey.data().toHex(), "0x03df9a5e4089f89d45913fb2b856de984c7e8bf1344cc6444cc9705899a48c939d") + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricSigner.kt new file mode 100644 index 00000000000..7567a61f21f --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/agoric/TestAgoricSigner.kt @@ -0,0 +1,68 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.agoric + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.AnyAddress +import wallet.core.jni.CoinType +import wallet.core.jni.PrivateKey +import wallet.core.jni.proto.Cosmos + +class TestAgoricSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun AgoricTransactionSigning() { + val key = PrivateKey("037048190544fa57651452f477c096de4f3073e7835cf3845b04602563a73f73".toHexByteArray()) + val publicKey = key.getPublicKeySecp256k1(true) + val from = AnyAddress(publicKey, CoinType.AGORIC).description() + + val transferAmount = Cosmos.Amount.newBuilder().apply { + amount = "1" + denom = "ubld" + }.build() + + val message = Cosmos.Message.newBuilder().apply { + sendCoinsMessage = Cosmos.Message.Send.newBuilder().apply { + fromAddress = from + toAddress = "agoric1cqvwa8jr6pmt45jndanc8lqmdsxjkhw0yertc0" + addAllAmounts(listOf(transferAmount)) + }.build() + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "2000" + denom = "ubld" + }.build() + + val cosmosFee = Cosmos.Fee.newBuilder().apply { + gas = 100000 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = Cosmos.SigningMode.Protobuf + accountNumber = 62972 + chainId = "agoric-3" + sequence = 1 + fee = cosmosFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, CoinType.AGORIC, Cosmos.SigningOutput.parser()) + + assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CowBCokBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmkKLWFnb3JpYzE4enZ2Z2s2ajNlcTV3ZDdtcXhjY2d0MjBnejJ3OTRjeTg4YWVrNRItYWdvcmljMWNxdndhOGpyNnBtdDQ1am5kYW5jOGxxbWRzeGpraHcweWVydGMwGgkKBHVibGQSATESZgpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA9+aXkCJ+J1FkT+yuFbemEx+i/E0TMZETMlwWJmkjJOdEgQKAggBGAESEgoMCgR1YmxkEgQyMDAwEKCNBhpAenbGO4UBK610dwSY6l5pl58qwHW1OujQ/9vF9unQdrA1SE0b/2mZxnevy5y3u6pJfBffWUfCx68PcVEu7D3EYQ==\"}") + } +} diff --git a/docs/registry.md b/docs/registry.md index b5ca89f1dbe..0d9e425c1d1 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -51,6 +51,7 @@ This list is generated from [./registry.json](../registry.json) | 501 | Solana | SOL | | | | 508 | Elrond | eGLD | | | | 529 | Secret | SCRT | | | +| 564 | Agoric | BLD | | | | 637 | Aptos | APT | | | | 714 | BNB Beacon Chain | BNB | | | | 818 | VeChain | VET | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index aaf37364468..cb196d5920b 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -126,6 +126,7 @@ enum TWCoinType { TWCoinTypeAptos = 637, TWCoinTypeHedera = 3030, TWCoinTypeSecret = 529, + TWCoinTypeAgoric = 564, }; /// Returns the blockchain for a coin type. diff --git a/registry.json b/registry.json index d2279f7144a..fabf45f3b5b 100644 --- a/registry.json +++ b/registry.json @@ -2880,5 +2880,36 @@ "source": "https://github.com/hashgraph", "documentation": "https://docs.hedera.com" } + }, + { + "id": "agoric", + "name": "Agoric", + "coinId": 564, + "symbol": "BLD", + "decimals": 6, + "blockchain": "Cosmos", + "derivation": [ + { + "path": "m/44'/564'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "agoric", + "chainId": "agoric-3", + "addressHasher": "sha256ripemd", + "explorer": { + "url": "https://atomscan.com/agoric", + "txPath": "/transactions/", + "accountPath": "/accounts/", + "sampleTx": "576224B1A0F3D56BA23C5350C2A0E3CEA86F40005B828793E5ACBC2F4813152E", + "sampleAccount": "agoric1cqvwa8jr6pmt45jndanc8lqmdsxjkhw0yertc0" + }, + "info": { + "url": "https://agoric.com", + "source": "https://github.com/Agoric/agoric-sdk", + "rpc": "https://agoric-rpc.polkachu.com", + "documentation": "https://docs.agoric.com" + } } ] diff --git a/swift/Tests/Blockchains/AgoricTests.swift b/swift/Tests/Blockchains/AgoricTests.swift new file mode 100644 index 00000000000..19404b3447b --- /dev/null +++ b/swift/Tests/Blockchains/AgoricTests.swift @@ -0,0 +1,63 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import WalletCore +import XCTest + +class AgoricTests: XCTestCase { + + func testAddress() { + let key = PrivateKey(data: Data(hexString: "037048190544fa57651452f477c096de4f3073e7835cf3845b04602563a73f73")!)! + let pubkey = key.getPublicKeySecp256k1(compressed: true) + let address = AnyAddress(publicKey: pubkey, coin: .agoric) + let addressFromString = AnyAddress(string: "agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5", coin: .agoric)! + + XCTAssertEqual(pubkey.data.hexString, "03df9a5e4089f89d45913fb2b856de984c7e8bf1344cc6444cc9705899a48c939d") + XCTAssertEqual(address.description, addressFromString.description) + } + + func testSign() { + let privateKey = PrivateKey(data: Data(hexString: "037048190544fa57651452f477c096de4f3073e7835cf3845b04602563a73f73")!)! + let publicKey = privateKey.getPublicKeySecp256k1(compressed: true) + let fromAddress = AnyAddress(publicKey: publicKey, coin: .agoric) + + let sendCoinsMessage = CosmosMessage.Send.with { + $0.fromAddress = fromAddress.description + $0.toAddress = "agoric1cqvwa8jr6pmt45jndanc8lqmdsxjkhw0yertc0" + $0.amounts = [CosmosAmount.with { + $0.amount = "1" + $0.denom = "ubld" + }] + } + + + let fee = CosmosFee.with { + $0.gas = 100000 + $0.amounts = [CosmosAmount.with { + $0.amount = "2000" + $0.denom = "ubld" + }] + } + + let input = CosmosSigningInput.with { + $0.signingMode = .protobuf; + $0.accountNumber = 62972 + $0.chainID = "agoric-3" + $0.sequence = 1 + $0.messages = [ + CosmosMessage.with { + $0.sendCoinsMessage = sendCoinsMessage + } + ] + $0.fee = fee + $0.privateKey = privateKey.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .agoric) + + XCTAssertJSONEqual(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CowBCokBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmkKLWFnb3JpYzE4enZ2Z2s2ajNlcTV3ZDdtcXhjY2d0MjBnejJ3OTRjeTg4YWVrNRItYWdvcmljMWNxdndhOGpyNnBtdDQ1am5kYW5jOGxxbWRzeGpraHcweWVydGMwGgkKBHVibGQSATESZgpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA9+aXkCJ+J1FkT+yuFbemEx+i/E0TMZETMlwWJmkjJOdEgQKAggBGAESEgoMCgR1YmxkEgQyMDAwEKCNBhpAenbGO4UBK610dwSY6l5pl58qwHW1OujQ/9vF9unQdrA1SE0b/2mZxnevy5y3u6pJfBffWUfCx68PcVEu7D3EYQ==\"}") + } +} diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 081a61cae55..d839b605452 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -262,7 +262,9 @@ class CoinAddressDerivationTests: XCTestCase { case .secret: let expectedResult = "secret1f69sk5033zcdr2p2yf3xjehn7xvgdeq09d2llh" assertCoinDerivation(coin, expectedResult, derivedAddress, address) - + case .agoric: + let expectedResult = "agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5" + assertCoinDerivation(coin, expectedResult, derivedAddress, address) @unknown default: fatalError() } diff --git a/tests/chains/Agoric/AddressTests.cpp b/tests/chains/Agoric/AddressTests.cpp new file mode 100644 index 00000000000..4e18f242374 --- /dev/null +++ b/tests/chains/Agoric/AddressTests.cpp @@ -0,0 +1,43 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "Cosmos/Address.h" +#include "PublicKey.h" +#include "PrivateKey.h" +#include +#include + +namespace TW::Cosmos::tests { + +TEST(AgoricAddress, Valid) { + ASSERT_TRUE(Address::isValid(TWCoinTypeSecret, "secret16vw3fp7x35tzmwlkdkyzr8vgscn0zewtduyjuf")); + ASSERT_TRUE(Address::isValid(TWCoinTypeSecret, "secret15rgv8teecnt53h0gdvngzt3am3yuz3rxh4fnle")); +} + +TEST(AgoricAddress, Invalid) { + ASSERT_FALSE(Address::isValid(TWCoinTypeAgoric, "agoric1cqvwa8jr6pmt45jndanc8lqmdsxjkhw0yert212")); + ASSERT_FALSE(Address::isValid(TWCoinTypeAgoric, "osmo1nvt7lu3e0l8wqahlya6m98zmma6qc9r40evp0v")); +} + +TEST(AgoricAddress, FromPrivateKey) { + auto privateKey = PrivateKey(parse_hex("037048190544fa57651452f477c096de4f3073e7835cf3845b04602563a73f73")); + auto address = Address(TWCoinTypeAgoric, privateKey.getPublicKey(TWPublicKeyTypeSECP256k1)); + ASSERT_EQ(address.string(), "agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5"); +} + +TEST(AgoricAddress, FromPublicKey) { + auto publicKey = PublicKey(parse_hex("03df9a5e4089f89d45913fb2b856de984c7e8bf1344cc6444cc9705899a48c939d"), TWPublicKeyTypeSECP256k1); + auto address = Address(TWCoinTypeAgoric, publicKey); + ASSERT_EQ(address.string(), "agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5"); +} + +TEST(AgoricAddress, FromString) { + Address address; + EXPECT_TRUE(Address::decode("agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5", address)); + EXPECT_EQ(address.string(), "agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5"); +} +} diff --git a/tests/chains/Agoric/TWCoinTypeTests.cpp b/tests/chains/Agoric/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..d113c5e1ef3 --- /dev/null +++ b/tests/chains/Agoric/TWCoinTypeTests.cpp @@ -0,0 +1,37 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "TestUtilities.h" +#include +#include + + +TEST(TWAgoricCoinType, TWCoinType) { + const auto coin = TWCoinTypeAgoric; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto chainId = WRAPS(TWCoinTypeChainId(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("576224B1A0F3D56BA23C5350C2A0E3CEA86F40005B828793E5ACBC2F4813152E")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("agoric1cqvwa8jr6pmt45jndanc8lqmdsxjkhw0yertc0")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "agoric"); + assertStringsEqual(name, "Agoric"); + assertStringsEqual(symbol, "BLD"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 6); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainCosmos); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); + assertStringsEqual(chainId, "agoric-3"); + assertStringsEqual(txUrl, "https://atomscan.com/agoric/transactions/576224B1A0F3D56BA23C5350C2A0E3CEA86F40005B828793E5ACBC2F4813152E"); + assertStringsEqual(accUrl, "https://atomscan.com/agoric/accounts/agoric1cqvwa8jr6pmt45jndanc8lqmdsxjkhw0yertc0"); +} diff --git a/tests/common/CoinAddressDerivationTests.cpp b/tests/common/CoinAddressDerivationTests.cpp index be0e69bce0a..64d792feea9 100644 --- a/tests/common/CoinAddressDerivationTests.cpp +++ b/tests/common/CoinAddressDerivationTests.cpp @@ -258,6 +258,9 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeSecret: EXPECT_EQ(address, "secret1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0m7t23a"); break; + case TWCoinTypeAgoric: + EXPECT_EQ(address, "agoric1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0txauuh"); + break; // no default branch here, intentionally, to better notice any missing coins } } From a5563f8dc6d50d9ebd4e9767f09617533c7b9742 Mon Sep 17 00:00:00 2001 From: Adam V <13562139+catenocrypt@users.noreply.github.com> Date: Mon, 9 Jan 2023 10:01:22 +0200 Subject: [PATCH 163/497] Add extra hrp and coin check to lockScriptForAddress() (#2814) --- src/Bitcoin/Script.cpp | 119 +++++++++++------- .../GroestlcoinTransactionSignerTests.swift | 3 + tests/chains/Bitcoin/TWBitcoinScriptTests.cpp | 4 +- tests/chains/DigiByte/TWDigiByteTests.cpp | 2 + tests/chains/ECash/TWECashTests.cpp | 1 + .../Groestlcoin/TWGroestlcoinSigningTests.cpp | 4 + 6 files changed, 89 insertions(+), 44 deletions(-) diff --git a/src/Bitcoin/Script.cpp b/src/Bitcoin/Script.cpp index fcd8f383268..407a8e5152e 100644 --- a/src/Bitcoin/Script.cpp +++ b/src/Bitcoin/Script.cpp @@ -9,6 +9,7 @@ #include "OpCodes.h" #include "Script.h" #include "SegwitAddress.h" +#include #include "../BinaryCoding.h" #include "../Coin.h" @@ -291,6 +292,7 @@ void Script::encode(Data& data) const { } Script Script::lockScriptForAddress(const std::string& string, enum TWCoinType coin) { + // First try legacy address, for all coins if (Address::isValid(string)) { auto address = Address(string); auto p2pkh = TW::p2pkhPrefix(coin); @@ -301,16 +303,23 @@ Script Script::lockScriptForAddress(const std::string& string, enum TWCoinType c data.reserve(Address::size - 1); std::copy(address.bytes.begin() + 1, address.bytes.end(), std::back_inserter(data)); return buildPayToPublicKeyHash(data); - } else if (p2sh == address.bytes[0]) { + } + if (p2sh == address.bytes[0]) { // address starts with 3/M auto data = Data(); data.reserve(Address::size - 1); std::copy(address.bytes.begin() + 1, address.bytes.end(), std::back_inserter(data)); return buildPayToScriptHash(data); } - } else if (SegwitAddress::isValid(string)) { - const auto result = SegwitAddress::decode(string); - // address starts with bc/ltc + return {}; + } + + // Second, try Segwit address, for all coins; also check HRP + if (const auto result = SegwitAddress::decode(string); + std::get<2>(result) && + (std::get<1>(result) == stringForHRP(TW::hrp(coin)) || (coin == TWCoinTypeBitcoin && std::get<1>(result) == SegwitAddress::TestnetPrefix)) + ) { + // address starts with bc/ltc/... const auto address = std::get<0>(result); if (address.witnessVersion == 0) { return buildPayToV0WitnessProgram(address.witnessProgram); @@ -318,45 +327,71 @@ Script Script::lockScriptForAddress(const std::string& string, enum TWCoinType c if (address.witnessVersion == 1 && address.witnessProgram.size() == 32) { return buildPayToV1WitnessProgram(address.witnessProgram); } - } else if (BitcoinCashAddress::isValid(string)) { - auto address = BitcoinCashAddress(string); - auto bitcoinAddress = address.legacyAddress(); - return lockScriptForAddress(bitcoinAddress.string(), TWCoinTypeBitcoinCash); - } else if (Decred::Address::isValid(string)) { - auto bytes = Base58::bitcoin.decodeCheck(string, Hash::HasherBlake256d); - if (bytes[1] == TW::p2pkhPrefix(TWCoinTypeDecred)) { - return buildPayToPublicKeyHash(Data(bytes.begin() + 2, bytes.end())); - } - if (bytes[1] == TW::p2shPrefix(TWCoinTypeDecred)) { - return buildPayToScriptHash(Data(bytes.begin() + 2, bytes.end())); - } - } else if (ECashAddress::isValid(string)) { - auto address = ECashAddress(string); - auto bitcoinAddress = address.legacyAddress(); - return lockScriptForAddress(bitcoinAddress.string(), TWCoinTypeECash); - } else if (Groestlcoin::Address::isValid(string)) { - auto address = Groestlcoin::Address(string); - auto data = Data(); - data.reserve(Address::size - 1); - std::copy(address.bytes.begin() + 1, address.bytes.end(), std::back_inserter(data)); - if (address.bytes[0] == TW::p2pkhPrefix(TWCoinTypeGroestlcoin)) { - return buildPayToPublicKeyHash(data); - } - if (address.bytes[0] == TW::p2shPrefix(TWCoinTypeGroestlcoin)) { - return buildPayToScriptHash(data); - } - } else if (Zcash::TAddress::isValid(string)) { - auto address = Zcash::TAddress(string); - auto data = Data(); - data.reserve(Address::size - 2); - std::copy(address.bytes.begin() + 2, address.bytes.end(), std::back_inserter(data)); - if (address.bytes[1] == TW::p2pkhPrefix(TWCoinTypeZcash)) { - return buildPayToPublicKeyHash(data); - } else if (address.bytes[1] == TW::p2shPrefix(TWCoinTypeZcash)) { - return buildPayToScriptHash(data); - } + return {}; + } + + // Thirdly, coin-specific address formats + switch (coin) { + case TWCoinTypeBitcoinCash: + if (BitcoinCashAddress::isValid(string)) { + auto address = BitcoinCashAddress(string); + auto bitcoinAddress = address.legacyAddress(); + return lockScriptForAddress(bitcoinAddress.string(), TWCoinTypeBitcoinCash); + } + return {}; + + case TWCoinTypeDecred: + if (Decred::Address::isValid(string)) { + auto bytes = Base58::bitcoin.decodeCheck(string, Hash::HasherBlake256d); + if (bytes[1] == TW::p2pkhPrefix(TWCoinTypeDecred)) { + return buildPayToPublicKeyHash(Data(bytes.begin() + 2, bytes.end())); + } + if (bytes[1] == TW::p2shPrefix(TWCoinTypeDecred)) { + return buildPayToScriptHash(Data(bytes.begin() + 2, bytes.end())); + } + } + return {}; + + case TWCoinTypeECash: + if (ECashAddress::isValid(string)) { + auto address = ECashAddress(string); + auto bitcoinAddress = address.legacyAddress(); + return lockScriptForAddress(bitcoinAddress.string(), TWCoinTypeECash); + } + return {}; + + case TWCoinTypeGroestlcoin: + if (Groestlcoin::Address::isValid(string)) { + auto address = Groestlcoin::Address(string); + auto data = Data(); + data.reserve(Address::size - 1); + std::copy(address.bytes.begin() + 1, address.bytes.end(), std::back_inserter(data)); + if (address.bytes[0] == TW::p2pkhPrefix(TWCoinTypeGroestlcoin)) { + return buildPayToPublicKeyHash(data); + } + if (address.bytes[0] == TW::p2shPrefix(TWCoinTypeGroestlcoin)) { + return buildPayToScriptHash(data); + } + } + return {}; + + case TWCoinTypeZcash: + if (Zcash::TAddress::isValid(string)) { + auto address = Zcash::TAddress(string); + auto data = Data(); + data.reserve(Address::size - 2); + std::copy(address.bytes.begin() + 2, address.bytes.end(), std::back_inserter(data)); + if (address.bytes[1] == TW::p2pkhPrefix(TWCoinTypeZcash)) { + return buildPayToPublicKeyHash(data); + } else if (address.bytes[1] == TW::p2shPrefix(TWCoinTypeZcash)) { + return buildPayToScriptHash(data); + } + } + return {}; + + default: + return {}; } - return {}; } } // namespace TW::Bitcoin diff --git a/swift/Tests/Blockchains/GroestlcoinTransactionSignerTests.swift b/swift/Tests/Blockchains/GroestlcoinTransactionSignerTests.swift index 09bdb7119ee..58ab98538a9 100644 --- a/swift/Tests/Blockchains/GroestlcoinTransactionSignerTests.swift +++ b/swift/Tests/Blockchains/GroestlcoinTransactionSignerTests.swift @@ -14,6 +14,7 @@ class GroestlcoinTransactionSignerTests: XCTestCase { func testSignP2WPKH() throws { var input = BitcoinSigningInput.with { + $0.coinType = CoinType.groestlcoin.rawValue $0.hashType = BitcoinScript.hashTypeForCoin(coinType: .groestlcoin) $0.amount = 2500 $0.byteFee = 1 @@ -67,6 +68,7 @@ class GroestlcoinTransactionSignerTests: XCTestCase { func testSignP2PKH() throws { var input = BitcoinSigningInput.with { + $0.coinType = CoinType.groestlcoin.rawValue $0.hashType = BitcoinScript.hashTypeForCoin(coinType: .groestlcoin) $0.amount = 2500 $0.byteFee = 1 @@ -118,6 +120,7 @@ class GroestlcoinTransactionSignerTests: XCTestCase { func testSignP2SH_P2WPKH() throws { var input = BitcoinSigningInput.with { + $0.coinType = CoinType.groestlcoin.rawValue $0.hashType = BitcoinScript.hashTypeForCoin(coinType: .groestlcoin) $0.amount = 5000 $0.byteFee = 1 diff --git a/tests/chains/Bitcoin/TWBitcoinScriptTests.cpp b/tests/chains/Bitcoin/TWBitcoinScriptTests.cpp index 2f9a3e1ad29..9d1aa7f4ce0 100644 --- a/tests/chains/Bitcoin/TWBitcoinScriptTests.cpp +++ b/tests/chains/Bitcoin/TWBitcoinScriptTests.cpp @@ -210,11 +210,11 @@ TEST(TWBitcoinScript, LockScriptForP2WSHAddress) { } TEST(TWBitcoinScript, LockScriptForCashAddress) { - auto script = WRAP(TWBitcoinScript, TWBitcoinScriptLockScriptForAddress(STRING("bitcoincash:pzclklsyx9f068hd00a0vene45akeyrg7vv0053uqf").get(), TWCoinTypeBitcoin)); + auto script = WRAP(TWBitcoinScript, TWBitcoinScriptLockScriptForAddress(STRING("bitcoincash:pzclklsyx9f068hd00a0vene45akeyrg7vv0053uqf").get(), TWCoinTypeBitcoinCash)); auto scriptData = WRAPD(TWBitcoinScriptData(script.get())); assertHexEqual(scriptData, "a914b1fb7e043152fd1eed7bfaf66679ad3b6c9068f387"); - auto script2 = WRAP(TWBitcoinScript, TWBitcoinScriptLockScriptForAddress(STRING("bitcoincash:qpk05r5kcd8uuzwqunn8rlx5xvuvzjqju5rch3tc0u").get(), TWCoinTypeBitcoin)); + auto script2 = WRAP(TWBitcoinScript, TWBitcoinScriptLockScriptForAddress(STRING("bitcoincash:qpk05r5kcd8uuzwqunn8rlx5xvuvzjqju5rch3tc0u").get(), TWCoinTypeBitcoinCash)); auto scriptData2 = WRAPD(TWBitcoinScriptData(script2.get())); assertHexEqual(scriptData2, "76a9146cfa0e96c34fce09c0e4e671fcd43338c14812e588ac"); } diff --git a/tests/chains/DigiByte/TWDigiByteTests.cpp b/tests/chains/DigiByte/TWDigiByteTests.cpp index c824018607c..1c40d8815a9 100644 --- a/tests/chains/DigiByte/TWDigiByteTests.cpp +++ b/tests/chains/DigiByte/TWDigiByteTests.cpp @@ -32,6 +32,7 @@ TEST(DigiByteTransaction, SignTransaction) { const int64_t fee = 1000; auto input = Bitcoin::Proto::SigningInput(); + input.set_coin_type(TWCoinTypeDigiByte); input.set_hash_type(TWBitcoinSigHashTypeAll); input.set_amount(amount); input.set_byte_fee(1); @@ -98,6 +99,7 @@ TEST(DigiByteTransaction, SignP2WPKH) { const int64_t amount = 2000000; Proto::SigningInput input; + input.set_coin_type(TWCoinTypeDigiByte); input.set_hash_type(TWBitcoinSigHashTypeAll); input.set_amount(amount); input.set_byte_fee(1); diff --git a/tests/chains/ECash/TWECashTests.cpp b/tests/chains/ECash/TWECashTests.cpp index f258e4a4816..bd9f5738b3b 100644 --- a/tests/chains/ECash/TWECashTests.cpp +++ b/tests/chains/ECash/TWECashTests.cpp @@ -124,6 +124,7 @@ TEST(ECash, SignTransaction) { // https://blockchair.com/ecash/transaction/96ee20002b34e468f9d3c5ee54f6a8ddaa61c118889c4f35395c2cd93ba5bbb4 auto input = Proto::SigningInput(); + input.set_coin_type(TWCoinTypeECash); input.set_hash_type(hashTypeForCoin(TWCoinTypeECash)); input.set_amount(amount); input.set_byte_fee(1); diff --git a/tests/chains/Groestlcoin/TWGroestlcoinSigningTests.cpp b/tests/chains/Groestlcoin/TWGroestlcoinSigningTests.cpp index 994c8977942..4134ab277f7 100644 --- a/tests/chains/Groestlcoin/TWGroestlcoinSigningTests.cpp +++ b/tests/chains/Groestlcoin/TWGroestlcoinSigningTests.cpp @@ -22,6 +22,7 @@ namespace TW::Bitcoin { TEST(GroestlcoinSigning, SignP2WPKH) { Proto::SigningInput input; + input.set_coin_type(TWCoinTypeGroestlcoin); input.set_hash_type(TWBitcoinSigHashTypeAll); input.set_amount(2500); input.set_byte_fee(1); @@ -64,6 +65,7 @@ TEST(GroestlcoinSigning, SignP2WPKH) { TEST(GroestlcoinSigning, SignP2PKH) { Proto::SigningInput input; + input.set_coin_type(TWCoinTypeGroestlcoin); input.set_hash_type(TWBitcoinSigHashTypeAll); input.set_amount(2500); input.set_byte_fee(1); @@ -107,6 +109,7 @@ TEST(GroestlcoinSigning, SignP2PKH) { TEST(GroestlcoinSigning, SignP2SH_P2WPKH) { // TX outputs Proto::SigningInput input; + input.set_coin_type(TWCoinTypeGroestlcoin); input.set_hash_type(TWBitcoinSigHashTypeAll); input.set_amount(5'000); input.set_byte_fee(1); @@ -159,6 +162,7 @@ TEST(GroestlcoinSigning, SignP2SH_P2WPKH) { TEST(GroestlcoinSigning, PlanP2WPKH) { Proto::SigningInput input; + input.set_coin_type(TWCoinTypeGroestlcoin); input.set_hash_type(TWBitcoinSigHashTypeAll); input.set_amount(2500); input.set_byte_fee(1); From 2f49d26071f32cfa34e3e73257c5bce8735b30cb Mon Sep 17 00:00:00 2001 From: Ayush Bherwani Date: Mon, 9 Jan 2023 14:52:09 +0530 Subject: [PATCH 164/497] Native Injective integration (#2828) * add basic implementation of injective * add swift tests * add cpp tests --- .../blockchains/CoinAddressDerivationTests.kt | 1 + .../TestNativeInjectiveAddress.kt | 29 ++++++++ .../TestNativeInjectiveSigner.kt | 69 +++++++++++++++++++ docs/registry.md | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 30 ++++++++ src/Cosmos/Protobuf/injective_keys.proto | 6 ++ src/Cosmos/ProtobufSerialization.cpp | 8 +++ .../Blockchains/NativeInjectiveTests.swift | 59 ++++++++++++++++ swift/Tests/CoinAddressDerivationTests.swift | 3 + tests/chains/NativeInjective/SignerTests.cpp | 55 +++++++++++++++ .../NativeInjective/TWAnyAddressTests.cpp | 20 ++++++ .../NativeInjective/TWCoinTypeTests.cpp | 37 ++++++++++ tests/common/CoinAddressDerivationTests.cpp | 3 + 14 files changed, 322 insertions(+) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveAddress.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveSigner.kt create mode 100644 src/Cosmos/Protobuf/injective_keys.proto create mode 100644 swift/Tests/Blockchains/NativeInjectiveTests.swift create mode 100644 tests/chains/NativeInjective/SignerTests.cpp create mode 100644 tests/chains/NativeInjective/TWAnyAddressTests.cpp create mode 100644 tests/chains/NativeInjective/TWCoinTypeTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index b3384921873..4e49c45c43e 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -108,6 +108,7 @@ class CoinAddressDerivationTests { APTOS -> assertEquals("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", address) HEDERA -> assertEquals("0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5", address) SECRET -> assertEquals("secret1f69sk5033zcdr2p2yf3xjehn7xvgdeq09d2llh", address) + NATIVEINJECTIVE -> assertEquals("inj13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a", address) AGORIC -> assertEquals("agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5", address) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveAddress.kt new file mode 100644 index 00000000000..fc0a81474eb --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveAddress.kt @@ -0,0 +1,29 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.nativeinjective + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestNativeInjectiveAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("9ee18daf8e463877aaf497282abc216852420101430482a28e246c179e2c5ef1".toHexByteArray()) + val pubKey = key.getPublicKeySecp256k1(false) + val address = AnyAddress(pubKey, CoinType.NATIVEINJECTIVE) + val expected = AnyAddress("inj13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a", CoinType.NATIVEINJECTIVE) + + assertEquals(address.description(), expected.description()) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveSigner.kt new file mode 100644 index 00000000000..2474fb37899 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/nativeinjective/TestNativeInjectiveSigner.kt @@ -0,0 +1,69 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.nativeinjective + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.AnyAddress +import wallet.core.jni.CoinType +import wallet.core.jni.PrivateKey +import wallet.core.jni.proto.Cosmos + +class TestNativeInjectiveSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun NativeInjectiveTransactionSigning() { + val key = PrivateKey("9ee18daf8e463877aaf497282abc216852420101430482a28e246c179e2c5ef1".toHexByteArray()) + val publicKey = key.getPublicKeySecp256k1(false) + val from = AnyAddress(publicKey, CoinType.NATIVEINJECTIVE).description() + + val transferAmount = Cosmos.Amount.newBuilder().apply { + amount = "10000000000" + denom = "inj" + }.build() + + val message = Cosmos.Message.newBuilder().apply { + sendCoinsMessage = Cosmos.Message.Send.newBuilder().apply { + fromAddress = from + toAddress = "inj1xmpkmxr4as00em23tc2zgmuyy2gr4h3wgcl6vd" + addAllAmounts(listOf(transferAmount)) + }.build() + }.build() + + val feeAmount = Cosmos.Amount.newBuilder().apply { + amount = "100000000000000" + denom = "inj" + }.build() + + val transferFee = Cosmos.Fee.newBuilder().apply { + gas = 110000 + addAllAmounts(listOf(feeAmount)) + }.build() + + val signingInput = Cosmos.SigningInput.newBuilder().apply { + signingMode = Cosmos.SigningMode.Protobuf + accountNumber = 17396 + chainId = "injective-1" + sequence = 1 + fee = transferFee + privateKey = ByteString.copyFrom(key.data()) + addAllMessages(listOf(message)) + }.build() + + val output = AnySigner.sign(signingInput, CoinType.NATIVEINJECTIVE, Cosmos.SigningOutput.parser()) + + // https://www.mintscan.io/injective/txs/135DD2C4A1910E4334A9C0F15125DA992E724EBF23FEB9638FCB71218BB064A5 + assertEquals(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"Co8BCowBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmwKKmluajEzdTZnN3ZxZ3cwNzRtZ21mMnplMmNhZHp2a3o5c25sd2NydHE4YRIqaW5qMXhtcGtteHI0YXMwMGVtMjN0YzJ6Z211eXkyZ3I0aDN3Z2NsNnZkGhIKA2luahILMTAwMDAwMDAwMDASfgpeClQKLS9pbmplY3RpdmUuY3J5cHRvLnYxYmV0YTEuZXRoc2VjcDI1NmsxLlB1YktleRIjCiEDWgxrg7i9mCflBycMrbSZt+OpCVJG9qIhMoH3g9h3yYsSBAoCCAEYARIcChYKA2luahIPMTAwMDAwMDAwMDAwMDAwELDbBhpArNDBBEwHVKwuSDozLIwvOOhDQ/i7bXC6Av5ZefSQf7RS2ejrapX/JKXPsYrtMWadhKCedomODhujvWzzGwmXVA==\"}") + } +} diff --git a/docs/registry.md b/docs/registry.md index 0d9e425c1d1..3c06e890867 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -78,6 +78,7 @@ This list is generated from [./registry.json](../registry.json) | 5718350 | Wanchain | WAN | | | | 5741564 | Waves | WAVES | | | | 10000025 | Cronos Chain | CRO | | | +| 10000060 | Native Injective | INJ | | | | 10000070 | Optimism Ethereum | ETH | | | | 10000100 | Gnosis Chain | xDAI | | | | 10000118 | Osmosis | OSMO | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index cb196d5920b..6bd2e78b158 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -126,6 +126,7 @@ enum TWCoinType { TWCoinTypeAptos = 637, TWCoinTypeHedera = 3030, TWCoinTypeSecret = 529, + TWCoinTypeNativeInjective = 10000060, TWCoinTypeAgoric = 564, }; diff --git a/registry.json b/registry.json index fabf45f3b5b..8d4d9d7f67d 100644 --- a/registry.json +++ b/registry.json @@ -2911,5 +2911,35 @@ "rpc": "https://agoric-rpc.polkachu.com", "documentation": "https://docs.agoric.com" } + }, + { + "id": "nativeinjective", + "name": "NativeInjective", + "displayName": "Native Injective", + "coinId": 10000060, + "symbol": "INJ", + "decimals": 18, + "blockchain": "Cosmos", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "hrp": "inj", + "addressHasher": "keccak256", + "chainId": "injective-1", + "explorer": { + "url": "https://www.mintscan.io/injective", + "txPath": "/txs/", + "accountPath": "/account/", + "sampleTx": "C5F6A4FF9DF1AE9FF543D2CEBD8E3E9B04290B2445F9D91D7707EDBF4B7EE16B", + "sampleAccount": "inj1xmpkmxr4as00em23tc2zgmuyy2gr4h3wgcl6vd" + }, + "info": { + "url": "https://injective.com", + "documentation": "https://docs.injective.network" + } } ] diff --git a/src/Cosmos/Protobuf/injective_keys.proto b/src/Cosmos/Protobuf/injective_keys.proto new file mode 100644 index 00000000000..bc11f94d667 --- /dev/null +++ b/src/Cosmos/Protobuf/injective_keys.proto @@ -0,0 +1,6 @@ +syntax = "proto3"; +package injective.crypto.v1beta1.ethsecp256k1; + +message PubKey { + bytes key = 1; +} diff --git a/src/Cosmos/ProtobufSerialization.cpp b/src/Cosmos/ProtobufSerialization.cpp index e2f2e070890..89eff73b63c 100644 --- a/src/Cosmos/ProtobufSerialization.cpp +++ b/src/Cosmos/ProtobufSerialization.cpp @@ -20,6 +20,7 @@ #include "Protobuf/terra_wasm_v1beta1_tx.pb.h" #include "Protobuf/thorchain_bank_tx.pb.h" #include "Protobuf/ethermint_keys.pb.h" +#include "Protobuf/injective_keys.pb.h" #include "PrivateKey.h" #include "Data.h" @@ -335,6 +336,12 @@ std::string buildAuthInfo(const Proto::SigningInput& input, TWCoinType coin) { signerInfo->mutable_public_key()->PackFrom(pubKey, ProtobufAnyNamespacePrefix); break; } + case TWCoinTypeNativeInjective: { + auto pubKey = injective::crypto::v1beta1::ethsecp256k1::PubKey(); + pubKey.set_key(publicKey.bytes.data(), publicKey.bytes.size()); + signerInfo->mutable_public_key()->PackFrom(pubKey, ProtobufAnyNamespacePrefix); + break; + } default: { auto pubKey = cosmos::crypto::secp256k1::PubKey(); pubKey.set_key(publicKey.bytes.data(), publicKey.bytes.size()); @@ -365,6 +372,7 @@ Data buildSignature(const Proto::SigningInput& input, const std::string& seriali Data hashToSign; switch(coin) { + case TWCoinTypeNativeInjective: case TWCoinTypeNativeEvmos: { hashToSign = Hash::keccak256(serializedSignDoc); break; diff --git a/swift/Tests/Blockchains/NativeInjectiveTests.swift b/swift/Tests/Blockchains/NativeInjectiveTests.swift new file mode 100644 index 00000000000..6a95b53e85f --- /dev/null +++ b/swift/Tests/Blockchains/NativeInjectiveTests.swift @@ -0,0 +1,59 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import WalletCore +import XCTest + +class NativeInjectiveTests: XCTestCase { + + func testAddress() { + let key = PrivateKey(data: Data(hexString: "9ee18daf8e463877aaf497282abc216852420101430482a28e246c179e2c5ef1")!)! + let pubkey = key.getPublicKeySecp256k1(compressed: false) + let address = AnyAddress(publicKey: pubkey, coin: .nativeInjective) + let addressFromString = AnyAddress(string: "inj13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a", coin: .nativeInjective)! + + XCTAssertEqual(address.description, addressFromString.description) + } + + func testSign() { + let privateKey = PrivateKey(data: Data(hexString: "9ee18daf8e463877aaf497282abc216852420101430482a28e246c179e2c5ef1")!)! + let publicKey = privateKey.getPublicKeySecp256k1(compressed: false) + let fromAddress = AnyAddress(publicKey: publicKey, coin: .nativeInjective) + + let message = CosmosMessage.with { + $0.sendCoinsMessage = CosmosMessage.Send.with { + $0.fromAddress = fromAddress.description + $0.toAddress = "inj1xmpkmxr4as00em23tc2zgmuyy2gr4h3wgcl6vd" + $0.amounts = [CosmosAmount.with { + $0.amount = "10000000000" + $0.denom = "inj" + }] + } + } + + let fee = CosmosFee.with { + $0.gas = 110000 + $0.amounts = [CosmosAmount.with { + $0.amount = "100000000000000" + $0.denom = "inj" + }] + } + + let input = CosmosSigningInput.with { + $0.signingMode = .protobuf; + $0.accountNumber = 17396 + $0.chainID = "injective-1" + $0.sequence = 1 + $0.messages = [message] + $0.fee = fee + $0.privateKey = privateKey.data + } + + let output: CosmosSigningOutput = AnySigner.sign(input: input, coin: .nativeInjective) + + XCTAssertJSONEqual(output.serialized, "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"Co8BCowBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmwKKmluajEzdTZnN3ZxZ3cwNzRtZ21mMnplMmNhZHp2a3o5c25sd2NydHE4YRIqaW5qMXhtcGtteHI0YXMwMGVtMjN0YzJ6Z211eXkyZ3I0aDN3Z2NsNnZkGhIKA2luahILMTAwMDAwMDAwMDASfgpeClQKLS9pbmplY3RpdmUuY3J5cHRvLnYxYmV0YTEuZXRoc2VjcDI1NmsxLlB1YktleRIjCiEDWgxrg7i9mCflBycMrbSZt+OpCVJG9qIhMoH3g9h3yYsSBAoCCAEYARIcChYKA2luahIPMTAwMDAwMDAwMDAwMDAwELDbBhpArNDBBEwHVKwuSDozLIwvOOhDQ/i7bXC6Av5ZefSQf7RS2ejrapX/JKXPsYrtMWadhKCedomODhujvWzzGwmXVA==\"}") + } +} diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index d839b605452..6b5a84791be 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -262,6 +262,9 @@ class CoinAddressDerivationTests: XCTestCase { case .secret: let expectedResult = "secret1f69sk5033zcdr2p2yf3xjehn7xvgdeq09d2llh" assertCoinDerivation(coin, expectedResult, derivedAddress, address) + case .nativeInjective: + let expectedResult = "inj13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a" + assertCoinDerivation(coin, expectedResult, derivedAddress, address) case .agoric: let expectedResult = "agoric18zvvgk6j3eq5wd7mqxccgt20gz2w94cy88aek5" assertCoinDerivation(coin, expectedResult, derivedAddress, address) diff --git a/tests/chains/NativeInjective/SignerTests.cpp b/tests/chains/NativeInjective/SignerTests.cpp new file mode 100644 index 00000000000..68b8789a1d2 --- /dev/null +++ b/tests/chains/NativeInjective/SignerTests.cpp @@ -0,0 +1,55 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "Base64.h" +#include "proto/Cosmos.pb.h" +#include "Cosmos/Address.h" +#include "Cosmos/Signer.h" +#include "TestUtilities.h" +#include + +#include +#include + +namespace TW::Cosmos::nativeInjective::tests { + +TEST(NativeInjectiveSigner, Sign) { + auto input = Proto::SigningInput(); + input.set_signing_mode(Proto::Protobuf); + input.set_account_number(17396); + input.set_chain_id("injective-1"); + input.set_sequence(1); + + Address fromAddress; + Address toAddress; + EXPECT_TRUE(Address::decode("inj13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a", fromAddress)); + EXPECT_TRUE(Address::decode("inj1xmpkmxr4as00em23tc2zgmuyy2gr4h3wgcl6vd", toAddress)); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_send_coins_message(); + message.set_from_address(fromAddress.string()); + message.set_to_address(toAddress.string()); + auto amountOfTx = message.add_amounts(); + amountOfTx->set_denom("inj"); + amountOfTx->set_amount("10000000000"); + + auto& fee = *input.mutable_fee(); + fee.set_gas(110000); + auto amountOfFee = fee.add_amounts(); + amountOfFee->set_denom("inj"); + amountOfFee->set_amount("100000000000000"); + + auto privateKey = parse_hex("9ee18daf8e463877aaf497282abc216852420101430482a28e246c179e2c5ef1"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input, TWCoinTypeNativeInjective); + + // https://www.mintscan.io/injective/txs/135DD2C4A1910E4334A9C0F15125DA992E724EBF23FEB9638FCB71218BB064A5 + assertJSONEqual(output.serialized(), "{\"tx_bytes\":\"Co8BCowBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmwKKmluajEzdTZnN3ZxZ3cwNzRtZ21mMnplMmNhZHp2a3o5c25sd2NydHE4YRIqaW5qMXhtcGtteHI0YXMwMGVtMjN0YzJ6Z211eXkyZ3I0aDN3Z2NsNnZkGhIKA2luahILMTAwMDAwMDAwMDASfgpeClQKLS9pbmplY3RpdmUuY3J5cHRvLnYxYmV0YTEuZXRoc2VjcDI1NmsxLlB1YktleRIjCiEDWgxrg7i9mCflBycMrbSZt+OpCVJG9qIhMoH3g9h3yYsSBAoCCAEYARIcChYKA2luahIPMTAwMDAwMDAwMDAwMDAwELDbBhpArNDBBEwHVKwuSDozLIwvOOhDQ/i7bXC6Av5ZefSQf7RS2ejrapX/JKXPsYrtMWadhKCedomODhujvWzzGwmXVA==\",\"mode\":\"BROADCAST_MODE_BLOCK\"}"); +} + +} diff --git a/tests/chains/NativeInjective/TWAnyAddressTests.cpp b/tests/chains/NativeInjective/TWAnyAddressTests.cpp new file mode 100644 index 00000000000..d2f2395ccd5 --- /dev/null +++ b/tests/chains/NativeInjective/TWAnyAddressTests.cpp @@ -0,0 +1,20 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include "HexCoding.h" + +#include "TestUtilities.h" +#include + +using namespace TW; + +TEST(TWNativeInjective, Address) { + auto string = STRING("inj1xmpkmxr4as00em23tc2zgmuyy2gr4h3wgcl6vd"); + auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithString(string.get(), TWCoinTypeNativeInjective)); + auto string2 = WRAPS(TWAnyAddressDescription(addr.get())); + EXPECT_TRUE(TWStringEqual(string.get(), string2.get())); +} diff --git a/tests/chains/NativeInjective/TWCoinTypeTests.cpp b/tests/chains/NativeInjective/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..15405de06e9 --- /dev/null +++ b/tests/chains/NativeInjective/TWCoinTypeTests.cpp @@ -0,0 +1,37 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "TestUtilities.h" +#include +#include + + +TEST(TWNativeInjectiveCoinType, TWCoinType) { + const auto coin = TWCoinTypeNativeInjective; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto chainId = WRAPS(TWCoinTypeChainId(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("C5F6A4FF9DF1AE9FF543D2CEBD8E3E9B04290B2445F9D91D7707EDBF4B7EE16B")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("inj1xmpkmxr4as00em23tc2zgmuyy2gr4h3wgcl6vd")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "nativeinjective"); + assertStringsEqual(name, "Native Injective"); + assertStringsEqual(symbol, "INJ"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 18); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainCosmos); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); + assertStringsEqual(chainId, "injective-1"); + assertStringsEqual(txUrl, "https://www.mintscan.io/injective/txs/C5F6A4FF9DF1AE9FF543D2CEBD8E3E9B04290B2445F9D91D7707EDBF4B7EE16B"); + assertStringsEqual(accUrl, "https://www.mintscan.io/injective/account/inj1xmpkmxr4as00em23tc2zgmuyy2gr4h3wgcl6vd"); +} diff --git a/tests/common/CoinAddressDerivationTests.cpp b/tests/common/CoinAddressDerivationTests.cpp index 64d792feea9..167041878b2 100644 --- a/tests/common/CoinAddressDerivationTests.cpp +++ b/tests/common/CoinAddressDerivationTests.cpp @@ -258,6 +258,9 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeSecret: EXPECT_EQ(address, "secret1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0m7t23a"); break; + case TWCoinTypeNativeInjective: + EXPECT_EQ(address, "inj1nk9x9ajk4rgkzhqjjn7hr6w0k0jg2kj0knl55v"); + break; case TWCoinTypeAgoric: EXPECT_EQ(address, "agoric1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0txauuh"); break; From e15919afd85d1bfe38295e2c216b2fac9a032363 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 9 Jan 2023 12:58:55 +0100 Subject: [PATCH 165/497] misc(CODEOWNERS): update CODEOWNERS (#2861) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 707fa9c11ea..61760e1454c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,4 +3,4 @@ # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @hewigovens @catenocrypt @milerius @miloserdow +* @hewigovens @catenocrypt @milerius From c452dc7554516ecdcb88a9bedcb4096bb1cf8b9a Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 10 Jan 2023 11:12:11 +0100 Subject: [PATCH 166/497] feat(thorswap): SWAP from atom support (#2860) --- src/THORChain/Swap.cpp | 37 ++++++++++++++++++++ src/THORChain/Swap.h | 4 ++- tests/chains/THORChain/SwapTests.cpp | 51 ++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/THORChain/Swap.cpp b/src/THORChain/Swap.cpp index e23c4ec999a..0371c6dfc61 100644 --- a/src/THORChain/Swap.cpp +++ b/src/THORChain/Swap.cpp @@ -9,6 +9,9 @@ #include "Coin.h" #include +// ATOM +#include "Cosmos/Address.h" +#include "../proto/Cosmos.pb.h" // BTC #include "Bitcoin/SigHashType.h" #include "../proto/Bitcoin.pb.h" @@ -56,6 +59,8 @@ TWCoinType chainCoinType(Chain chain) { return TWCoinTypeBitcoinCash; case Chain::LTC: return TWCoinTypeLitecoin; + case Chain::ATOM: + return TWCoinTypeCosmos; case Chain::THOR: default: return TWCoinTypeTHORChain; @@ -76,6 +81,8 @@ std::string chainName(Chain chain) { return "BCH"; case Chain::LTC: return "LTC"; + case Chain::ATOM: + return "ATOM"; case Chain::THOR: default: return "THOR"; @@ -108,6 +115,8 @@ SwapBundled SwapBuilder::build(bool shortened) { return buildBitcoin(fromAmountNum, memo, fromChain); case Chain::BNB: return buildBinance(mFromAsset, fromAmountNum, memo); + case Chain::ATOM: + return buildAtom(fromAmountNum, memo); case Chain::ETH: return buildEth(fromAmountNum, memo); } @@ -254,4 +263,32 @@ SwapBundled SwapBuilder::buildEth(uint64_t amount, const std::string& memo) { out.insert(out.end(), serialized.begin(), serialized.end()); return {.out = std::move(out)}; } + +SwapBundled SwapBuilder::buildAtom(uint64_t amount, const std::string& memo) { + if (!Cosmos::Address::isValid(mVaultAddress, "cosmos")) { + return {.status_code = static_cast(Proto::ErrorCode::Error_Invalid_vault_address), .error = "Invalid vault address: " + mVaultAddress}; + } + Data out; + + auto input = Cosmos::Proto::SigningInput(); + input.set_signing_mode(Cosmos::Proto::Protobuf); + input.set_chain_id("cosmoshub-4"); + input.set_memo(memo); + + auto msg = input.add_messages(); + auto& message = *msg->mutable_send_coins_message(); + + message.set_from_address(mFromAddress); + message.set_to_address(mVaultAddress); + + auto amountOfTx = message.add_amounts(); + amountOfTx->set_denom("uatom"); + amountOfTx->set_amount(std::to_string(amount)); + + auto serialized = input.SerializeAsString(); + out.insert(out.end(), serialized.begin(), serialized.end()); + + return {.out = std::move(out)}; +} + } // namespace TW::THORChainSwap diff --git a/src/THORChain/Swap.h b/src/THORChain/Swap.h index 504553567ef..aca8ce154aa 100644 --- a/src/THORChain/Swap.h +++ b/src/THORChain/Swap.h @@ -23,7 +23,8 @@ enum Chain { BNB = 3, DOGE = 4, BCH = 5, - LTC = 6 + LTC = 6, + ATOM = 7 }; using SwapErrorCode = int; @@ -50,6 +51,7 @@ class SwapBuilder { SwapBundled buildBitcoin(uint64_t amount, const std::string& memo, Chain fromChain); SwapBundled buildBinance(Proto::Asset fromAsset, uint64_t amount, const std::string& memo); SwapBundled buildEth(uint64_t amount, const std::string& memo); + SwapBundled buildAtom(uint64_t amount, const std::string& memo); public: SwapBuilder() noexcept = default; diff --git a/tests/chains/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp index 54bb152bb3c..1c0a86ec1a4 100644 --- a/tests/chains/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -13,6 +13,7 @@ #include "Ethereum/Address.h" #include "THORChain/Swap.h" #include "proto/Binance.pb.h" +#include "proto/Cosmos.pb.h" #include "proto/Bitcoin.pb.h" #include "proto/Ethereum.pb.h" #include "proto/THORChainSwap.pb.h" @@ -373,6 +374,56 @@ TEST(THORChainSwap, SwapBtcBnb) { // https://explorer.binance.org/tx/8D78469069118E9B9546696214CCD46E63D3FA0D7E854C094D63C8F6061278B7 } +TEST(THORChainSwap, SwapAtomBnb) { + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::ATOM)); + fromAsset.set_symbol("ATOM"); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BNB)); + toAsset.set_symbol("BNB"); + + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress("cosmos1v4e6vpehwrfez2dqepnw9g6t4fl83xzegd5ac9") + .toAddress("bnb1s4kallxngpyspzm6nrezkml9rgyw6kxpw4fhr2") + .vault("cosmos154t5ycejlr7ax3ynmed9z05yg5a27y9u6pj5hq") + .fromAmount("300000") + .toAmountLimit("819391") + .affFeeAddress("t") + .affFeeRate("0") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "08011a0b636f736d6f736875622d342a3f3d3a424e422e424e423a626e623173346b616c6c786e67707973707a6d366e72657a6b6d6c3972677977366b78707734666872323a3831393339313a743a3042710a6f0a2d636f736d6f73317634653676706568777266657a32647165706e773967367434666c3833787a65676435616339122d636f736d6f7331353474357963656a6c7237617833796e6d6564397a303579673561323779397536706a3568711a0f0a057561746f6d1206333030303030"); + + auto tx = Cosmos::Proto::SigningInput(); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); + ASSERT_EQ(tx.memo(), "=:BNB.BNB:bnb1s4kallxngpyspzm6nrezkml9rgyw6kxpw4fhr2:819391:t:0"); + + auto& fee = *tx.mutable_fee(); + fee.set_gas(200000); + auto& fee_amount = *fee.add_amounts(); + fee_amount.set_denom("uatom"); + fee_amount.set_amount("500"); + + + tx.set_account_number(1483163); + tx.set_sequence(1); + + auto privKey = parse_hex("3eed3f32b8ba90e579ba46f37e7445fb4b34558306aa5bc32c525a93dff486e7"); + tx.set_private_key(privKey.data(), privKey.size()); + + Cosmos::Proto::SigningOutput output; + ANY_SIGN(tx, TWCoinTypeCosmos); + EXPECT_EQ(output.error(), ""); + ASSERT_EQ(output.serialized(), "{\"mode\":\"BROADCAST_MODE_BLOCK\",\"tx_bytes\":\"CtMBCo8BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm8KLWNvc21vczF2NGU2dnBlaHdyZmV6MmRxZXBudzlnNnQ0Zmw4M3h6ZWdkNWFjORItY29zbW9zMTU0dDV5Y2VqbHI3YXgzeW5tZWQ5ejA1eWc1YTI3eTl1NnBqNWhxGg8KBXVhdG9tEgYzMDAwMDASPz06Qk5CLkJOQjpibmIxczRrYWxseG5ncHlzcHptNm5yZXprbWw5cmd5dzZreHB3NGZocjI6ODE5MzkxOnQ6MBJmClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDmmNIYBvR9bnOloFEMOWdk9DHYIGe7naW0T19y+/k1SUSBAoCCAEYARISCgwKBXVhdG9tEgM1MDAQwJoMGkCFqUWtDu0pn1P/cnVQnIJIWF8HFJn/xkJh55Mc7ZLVPF60uXYUOg8nNkt0IQPuTFREw32/yff6lmA5w6KwPen/\"}"); + + // https://viewblock.io/thorchain/tx/07F47D71A74245538E205F24ADB4BBB799B49C3A8A8875665D249EA51662AA50 + // https://www.mintscan.io/cosmos/txs/07F47D71A74245538E205F24ADB4BBB799B49C3A8A8875665D249EA51662AA50 + // https://binance.mintscan.io/txs/2C97061737B16B234990B9B18A2BF65F7C7418FF9E39A68E634C832E4E4C59CE +} + Data SwapTest_ethAddressStringToData(const std::string& asString) { if (asString.empty()) { return Data(); From 7a372b216b29d3c025e4769515a56c9f14bfa5fe Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 11 Jan 2023 08:37:39 +0100 Subject: [PATCH 167/497] feat(thorswap): add full avax support (#2864) --- src/THORChain/Swap.cpp | 5 +++ src/THORChain/Swap.h | 3 +- tests/chains/THORChain/SwapTests.cpp | 62 ++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/THORChain/Swap.cpp b/src/THORChain/Swap.cpp index 0371c6dfc61..8cf5c44be2d 100644 --- a/src/THORChain/Swap.cpp +++ b/src/THORChain/Swap.cpp @@ -49,6 +49,8 @@ TWCoinType chainCoinType(Chain chain) { switch (chain) { case Chain::ETH: return TWCoinTypeEthereum; + case Chain::AVAX: + return TWCoinTypeAvalancheCChain; case Chain::BNB: return TWCoinTypeBinance; case Chain::BTC: @@ -69,6 +71,8 @@ TWCoinType chainCoinType(Chain chain) { std::string chainName(Chain chain) { switch (chain) { + case Chain::AVAX: + return "AVAX"; case Chain::ETH: return "ETH"; case Chain::BNB: @@ -118,6 +122,7 @@ SwapBundled SwapBuilder::build(bool shortened) { case Chain::ATOM: return buildAtom(fromAmountNum, memo); case Chain::ETH: + case Chain::AVAX: return buildEth(fromAmountNum, memo); } default: diff --git a/src/THORChain/Swap.h b/src/THORChain/Swap.h index aca8ce154aa..b8bedea7a76 100644 --- a/src/THORChain/Swap.h +++ b/src/THORChain/Swap.h @@ -24,7 +24,8 @@ enum Chain { DOGE = 4, BCH = 5, LTC = 6, - ATOM = 7 + ATOM = 7, + AVAX = 8 }; using SwapErrorCode = int; diff --git a/tests/chains/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp index 1c0a86ec1a4..2ecd1094172 100644 --- a/tests/chains/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -499,6 +499,68 @@ TEST(THORChainSwap, SwapErc20Rune) { // https://viewblock.io/thorchain/tx/BC1464CF3B56B07E40CF57985511814AEC9EAE2F1329CEE059A21529FDDFDB8C } +TEST(THORChainSwap, SwapAvaxBnb) { + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::AVAX)); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BNB)); + toAsset.set_symbol("BNB"); + auto && [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress("0x4340fb8bb31357559607142b37C2173418E36785") + .toAddress("bnb1hy9a63tgsvham463vw2tkkw2j5y20v5drhw8p2") + .vault("0x53595320f158d4546677B4795Cc66dfF59D154Db") + .router("0x8f66c4ae756bebc49ec8b81966dd8bba9f127549") + .fromAmount("20000000000000000") + .build(); + ASSERT_EQ(errorCode, 0); + ASSERT_EQ(error, ""); + EXPECT_EQ(hex(out), "0a01001201002201002a0100422a30783866363663346165373536626562633439656338623831393636646438626261396631323735343952f30132f0010a07470de4df82000012e4011fece7b400000000000000000000000053595320f158d4546677b4795cc66dff59d154db000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470de4df820000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000343d3a424e422e424e423a626e62316879396136337467737668616d343633767732746b6b77326a35793230763564726877387032000000000000000000000000"); + + auto tx = Ethereum::Proto::SigningInput(); + ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); + + // check fields + EXPECT_EQ(tx.to_address(), "0x8f66c4ae756bebc49ec8b81966dd8bba9f127549"); + ASSERT_TRUE(tx.transaction().has_contract_generic()); + + Data vaultAddressBin = SwapTest_ethAddressStringToData("0x53595320f158d4546677B4795Cc66dfF59D154Db"); + EXPECT_EQ(hex(vaultAddressBin), "53595320f158d4546677b4795cc66dff59d154db"); + auto func = Ethereum::ABI::Function("deposit", std::vector>{ + std::make_shared(vaultAddressBin), + std::make_shared(parse_hex("0000000000000000000000000000000000000000")), + std::make_shared(uint256_t(20000000000000000)), + std::make_shared("=:BNB.BNB:bnb1hy9a63tgsvham463vw2tkkw2j5y20v5drhw8p2")}); + Data payload; + func.encode(payload); + EXPECT_EQ(hex(payload), "1fece7b400000000000000000000000053595320f158d4546677b4795cc66dff59d154db000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470de4df820000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000343d3a424e422e424e423a626e62316879396136337467737668616d343633767732746b6b77326a35793230763564726877387032000000000000000000000000"); + EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().amount())), "470de4df820000"); + EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().data())), hex(payload)); + + EXPECT_EQ(hex(TW::data(tx.private_key())), ""); + + // set few fields before signing + auto chainId = store(uint256_t(43114)); + tx.set_chain_id(chainId.data(), chainId.size()); + auto nonce = store(uint256_t(4)); + tx.set_nonce(nonce.data(), nonce.size()); + auto gasPrice = store(uint256_t(30000000000)); + tx.set_gas_price(gasPrice.data(), gasPrice.size()); + auto gasLimit = store(uint256_t(108810)); + tx.set_gas_limit(gasLimit.data(), gasLimit.size()); + auto privKey = parse_hex("42dcdf1cc2020a98f874a2f754eeb127e556ee62714973299e62ebdaadb48218"); + tx.set_private_key(privKey.data(), privKey.size()); + + // sign and encode resulting input + Ethereum::Proto::SigningOutput output; + ANY_SIGN(tx, TWCoinTypeAvalancheCChain); + EXPECT_EQ(hex(output.encoded()), "f90154048506fc23ac008301a90a948f66c4ae756bebc49ec8b81966dd8bba9f12754987470de4df820000b8e41fece7b400000000000000000000000053595320f158d4546677b4795cc66dff59d154db000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470de4df820000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000343d3a424e422e424e423a626e62316879396136337467737668616d343633767732746b6b77326a35793230763564726877387032000000000000000000000000830150f8a09491c6b06fc1773bfc2a067787da96143f3d56eaf9fa9667298fdb298d33944ea04e2e2618e7c822b21af1ccc27746bfa46fa703b1c7f14cb0e33bd7f88acf2045"); + // https://viewblock.io/thorchain/tx/8A29B132443BF1B0A0BD3E00F8155D10FEEEC7737BDC912C4A1AFB0A52E4FD4F + // https://snowtrace.io/tx/0x8A29B132443BF1B0A0BD3E00F8155D10FEEEC7737BDC912C4A1AFB0A52E4FD4F + // https://binance.mintscan.io/txs/9D250C8BAC8205B942A597AFB345045439A55CAB8DD588B75870D4E47D751C16 +} + TEST(THORChainSwap, SwapEthBnb) { Proto::Asset fromAsset; fromAsset.set_chain(static_cast(Chain::ETH)); From 9d1e8abfec727f0ca2a26aadd3cfd2d7eff68026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 11 Jan 2023 12:07:28 +0200 Subject: [PATCH 168/497] Rename Elrond to MultiversX (configuration change) (#2862) * Rename Elrond to MultiversX. * Fix logo URL, fix example URLs. --- .../core/app/blockchains/elrond/TestElrondSigner.kt | 4 ++-- docs/registry.md | 2 +- registry.json | 13 +++++++------ src/Elrond/Codec.cpp | 2 +- src/Elrond/Codec.h | 6 +++--- src/Elrond/NetworkConfig.h | 4 ++-- src/Elrond/TransactionFactory.h | 12 ++++++------ swift/Tests/Blockchains/ElrondTests.swift | 4 ++-- tests/chains/Elrond/SignerTests.cpp | 4 ++-- tests/chains/Elrond/TWCoinTypeTests.cpp | 10 +++++----- 10 files changed, 31 insertions(+), 30 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt index 44a9e16b2a3..a3597e4deb0 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt @@ -59,7 +59,7 @@ class TestElrondSigner { @Test fun signGenericActionUndelegate() { - // Successfully broadcasted https://explorer.elrond.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 + // Successfully broadcasted https://explorer.multiversx.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) val accounts = Elrond.Accounts.newBuilder() @@ -92,7 +92,7 @@ class TestElrondSigner { @Test fun signGenericActionDelegate() { - // Successfully broadcasted https://explorer.elrond.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 + // Successfully broadcasted https://explorer.multiversx.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) val accounts = Elrond.Accounts.newBuilder() diff --git a/docs/registry.md b/docs/registry.md index 3c06e890867..823c1526609 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -49,7 +49,7 @@ This list is generated from [./registry.json](../registry.json) | 494 | BandChain | BAND | | | | 500 | Theta | THETA | | | | 501 | Solana | SOL | | | -| 508 | Elrond | eGLD | | | +| 508 | MultiversX | eGLD | | | | 529 | Secret | SCRT | | | | 564 | Agoric | BLD | | | | 637 | Aptos | APT | | | diff --git a/registry.json b/registry.json index 8d4d9d7f67d..8bc0bedea72 100644 --- a/registry.json +++ b/registry.json @@ -1352,6 +1352,7 @@ { "id": "elrond", "name": "Elrond", + "displayName": "MultiversX", "coinId": 508, "symbol": "eGLD", "decimals": 18, @@ -1365,15 +1366,15 @@ "publicKeyType": "ed25519", "hrp": "erd", "explorer": { - "url": "https://explorer.elrond.com", + "url": "https://explorer.multiversx.com", "txPath": "/transactions/", - "accountPath": "/address/" + "accountPath": "/accounts/" }, "info": { - "url": "https://elrond.com/", - "source": "https://github.com/ElrondNetwork/elrond-go", - "rpc": "https://api.elrond.com", - "documentation": "https://docs.elrond.com" + "url": "https://multiversx.com/", + "source": "https://github.com/multiversx/mx-chain-go", + "rpc": "https://api.multiversx.com", + "documentation": "https://docs.multiversx.com" } }, { diff --git a/src/Elrond/Codec.cpp b/src/Elrond/Codec.cpp index dbdf0859291..a76328f8b39 100644 --- a/src/Elrond/Codec.cpp +++ b/src/Elrond/Codec.cpp @@ -25,7 +25,7 @@ std::string Codec::encodeBigInt(const std::string& value) { return encodeBigInt(uint256_t(value)); } -// For reference, see https://docs.elrond.com/developers/developer-reference/elrond-serialization-format/#arbitrary-width-big-numbers. +// For reference, see https://docs.multiversx.com/developers/developer-reference/elrond-serialization-format/#arbitrary-width-big-numbers. std::string Codec::encodeBigInt(uint256_t value) { std::string encoded = hex(store(value)); return encoded; diff --git a/src/Elrond/Codec.h b/src/Elrond/Codec.h index b2ffd73405b..18d71f3f223 100644 --- a/src/Elrond/Codec.h +++ b/src/Elrond/Codec.h @@ -13,9 +13,9 @@ namespace TW::Elrond { /// A stripped-down variant of the Elrond codec. /// For reference, see: -/// - https://docs.elrond.com/developers/developer-reference/elrond-serialization-format -/// - https://github.com/ElrondNetwork/elrond-sdk-erdjs/tree/main/src/smartcontracts/codec -/// - https://github.com/ElrondNetwork/elrond-wasm-rs/tree/master/elrond-codec +/// - https://docs.multiversx.com/developers/developer-reference/overview +/// - https://github.com/multiversx/mx-sdk-erdjs/tree/main/src/smartcontracts/codec +/// - https://github.com/multiversx/mx-sdk-rs/tree/master/framework/codec class Codec { public: static std::string encodeString(const std::string& value); diff --git a/src/Elrond/NetworkConfig.h b/src/Elrond/NetworkConfig.h index 79b5ebf61d0..719335b17ed 100644 --- a/src/Elrond/NetworkConfig.h +++ b/src/Elrond/NetworkConfig.h @@ -12,8 +12,8 @@ namespace TW::Elrond { /// A "NetworkConfig" object holds the network parameters relevant to creating transactions (e.g. minimum gas limit, minimum gas price). class NetworkConfig { - /// The following fields can (should) be fetched from https://api.elrond.com/network/config. - /// However, a "NetworkConfig" object is initialized with proper default values for Elrond Mainnet (as of December 2021). + /// The following fields can (should) be fetched from https://api.multiversx.com/network/config. + /// However, a "NetworkConfig" object is initialized with proper default values for Mainnet (as of December 2021). std::string chainId; uint32_t gasPerDataByte; uint32_t minGasLimit; diff --git a/src/Elrond/TransactionFactory.h b/src/Elrond/TransactionFactory.h index db3b3058b9d..db7ec70e19c 100644 --- a/src/Elrond/TransactionFactory.h +++ b/src/Elrond/TransactionFactory.h @@ -30,20 +30,20 @@ class TransactionFactory { Transaction fromGenericAction(const Proto::SigningInput& input); /// This should be used to transfer EGLD. - /// For reference, see: https://docs.elrond.com/developers/signing-transactions/signing-transactions/#general-structure. + /// For reference, see: https://docs.multiversx.com/developers/signing-transactions/signing-transactions. Transaction fromEGLDTransfer(const Proto::SigningInput& input); /// This should be used to transfer regular ESDTs (fungible tokens). - /// For reference, see: https://docs.elrond.com/developers/esdt-tokens/#transfers + /// For reference, see: https://docs.multiversx.com/developers/esdt-tokens /// - /// The "regular" ESDT tokens held by an account can be fetched from https://api.elrond.com/accounts/{address}/tokens. + /// The "regular" ESDT tokens held by an account can be fetched from https://api.multiversx.com/accounts/{address}/tokens. Transaction fromESDTTransfer(const Proto::SigningInput& input); /// This should be used to transfer NFTs, SFTs and Meta ESDTs. - /// For reference, see: https://docs.elrond.com/developers/nft-tokens/#transfers + /// For reference, see: https://docs.multiversx.com/developers/nft-tokens /// - /// The semi-fungible and non-fungible tokens held by an account can be fetched from https://api.elrond.com/accounts/{address}/nfts?type=SemiFungibleESDT,NonFungibleESDT. - /// The Meta ESDTs (a special kind of SFTs) held by an account can be fetched from https://api.elrond.com/accounts/{address}/nfts?type=MetaESDT. + /// The semi-fungible and non-fungible tokens held by an account can be fetched from https://api.multiversx.com/accounts/{address}/nfts?type=SemiFungibleESDT,NonFungibleESDT. + /// The Meta ESDTs (a special kind of SFTs) held by an account can be fetched from https://api.multiversx.com/accounts/{address}/nfts?type=MetaESDT. /// /// The fields "token_collection" and "token_nonce" are found as well in the HTTP response of the API call (as "collection" and "nonce", respectively). Transaction fromESDTNFTTransfer(const Proto::SigningInput& input); diff --git a/swift/Tests/Blockchains/ElrondTests.swift b/swift/Tests/Blockchains/ElrondTests.swift index beee15a7a26..fa6a64ee3ca 100644 --- a/swift/Tests/Blockchains/ElrondTests.swift +++ b/swift/Tests/Blockchains/ElrondTests.swift @@ -53,7 +53,7 @@ class ElrondTests: XCTestCase { } func testSignGenericActionUndelegate() { - // Successfully broadcasted https://explorer.elrond.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 + // Successfully broadcasted https://explorer.multiversx.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)! let input = ElrondSigningInput.with { @@ -82,7 +82,7 @@ class ElrondTests: XCTestCase { } func testSignGenericActionDelegate() { - // Successfully broadcasted https://explorer.elrond.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 + // Successfully broadcasted https://explorer.multiversx.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)! let input = ElrondSigningInput.with { diff --git a/tests/chains/Elrond/SignerTests.cpp b/tests/chains/Elrond/SignerTests.cpp index f2348dbe155..12172fa73d8 100644 --- a/tests/chains/Elrond/SignerTests.cpp +++ b/tests/chains/Elrond/SignerTests.cpp @@ -80,7 +80,7 @@ TEST(ElrondSigner, SignGenericActionUnDelegate) { })"_json; assertJSONEqual(expected, nlohmann::json::parse(encoded)); ASSERT_EQ(expectedSignature, signature); - // Successfully broadcasted https://explorer.elrond.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 + // Successfully broadcasted https://explorer.multiversx.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 } TEST(ElrondSigner, SignGenericActionRedelegateRewards) { @@ -226,7 +226,7 @@ TEST(ElrondSigner, SignGenericActionDelegate) { })"_json; assertJSONEqual(expected, nlohmann::json::parse(encoded)); ASSERT_EQ(expectedSignature, signature); - // Successfully broadcasted https://explorer.elrond.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 + // Successfully broadcasted https://explorer.multiversx.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 } TEST(ElrondSigner, SignGenericActionJSON) { diff --git a/tests/chains/Elrond/TWCoinTypeTests.cpp b/tests/chains/Elrond/TWCoinTypeTests.cpp index 1f7a977bdc0..5502507c216 100644 --- a/tests/chains/Elrond/TWCoinTypeTests.cpp +++ b/tests/chains/Elrond/TWCoinTypeTests.cpp @@ -15,9 +15,9 @@ TEST(TWElrondCoinType, TWCoinType) { auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeElrond)); - auto txId = WRAPS(TWStringCreateWithUTF8Bytes("1fc9785cb8bea0129a16cf7bddc97630c176a556ea566f0e72923c882b5cb3c8")); + auto txId = WRAPS(TWStringCreateWithUTF8Bytes("163b46551a74626415074b626d2f37d3c78aef0f6ccb628db434ee65a35ea127")); auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeElrond, txId.get())); - auto accId = WRAPS(TWStringCreateWithUTF8Bytes("erd12yne790km8ezwetkz7m3hmqy9utdc6vdkgsunfzpwguec6v04p2qtk9uqj")); + auto accId = WRAPS(TWStringCreateWithUTF8Bytes("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")); auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeElrond, accId.get())); auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeElrond)); auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeElrond)); @@ -27,8 +27,8 @@ TEST(TWElrondCoinType, TWCoinType) { ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeElrond)); ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeElrond)); assertStringsEqual(symbol, "eGLD"); - assertStringsEqual(txUrl, "https://explorer.elrond.com/transactions/1fc9785cb8bea0129a16cf7bddc97630c176a556ea566f0e72923c882b5cb3c8"); - assertStringsEqual(accUrl, "https://explorer.elrond.com/address/erd12yne790km8ezwetkz7m3hmqy9utdc6vdkgsunfzpwguec6v04p2qtk9uqj"); + assertStringsEqual(txUrl, "https://explorer.multiversx.com/transactions/163b46551a74626415074b626d2f37d3c78aef0f6ccb628db434ee65a35ea127"); + assertStringsEqual(accUrl, "https://explorer.multiversx.com/accounts/erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); assertStringsEqual(id, "elrond"); - assertStringsEqual(name, "Elrond"); + assertStringsEqual(name, "MultiversX"); } From ad351ab9e1de23bcbfbb3284db0cc7fc682b133b Mon Sep 17 00:00:00 2001 From: stspbu Date: Fri, 13 Jan 2023 17:31:27 +0400 Subject: [PATCH 169/497] TON support (#2813) --- .../blockchains/CoinAddressDerivationTests.kt | 1 + .../TestTheOpenNetworkAddress.kt | 50 ++++++ .../TestTheOpenNetworkSigner.kt | 50 ++++++ docs/registry.md | 1 + include/TrustWalletCore/TWBlockchain.h | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 28 +++ src/Base64.cpp | 20 +++ src/Base64.h | 3 + src/Coin.cpp | 3 + src/Everscale/Address.cpp | 45 +---- src/Everscale/Address.h | 27 ++- src/Everscale/{ => CommonTON}/Cell.cpp | 6 +- src/Everscale/{ => CommonTON}/Cell.h | 6 +- src/Everscale/{ => CommonTON}/CellBuilder.cpp | 6 +- src/Everscale/{ => CommonTON}/CellBuilder.h | 4 +- src/Everscale/{ => CommonTON}/CellSlice.cpp | 6 +- src/Everscale/{ => CommonTON}/CellSlice.h | 4 +- src/Everscale/CommonTON/Messages.cpp | 76 ++++++++ src/Everscale/CommonTON/Messages.h | 78 ++++++++ src/Everscale/CommonTON/RawAddress.cpp | 103 +++++++++++ src/Everscale/CommonTON/RawAddress.h | 42 +++++ src/Everscale/CommonTON/WorkchainType.h | 16 ++ src/Everscale/Messages.cpp | 87 ++------- src/Everscale/Messages.h | 65 +------ src/Everscale/Signer.cpp | 11 +- src/Everscale/Wallet.cpp | 25 +-- src/Everscale/Wallet.h | 21 +-- src/Everscale/WorkchainType.h | 9 +- src/HexCoding.h | 9 + src/TheOpenNetwork/Address.cpp | 125 +++++++++++++ src/TheOpenNetwork/Address.h | 63 +++++++ src/TheOpenNetwork/Entry.cpp | 33 ++++ src/TheOpenNetwork/Entry.h | 21 +++ src/TheOpenNetwork/Message.cpp | 38 ++++ src/TheOpenNetwork/Message.h | 28 +++ src/TheOpenNetwork/Signer.cpp | 65 +++++++ src/TheOpenNetwork/Signer.h | 30 ++++ src/TheOpenNetwork/WorkchainType.h | 13 ++ src/TheOpenNetwork/wallet/Wallet.cpp | 94 ++++++++++ src/TheOpenNetwork/wallet/Wallet.h | 59 +++++++ src/TheOpenNetwork/wallet/WalletV4R2.cpp | 54 ++++++ src/TheOpenNetwork/wallet/WalletV4R2.h | 24 +++ src/proto/TheOpenNetwork.proto | 75 ++++++++ .../Blockchains/TheOpenNetworkTests.swift | 62 +++++++ swift/Tests/CoinAddressDerivationTests.swift | 3 + tests/chains/Everscale/CellBuilderTest.cpp | 5 +- tests/chains/Everscale/CellTests.cpp | 10 +- tests/chains/TheOpenNetwork/AddressTests.cpp | 116 ++++++++++++ tests/chains/TheOpenNetwork/SignerTests.cpp | 166 ++++++++++++++++++ .../TheOpenNetwork/TWAnyAddressTests.cpp | 33 ++++ .../TheOpenNetwork/TWAnySignerTests.cpp | 37 ++++ .../chains/TheOpenNetwork/TWCoinTypeTests.cpp | 36 ++++ tests/common/Base64Tests.cpp | 11 ++ tests/common/CoinAddressDerivationTests.cpp | 3 + tests/common/CoinAddressValidationTests.cpp | 7 + tests/common/HexCodingTests.cpp | 7 + wasm/tests/Blockchain/TheOpenNetwork.test.ts | 100 +++++++++++ 58 files changed, 1864 insertions(+), 258 deletions(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkAddress.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkSigner.kt rename src/Everscale/{ => CommonTON}/Cell.cpp (99%) rename src/Everscale/{ => CommonTON}/Cell.h (96%) rename src/Everscale/{ => CommonTON}/CellBuilder.cpp (98%) rename src/Everscale/{ => CommonTON}/CellBuilder.h (96%) rename src/Everscale/{ => CommonTON}/CellSlice.cpp (94%) rename src/Everscale/{ => CommonTON}/CellSlice.h (92%) create mode 100644 src/Everscale/CommonTON/Messages.cpp create mode 100644 src/Everscale/CommonTON/Messages.h create mode 100644 src/Everscale/CommonTON/RawAddress.cpp create mode 100644 src/Everscale/CommonTON/RawAddress.h create mode 100644 src/Everscale/CommonTON/WorkchainType.h create mode 100644 src/TheOpenNetwork/Address.cpp create mode 100644 src/TheOpenNetwork/Address.h create mode 100644 src/TheOpenNetwork/Entry.cpp create mode 100644 src/TheOpenNetwork/Entry.h create mode 100644 src/TheOpenNetwork/Message.cpp create mode 100644 src/TheOpenNetwork/Message.h create mode 100644 src/TheOpenNetwork/Signer.cpp create mode 100644 src/TheOpenNetwork/Signer.h create mode 100644 src/TheOpenNetwork/WorkchainType.h create mode 100644 src/TheOpenNetwork/wallet/Wallet.cpp create mode 100644 src/TheOpenNetwork/wallet/Wallet.h create mode 100644 src/TheOpenNetwork/wallet/WalletV4R2.cpp create mode 100644 src/TheOpenNetwork/wallet/WalletV4R2.h create mode 100644 src/proto/TheOpenNetwork.proto create mode 100644 swift/Tests/Blockchains/TheOpenNetworkTests.swift create mode 100644 tests/chains/TheOpenNetwork/AddressTests.cpp create mode 100644 tests/chains/TheOpenNetwork/SignerTests.cpp create mode 100644 tests/chains/TheOpenNetwork/TWAnyAddressTests.cpp create mode 100644 tests/chains/TheOpenNetwork/TWAnySignerTests.cpp create mode 100644 tests/chains/TheOpenNetwork/TWCoinTypeTests.cpp create mode 100644 wasm/tests/Blockchain/TheOpenNetwork.test.ts diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 4e49c45c43e..d1eec662f19 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -105,6 +105,7 @@ class CoinAddressDerivationTests { NATIVEEVMOS -> assertEquals("evmos13u6g7vqgw074mgmf2ze2cadzvkz9snlwstd20d", address) NERVOS -> assertEquals("ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdtyq04tvp02wectaumxn0664yw2jd53lqk4mxg3", address) EVERSCALE -> assertEquals("0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04", address) + TON -> assertEquals("EQDgEMqToTacHic7SnvnPFmvceG5auFkCcAw0mSCvzvKUfk9", address) APTOS -> assertEquals("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", address) HEDERA -> assertEquals("0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5", address) SECRET -> assertEquals("secret1f69sk5033zcdr2p2yf3xjehn7xvgdeq09d2llh", address) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkAddress.kt new file mode 100644 index 00000000000..d2f341dc62f --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkAddress.kt @@ -0,0 +1,50 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.theopennetwork + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestTheOpenNetworkAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddressFromPrivateKey() { + val privateKey = PrivateKey("63474e5fe9511f1526a50567ce142befc343e71a49b865ac3908f58667319cb8".toHexByteArray()) + val publicKey = privateKey.getPublicKeyEd25519() + val address = AnyAddress(publicKey, CoinType.TON) + assertEquals(publicKey.data().toHex(), "0xf42c77f931bea20ec5d0150731276bbb2e2860947661245b2319ef8133ee8d41") + assertEquals(address.description(), "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q") + } + + @Test + fun testAddressFromPublicKey() { + val publicKey = PublicKey("f42c77f931bea20ec5d0150731276bbb2e2860947661245b2319ef8133ee8d41".toHexByteArray(), PublicKeyType.ED25519) + val address = AnyAddress(publicKey, CoinType.TON) + assertEquals(address.description(), "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q") + } + + @Test + fun testAddressFromRawString() { + val addressString = "0:66fbe3c5c03bf5c82792f904c9f8bf28894a6aa3d213d41c20569b654aadedb3" + val address = AnyAddress(addressString, CoinType.TON) + assertEquals(address.description(), "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q") + } + + @Test + fun testAddressFromUserFriendlyString() { + val addressString = "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q" + val address = AnyAddress(addressString, CoinType.TON) + assertEquals(address.description(), "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkSigner.kt new file mode 100644 index 00000000000..fcc1336c954 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkSigner.kt @@ -0,0 +1,50 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.theopennetwork + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.PrivateKey +import wallet.core.jni.proto.TheOpenNetwork +import wallet.core.jni.proto.TheOpenNetwork.SigningOutput + +class TestTheOpenNetworkSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun TheOpenNetworkTransactionSigning() { + val privateKey = PrivateKey("c38f49de2fb13223a9e7d37d5d0ffbdd89a5eb7c8b0ee4d1c299f2cefe7dc4a0".toHexByteArray()) + + val transfer = TheOpenNetwork.Transfer.newBuilder() + .setWalletVersion(TheOpenNetwork.WalletVersion.WALLET_V4_R2) + .setDest("EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q") + .setAmount(10) + .setSequenceNumber(6) + .setMode(TheOpenNetwork.SendMode.PAY_FEES_SEPARATELY_VALUE or TheOpenNetwork.SendMode.IGNORE_ACTION_PHASE_ERRORS_VALUE) + .setExpireAt(1671132440) + .build() + + val input = TheOpenNetwork.SigningInput.newBuilder() + .setTransfer(transfer) + .setPrivateKey(ByteString.copyFrom(privateKey.data())) + .build() + + val output = AnySigner.sign(input, CoinType.TON, SigningOutput.parser()) + + // tx: https://tonscan.org/tx/3Z4tHpXNLyprecgu5aTQHWtY7dpHXEoo11MAX61Xyg0= + val expectedString = "te6ccgICAAQAAQAAALAAAAFFiAGwt/q8k4SrjbFbQCjJZfQr64ExRxcUMsWqaQODqTUijgwAAQGcEUPkil2aZ4s8KKparSep/OKHMC8vuXafFbW2HGp/9AcTRv0J5T4dwyW1G0JpHw+g5Ov6QI3Xo0O9RFr3KidICimpoxdjm3UYAAAABgADAAIBYmIAM33x4uAd+uQTyXyCZPxflESlNVHpCeoOECtNsqVW9tmIUAAAAAAAAAAAAAAAAAEAAwAA" + + assertEquals(output.encoded, expectedString) + } +} diff --git a/docs/registry.md b/docs/registry.md index 823c1526609..51cb097e664 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -52,6 +52,7 @@ This list is generated from [./registry.json](../registry.json) | 508 | MultiversX | eGLD | | | | 529 | Secret | SCRT | | | | 564 | Agoric | BLD | | | +| 607 | TON | TON | | | | 637 | Aptos | APT | | | | 714 | BNB Beacon Chain | BNB | | | | 818 | VeChain | VET | | | diff --git a/include/TrustWalletCore/TWBlockchain.h b/include/TrustWalletCore/TWBlockchain.h index 44724e534f6..4231010137d 100644 --- a/include/TrustWalletCore/TWBlockchain.h +++ b/include/TrustWalletCore/TWBlockchain.h @@ -56,6 +56,7 @@ enum TWBlockchain { TWBlockchainEverscale = 42, TWBlockchainAptos = 43, // Aptos TWBlockchainHedera = 44, // Hedera + TWBlockchainTheOpenNetwork = 45, }; TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 6bd2e78b158..661ccebf68d 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -128,6 +128,7 @@ enum TWCoinType { TWCoinTypeSecret = 529, TWCoinTypeNativeInjective = 10000060, TWCoinTypeAgoric = 564, + TWCoinTypeTON = 607, }; /// Returns the blockchain for a coin type. diff --git a/registry.json b/registry.json index 8bc0bedea72..81df647a241 100644 --- a/registry.json +++ b/registry.json @@ -2942,5 +2942,33 @@ "url": "https://injective.com", "documentation": "https://docs.injective.network" } + }, + { + "id": "ton", + "name": "TON", + "coinId": 607, + "symbol": "TON", + "decimals": 9, + "blockchain": "The Open Network", + "derivation": [ + { + "path": "m/44'/607'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://tonscan.org", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "fJXfn0EVhV09HFuEgUHu4Cchb24nUQtIMwSzmzk2tLs=", + "sampleAccount": "EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N" + }, + "info": { + "url": "https://ton.org", + "source": "https://github.com/ton-blockchain", + "rpc": "https://toncenter.com/api/v2/jsonRPC", + "documentation": "https://ton.org/docs" + } } ] diff --git a/src/Base64.cpp b/src/Base64.cpp index cf4605592ad..edb5db03998 100644 --- a/src/Base64.cpp +++ b/src/Base64.cpp @@ -16,6 +16,26 @@ namespace TW::Base64 { using namespace TW; using namespace std; +static bool isBase64Any(const string& val, const char* alphabet) { + if (val.length() % 4 != 0) { + return false; + } + size_t first_non_alphabet = val.find_first_not_of(alphabet); + size_t first_non_padding = val.find_first_not_of("=", first_non_alphabet); + + if (first_non_alphabet == std::string::npos || + (first_non_padding == std::string::npos && (val.length() - first_non_alphabet < 3))) { + return true; + } + return false; +} + +bool isBase64orBase64Url(const string& val) { + const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const char* base64_url_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + return isBase64Any(val, base64_chars) || isBase64Any(val, base64_url_chars); +} + Data decode(const string& val) { using namespace boost::archive::iterators; using It = transform_width, 8, 6>; diff --git a/src/Base64.h b/src/Base64.h index 5bc20e6fc70..8ea6f74356b 100644 --- a/src/Base64.h +++ b/src/Base64.h @@ -10,6 +10,9 @@ namespace TW::Base64 { +// Checks if as string is in Base64-format or Base64Url-format +bool isBase64orBase64Url(const std::string& val); + // Decode a Base64-format string Data decode(const std::string& val); diff --git a/src/Coin.cpp b/src/Coin.cpp index dd82fc790d9..521db9fb0a8 100644 --- a/src/Coin.cpp +++ b/src/Coin.cpp @@ -56,6 +56,7 @@ #include "Zcash/Entry.h" #include "Zilliqa/Entry.h" #include "Hedera/Entry.h" +#include "TheOpenNetwork/Entry.h" // end_of_coin_includes_marker_do_not_modify using namespace TW; @@ -105,6 +106,7 @@ Zilliqa::Entry zilliqaDP; Nervos::Entry NervosDP; Everscale::Entry EverscaleDP; Hedera::Entry HederaDP; +TheOpenNetwork::Entry tonDP; // end_of_coin_dipatcher_declarations_marker_do_not_modify CoinEntry* coinDispatcher(TWCoinType coinType) { @@ -156,6 +158,7 @@ CoinEntry* coinDispatcher(TWCoinType coinType) { case TWBlockchainEverscale: entry = &EverscaleDP; break; case TWBlockchainAptos: entry = &AptosDP; break; case TWBlockchainHedera: entry = &HederaDP; break; + case TWBlockchainTheOpenNetwork: entry = &tonDP; break; // end_of_coin_dipatcher_switch_marker_do_not_modify default: entry = nullptr; break; diff --git a/src/Everscale/Address.cpp b/src/Everscale/Address.cpp index 177313473cd..c59331e110e 100644 --- a/src/Everscale/Address.cpp +++ b/src/Everscale/Address.cpp @@ -10,45 +10,15 @@ #include "Address.h" #include "HexCoding.h" #include "Wallet.h" -#include "WorkchainType.h" using namespace TW; namespace TW::Everscale { -using MaybeWorkchain = std::optional>; - -MaybeWorkchain parseWorkchainId(const std::string& string) { - if (auto pos = string.find(':'); pos != std::string::npos) { - try { - auto workchainId = static_cast(std::stoi(string.substr(0, pos))); - return std::make_pair(workchainId, pos + 1); - } catch (...) { - // Do nothing and return empty value later - } - } - - return {}; -} +using AddressImpl = TW::CommonTON::RawAddress; bool Address::isValid(const std::string& string) noexcept { - auto parsed = parseWorkchainId(string); - if (!parsed.has_value()) { - return false; - } - - auto [workchainId, pos] = *parsed; - - if (workchainId != WorkchainType::Basechain && workchainId != WorkchainType::Masterchain) { - return false; - } - - if (string.size() != pos + hexAddrLen) { - return false; - } - - std::string addr = string.substr(pos); - return parse_hex(addr).size() == size; + return AddressImpl::isValid(string); } Address::Address(const std::string& string) { @@ -56,13 +26,7 @@ Address::Address(const std::string& string) { throw std::invalid_argument("Invalid address string!"); } - auto parsed = parseWorkchainId(string); - auto [parsedWorkchainId, pos] = *parsed; - - workchainId = parsedWorkchainId; - - const auto parsedHash = parse_hex(string.substr(pos)); - std::copy(begin(parsedHash), end(parsedHash), begin(hash)); + addressData = AddressImpl::splitAddress(string); } Address::Address(const PublicKey& publicKey, int8_t workchainId) @@ -70,8 +34,7 @@ Address::Address(const PublicKey& publicKey, int8_t workchainId) } std::string Address::string() const { - std::string address = std::to_string(workchainId) + ":" + hex(hash); - return address; + return AddressImpl::to_string(addressData); } } // namespace TW::Everscale diff --git a/src/Everscale/Address.h b/src/Everscale/Address.h index d97ec61f44c..9f76f64e2e4 100644 --- a/src/Everscale/Address.h +++ b/src/Everscale/Address.h @@ -7,25 +7,20 @@ #pragma once #include "Data.h" -#include "../PublicKey.h" +#include "PublicKey.h" + +#include "CommonTON/RawAddress.h" #include #include namespace TW::Everscale { +using AddressData = CommonTON::AddressData; + class Address { public: - /// Number of bytes in an address - static const size_t size = Hash::sha256Size; - - /// Hex address length - static const size_t hexAddrLen = size * 2; - - /// Workchain ID (-1 for masterchain, 0 for base workchain) - std::int8_t workchainId; - /// StateInit hash - std::array hash{}; + AddressData addressData; /// Determines whether a string makes a valid address. [[nodiscard]] static bool isValid(const std::string& string) noexcept; @@ -37,15 +32,19 @@ class Address { explicit Address(const PublicKey& publicKey, int8_t workchainId); /// Initializes an Everscale address with its parts - explicit Address(int8_t workchainId, std::array hash) - : workchainId(workchainId), hash(hash) {} + explicit Address(int8_t workchainId, std::array hash) + : addressData(workchainId, hash) {} + + /// Initializes an Everscale address with AddressData + explicit Address(AddressData addressData) + : addressData(addressData) {} /// Returns a string representation of the address. [[nodiscard]] std::string string() const; }; inline bool operator==(const Address& lhs, const Address& rhs) { - return lhs.workchainId == rhs.workchainId && lhs.hash == rhs.hash; + return lhs.addressData.workchainId == rhs.addressData.workchainId && lhs.addressData.hash == rhs.addressData.hash; } } // namespace TW::Everscale diff --git a/src/Everscale/Cell.cpp b/src/Everscale/CommonTON/Cell.cpp similarity index 99% rename from src/Everscale/Cell.cpp rename to src/Everscale/CommonTON/Cell.cpp index 41d9ec32a81..eebd31a5063 100644 --- a/src/Everscale/Cell.cpp +++ b/src/Everscale/CommonTON/Cell.cpp @@ -11,14 +11,14 @@ #include #include -#include "../BinaryCoding.h" +#include "BinaryCoding.h" #include #include using namespace TW; -namespace TW::Everscale { +namespace TW::CommonTON { constexpr static uint32_t BOC_MAGIC = 0xb5ee9c72; @@ -397,4 +397,4 @@ void Cell::finalize() { finalized = true; } -} // namespace TW::Everscale +} // namespace TW::CommonTON diff --git a/src/Everscale/Cell.h b/src/Everscale/CommonTON/Cell.h similarity index 96% rename from src/Everscale/Cell.h rename to src/Everscale/CommonTON/Cell.h index 0a621ffcf19..56240993172 100644 --- a/src/Everscale/Cell.h +++ b/src/Everscale/CommonTON/Cell.h @@ -13,9 +13,9 @@ #include #include "Data.h" -#include "../Hash.h" +#include "Hash.h" -namespace TW::Everscale { +namespace TW::CommonTON { class Cell { public: @@ -63,4 +63,4 @@ class Cell { } }; -} // namespace TW::Everscale +} // namespace TW::CommonTON diff --git a/src/Everscale/CellBuilder.cpp b/src/Everscale/CommonTON/CellBuilder.cpp similarity index 98% rename from src/Everscale/CellBuilder.cpp rename to src/Everscale/CommonTON/CellBuilder.cpp index 8ddc3ccbc94..d077b7098ea 100644 --- a/src/Everscale/CellBuilder.cpp +++ b/src/Everscale/CommonTON/CellBuilder.cpp @@ -11,11 +11,11 @@ #include #include -#include "../BinaryCoding.h" +#include "BinaryCoding.h" using namespace TW; -namespace TW::Everscale { +namespace TW::CommonTON { CellBuilder::CellBuilder(Data& appendedData, uint16_t bits) { assert(bits <= appendedData.size() * 8); @@ -257,4 +257,4 @@ void CellBuilder::encode128BE(const uint128_t& val, Data& data) { data.emplace_back(static_cast(val)); } -} // namespace TW::Everscale +} // namespace TW::CommonTON diff --git a/src/Everscale/CellBuilder.h b/src/Everscale/CommonTON/CellBuilder.h similarity index 96% rename from src/Everscale/CellBuilder.h rename to src/Everscale/CommonTON/CellBuilder.h index 8b192ec42b3..596393c7ae5 100644 --- a/src/Everscale/CellBuilder.h +++ b/src/Everscale/CommonTON/CellBuilder.h @@ -13,7 +13,7 @@ #include "Cell.h" #include "CellSlice.h" -namespace TW::Everscale { +namespace TW::CommonTON { class CellBuilder { uint16_t bitLen = 0; @@ -52,4 +52,4 @@ class CellBuilder { static void encode128BE(const uint128_t& value, Data& data); }; -} // namespace TW::Everscale +} // namespace TW::CommonTON diff --git a/src/Everscale/CellSlice.cpp b/src/Everscale/CommonTON/CellSlice.cpp similarity index 94% rename from src/Everscale/CellSlice.cpp rename to src/Everscale/CommonTON/CellSlice.cpp index 346f4a65365..68e5f2af433 100644 --- a/src/Everscale/CellSlice.cpp +++ b/src/Everscale/CommonTON/CellSlice.cpp @@ -8,11 +8,11 @@ #include -#include "../BinaryCoding.h" +#include "BinaryCoding.h" using namespace TW; -namespace TW::Everscale { +namespace TW::CommonTON { uint32_t CellSlice::getNextU32() { const auto bytes = getNextBytes(sizeof(uint32_t)); @@ -56,4 +56,4 @@ void CellSlice::require(uint16_t bits) const { } } -} // namespace TW::Everscale +} // namespace TW::CommonTON diff --git a/src/Everscale/CellSlice.h b/src/Everscale/CommonTON/CellSlice.h similarity index 92% rename from src/Everscale/CellSlice.h rename to src/Everscale/CommonTON/CellSlice.h index 38c4598b9a5..b553c6ab670 100644 --- a/src/Everscale/CellSlice.h +++ b/src/Everscale/CommonTON/CellSlice.h @@ -12,7 +12,7 @@ #include "Cell.h" -namespace TW::Everscale { +namespace TW::CommonTON { class CellSlice { public: @@ -29,4 +29,4 @@ class CellSlice { void require(uint16_t bits) const; }; -} // namespace TW::Everscale +} // namespace TW::CommonTON diff --git a/src/Everscale/CommonTON/Messages.cpp b/src/Everscale/CommonTON/Messages.cpp new file mode 100644 index 00000000000..ae79a75111f --- /dev/null +++ b/src/Everscale/CommonTON/Messages.cpp @@ -0,0 +1,76 @@ +#include "Messages.h" + +namespace TW::CommonTON { + +void ExternalInboundMessageHeader::writeTo(CellBuilder& builder) const { + builder.appendBitOne(); + builder.appendBitZero(); + + // addr src (none) + builder.appendRaw(Data{0x00}, 2); + + // addr dst + Data dstAddr(_dst.hash.begin(), _dst.hash.end()); + + Data prefix{0x80}; + builder.appendRaw(prefix, 2); + + builder.appendBitZero(); + builder.appendI8(_dst.workchainId); + builder.appendRaw(dstAddr, 256); + + // fee + builder.appendU128(_importFee); +} + +void InternalMessageHeader::writeTo(CellBuilder& builder) const { + // tag + builder.appendBitZero(); + + builder.appendBitBool(_ihrDisabled); + builder.appendBitBool(_bounce); + builder.appendBitBool(_bounced); + + // addr src (none) + builder.appendRaw(Data{0x00}, 2); + + // addr dst + Data dstAddr(_dst.hash.begin(), _dst.hash.end()); + + Data prefix{0x80}; + builder.appendRaw(prefix, 2); + + builder.appendBitZero(); + builder.appendI8(_dst.workchainId); + builder.appendRaw(dstAddr, 256); + + // value + builder.appendU128(_value); + + // currency collections + builder.appendBitZero(); + + // fee + builder.appendU128(_ihrFee); + builder.appendU128(_fwdFee); + + // created + builder.appendU64(_createdLt); + builder.appendU32(_createdAt); +} + +CellBuilder StateInit::writeTo() const { + CellBuilder builder; + + builder.appendBitZero(); // split_depth + builder.appendBitZero(); // special + builder.appendBitOne(); // code + builder.appendReferenceCell(code); + builder.appendBitOne(); // data + builder.appendReferenceCell(data); + builder.appendBitZero(); // library + + return builder; +} + +} // namespace TW::CommonTON \ No newline at end of file diff --git a/src/Everscale/CommonTON/Messages.h b/src/Everscale/CommonTON/Messages.h new file mode 100644 index 00000000000..bd96fe7b731 --- /dev/null +++ b/src/Everscale/CommonTON/Messages.h @@ -0,0 +1,78 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include + +#include "Cell.h" +#include "CellBuilder.h" +#include "CellSlice.h" +#include "RawAddress.h" + +#include "PrivateKey.h" + +namespace TW::CommonTON { + +using uint128_t = CellBuilder::uint128_t; + +class CommonMsgInfo { +public: + virtual void writeTo(CellBuilder& builder) const = 0; + + virtual ~CommonMsgInfo() = default; +}; + +class ExternalInboundMessageHeader : public CommonMsgInfo { + AddressData _dst; + uint128_t _importFee{}; + +public: + explicit ExternalInboundMessageHeader(AddressData dst) + : _dst(dst) {} + + void writeTo(CellBuilder& builder) const override; +}; + +class InternalMessageHeader : public CommonMsgInfo { + bool _ihrDisabled; + bool _bounce; + AddressData _dst; + uint128_t _value; + + bool _bounced{}; + uint128_t _ihrFee{}; + uint128_t _fwdFee{}; + uint64_t _createdLt{}; + uint32_t _createdAt{}; + +public: + InternalMessageHeader(bool ihrDisabled, bool bounce, AddressData dst, uint64_t value) + : _ihrDisabled(ihrDisabled), _bounce(bounce), _dst(dst), _value(static_cast(value)) {} + + void writeTo(CellBuilder& builder) const override; +}; + +class StateInit { +public: + Cell::Ref code; + Cell::Ref data; + + [[nodiscard]] CellBuilder writeTo() const; +}; + +struct MessageData { + std::shared_ptr header; + std::optional init{}; + std::optional body{}; + + using HeaderRef = std::shared_ptr; + + explicit MessageData(HeaderRef header) : header(std::move(header)) { } +}; + +} // namespace TW::CommonTON diff --git a/src/Everscale/CommonTON/RawAddress.cpp b/src/Everscale/CommonTON/RawAddress.cpp new file mode 100644 index 00000000000..5aa6199062f --- /dev/null +++ b/src/Everscale/CommonTON/RawAddress.cpp @@ -0,0 +1,103 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "RawAddress.h" + +#include "HexCoding.h" +#include "WorkchainType.h" + +using MaybeWorkchain = std::optional>; + +namespace TW::CommonTON { + +static std::optional parse_long(char const *s) +{ + char *end; + auto previous_errno = errno; + errno = 0; + long l = strtol(s, &end, 10); + if (errno == ERANGE && l == LONG_MAX) { + errno = previous_errno; + return {}; // Overflow + } + if (errno == ERANGE && l == LONG_MIN) { + errno = previous_errno; + return {}; // Underflow + } + if (*s == '\0' || *end != '\0') { + errno = previous_errno; + return {}; // Inconvertible + } + errno = previous_errno; + return l; +} + +static std::optional parse_int8(char const *s) { + auto value = parse_long(s); + if (!value.has_value()) { + return std::nullopt; + } + if (value.value() <= static_cast(std::numeric_limits::max()) && value.value() >= static_cast(std::numeric_limits::min())) { + return value; + } else { + return std::nullopt; + } +} + +static MaybeWorkchain parseWorkchainId(const std::string& string) { + if (auto pos = string.find(':'); pos != std::string::npos) { + std::string workchain_string = string.substr(0, pos); + auto workchain_id = parse_int8(workchain_string.c_str()); + if (workchain_id.has_value()) { + return std::make_pair(workchain_id.value(), pos + 1); + } + } + return {}; +} + +bool RawAddress::isValid(const std::string& string) { + auto parsed = parseWorkchainId(string); + if (!parsed.has_value()) { + return false; + } + + auto [workchainId, pos] = *parsed; + + if (workchainId != WorkchainType::Basechain && workchainId != WorkchainType::Masterchain) { + return false; + } + + if (string.size() != pos + AddressData::hexAddrLen) { + return false; + } + + std::string addr = string.substr(pos); + if (!is_hex_encoded(addr)) { + return false; + } + return parse_hex(addr).size() == AddressData::size; +} + +AddressData RawAddress::splitAddress(const std::string& address) { + auto parsed = parseWorkchainId(address); + auto [parsedWorkchainId, pos] = *parsed; + + auto workchainId = parsedWorkchainId; + + const auto parsedHash = parse_hex(address.substr(pos)); + + std::array hash{}; + std::copy(begin(parsedHash), end(parsedHash), begin(hash)); + + return AddressData(workchainId, hash); +} + +std::string RawAddress::to_string(const AddressData& addressData) { + std::string address = std::to_string(addressData.workchainId) + ":" + hex(addressData.hash); + return address; +} + +} // namespace TW::CommonTON diff --git a/src/Everscale/CommonTON/RawAddress.h b/src/Everscale/CommonTON/RawAddress.h new file mode 100644 index 00000000000..dbca44b11c0 --- /dev/null +++ b/src/Everscale/CommonTON/RawAddress.h @@ -0,0 +1,42 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include +#include + +#include "Hash.h" + +namespace TW::CommonTON { + +struct AddressData { + /// Number of bytes in an address + static const size_t size = Hash::sha256Size; + + /// Hex address length + static const size_t hexAddrLen = size * 2; + + /// Workchain ID (-1 for masterchain, 0 for base workchain) + std::int8_t workchainId{}; + + /// StateInit hash + std::array hash{}; + + explicit AddressData(int8_t workchainId, std::array hash) + : workchainId(workchainId), hash(hash) {} + + explicit AddressData() = default; +}; + +struct RawAddress { + static bool isValid(const std::string& string); + static AddressData splitAddress(const std::string& address); + static std::string to_string(const AddressData& addressData); +}; + +} // namespace TW::CommonTON diff --git a/src/Everscale/CommonTON/WorkchainType.h b/src/Everscale/CommonTON/WorkchainType.h new file mode 100644 index 00000000000..9e1c3fee27e --- /dev/null +++ b/src/Everscale/CommonTON/WorkchainType.h @@ -0,0 +1,16 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +namespace TW::CommonTON { + +enum WorkchainType { + Masterchain = -1, + Basechain = 0, +}; + +} // namespace TW::CommonTON diff --git a/src/Everscale/Messages.cpp b/src/Everscale/Messages.cpp index a20ee263f08..43f48539446 100644 --- a/src/Everscale/Messages.cpp +++ b/src/Everscale/Messages.cpp @@ -5,76 +5,23 @@ // file LICENSE at the root of the source code distribution tree. #include "Messages.h" + +#include "Wallet.h" #include "WorkchainType.h" using namespace TW; namespace TW::Everscale { -void ExternalInboundMessageHeader::writeTo(CellBuilder& builder) const { - builder.appendBitOne(); - builder.appendBitZero(); - - // addr src (none) - builder.appendRaw(Data{0x00}, 2); - - // addr dst - Data dstAddr(_dst.hash.begin(), _dst.hash.end()); - - Data prefix{0x80}; - builder.appendRaw(prefix, 2); - - builder.appendBitZero(); - builder.appendI8(_dst.workchainId); - builder.appendRaw(dstAddr, 256); - - // fee - builder.appendU128(_importFee); -} - -void InternalMessageHeader::writeTo(CellBuilder& builder) const { - // tag - builder.appendBitZero(); - - builder.appendBitBool(_ihrDisabled); - builder.appendBitBool(_bounce); - builder.appendBitBool(_bounced); - - // addr src (none) - builder.appendRaw(Data{0x00}, 2); - - // addr dst - Data dstAddr(_dst.hash.begin(), _dst.hash.end()); - - Data prefix{0x80}; - builder.appendRaw(prefix, 2); - - builder.appendBitZero(); - builder.appendI8(_dst.workchainId); - builder.appendRaw(dstAddr, 256); - - // value - builder.appendU128(_value); - builder.appendBitZero(); - - // fee - builder.appendU128(_ihrFee); - builder.appendU128(_fwdFee); - - // created - builder.appendU64(_createdLt); - builder.appendU32(_createdAt); -} - Cell::Ref Message::intoCell() const { CellBuilder builder; // write Header - _header->writeTo(builder); + _messageData.header->writeTo(builder); // write StateInit - if (_init.has_value()) { - auto initBuilder = _init.value().writeTo(); + if (_messageData.init.has_value()) { + auto initBuilder = _messageData.init.value().writeTo(); builder.appendBitOne(); builder.appendBitZero(); @@ -84,9 +31,9 @@ Cell::Ref Message::intoCell() const { } // write Body - if (_body.has_value()) { + if (_messageData.body.has_value()) { builder.appendBitZero(); - builder.appendCellSlice(_body.value()); + builder.appendCellSlice(CellSlice(_messageData.body.value().get())); } else { builder.appendBitZero(); } @@ -94,8 +41,8 @@ Cell::Ref Message::intoCell() const { return builder.intoCell(); } -Data createSignedMessage(PublicKey& publicKey, PrivateKey& key, bool bounce, uint32_t flags, uint64_t amount, uint32_t expiredAt, - Address to, const Cell::Ref& contractData) { +MessageData createSignedMessage(PublicKey& publicKey, PrivateKey& key, bool bounce, uint32_t flags, uint64_t amount, uint32_t expiredAt, + Address to, const Cell::Ref& contractData) { auto getInitData = [](const PublicKey& publicKey, const Cell::Ref& contractData) { if (contractData != nullptr) { auto cellSlice = CellSlice(contractData.get()); @@ -124,23 +71,15 @@ Data createSignedMessage(PublicKey& publicKey, PrivateKey& key, bool bounce, uin payload.prependRaw(signature, static_cast(signature.size()) * 8); auto header = std::make_shared(InitData(publicKey).computeAddr(WorkchainType::Basechain)); - auto message = Message(header); + auto message = MessageData(header); if (withInitState) { - message.setStateInit(initData.makeStateInit()); + message.init = initData.makeStateInit(); } - auto cell = payload.intoCell(); - auto body = CellSlice(cell.get()); - - message.setBody(body); - - const auto messageCell = message.intoCell(); - - Data result{}; - messageCell->serialize(result); + message.body = payload.intoCell(); - return result; + return message; } } // namespace TW::Everscale diff --git a/src/Everscale/Messages.h b/src/Everscale/Messages.h index 345f75667ec..c0eb9ca027c 100644 --- a/src/Everscale/Messages.h +++ b/src/Everscale/Messages.h @@ -6,76 +6,23 @@ #pragma once -#include -#include - #include "Address.h" -#include "CellBuilder.h" -#include "CellSlice.h" -#include "Wallet.h" +#include "CommonTON/Messages.h" -#include "../PrivateKey.h" +using namespace TW::CommonTON; namespace TW::Everscale { -using uint128_t = CellBuilder::uint128_t; - -class CommonMsgInfo { -public: - virtual void writeTo(CellBuilder& builder) const = 0; - - virtual ~CommonMsgInfo() = default; -}; - -class ExternalInboundMessageHeader : public CommonMsgInfo { - Address _dst; - uint128_t _importFee{}; - -public: - explicit ExternalInboundMessageHeader(Address dst) - : _dst(dst) {} - - void writeTo(CellBuilder& builder) const override; -}; - -class InternalMessageHeader : public CommonMsgInfo { - bool _ihrDisabled; - bool _bounce; - Address _dst; - uint128_t _value; - - bool _bounced{}; - uint128_t _ihrFee{}; - uint128_t _fwdFee{}; - uint64_t _createdLt{}; - uint32_t _createdAt{}; - -public: - InternalMessageHeader(bool ihrDisabled, bool bounce, Address dst, uint64_t value) - : _ihrDisabled(ihrDisabled), _bounce(bounce), _dst(dst), _value(static_cast(value)) {} - - void writeTo(CellBuilder& builder) const override; -}; - class Message { private: - std::shared_ptr _header; - - std::optional _init{}; - std::optional _body{}; + MessageData _messageData; public: - using HeaderRef = std::shared_ptr; - - explicit Message(HeaderRef header) - : _header(std::move(header)) {} - + explicit Message(MessageData messageData) : _messageData(std::move(messageData)) {} [[nodiscard]] Cell::Ref intoCell() const; - inline void setBody(CellSlice body) { _body = body; } - inline void setStateInit(const StateInit& stateInit) { _init = stateInit; } }; -Data createSignedMessage(PublicKey& publicKey, PrivateKey& key, bool bounce, uint32_t flags, uint64_t amount, - uint32_t expiredAt, Address destination, const Cell::Ref& contractData); +MessageData createSignedMessage(PublicKey& publicKey, PrivateKey& key, bool bounce, uint32_t flags, uint64_t amount, + uint32_t expiredAt, Address destination, const Cell::Ref& contractData); } // namespace TW::Everscale diff --git a/src/Everscale/Signer.cpp b/src/Everscale/Signer.cpp index 1f2a0fb9d10..a76bd35f690 100644 --- a/src/Everscale/Signer.cpp +++ b/src/Everscale/Signer.cpp @@ -7,11 +7,9 @@ #include "Signer.h" #include "Address.h" #include "Messages.h" +#include "Wallet.h" -#include "../Base64.h" - -using namespace TW; -using namespace std::chrono; +#include "Base64.h" namespace TW::Everscale { @@ -56,7 +54,10 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { transfer.expired_at(), Address(transfer.to()), contractData); - protoOutput.set_encoded(TW::Base64::encode(signedMessage)); + Data result{}; + Message(signedMessage).intoCell()->serialize(result); + + protoOutput.set_encoded(TW::Base64::encode(result)); break; } default: diff --git a/src/Everscale/Wallet.cpp b/src/Everscale/Wallet.cpp index 09bf1e442e5..0ea085209d2 100644 --- a/src/Everscale/Wallet.cpp +++ b/src/Everscale/Wallet.cpp @@ -5,13 +5,10 @@ // file LICENSE at the root of the source code distribution tree. #include "Wallet.h" -#include "CellBuilder.h" #include "Messages.h" #include "HexCoding.h" -using namespace TW; - namespace TW::Everscale { // WalletV3 contract https://github.com/tonlabs/ton-1/blob/master/crypto/smartcont/wallet3-code.fc @@ -27,14 +24,14 @@ CellBuilder InitData::writeTo() const { return builder; } -Address InitData::computeAddr(int8_t workchainId) const { +AddressData InitData::computeAddr(int8_t workchainId) const { auto builder = this->writeTo(); StateInit stateInit{ .code = Cell::deserialize(Wallet::code.data(), Wallet::code.size()), .data = builder.intoCell(), }; - return Address(workchainId, stateInit.writeTo().intoCell()->hash); + return AddressData(workchainId, stateInit.writeTo().intoCell()->hash); } StateInit InitData::makeStateInit() const { @@ -55,8 +52,8 @@ CellBuilder InitData::makeTransferPayload(uint32_t expireAt, const Wallet::Gift& payload.appendU32(_seqno); // create internal message - Message::HeaderRef header = std::make_shared(true, gift.bounce, gift.to, gift.amount); - auto message = Message(header); + MessageData::HeaderRef header = std::make_shared(true, gift.bounce, gift.to.addressData, gift.amount); + auto message = Message(MessageData(header)); // append it to the body payload.appendU8(gift.flags); @@ -65,18 +62,4 @@ CellBuilder InitData::makeTransferPayload(uint32_t expireAt, const Wallet::Gift& return payload; } -CellBuilder StateInit::writeTo() const { - CellBuilder builder; - - builder.appendBitZero(); // split_depth - builder.appendBitZero(); // special - builder.appendBitOne(); // code - builder.appendReferenceCell(code); - builder.appendBitOne(); // data - builder.appendReferenceCell(data); - builder.appendBitZero(); // library - - return builder; -} - } // namespace TW::Everscale diff --git a/src/Everscale/Wallet.h b/src/Everscale/Wallet.h index a0216c465db..93dd7a4f98a 100644 --- a/src/Everscale/Wallet.h +++ b/src/Everscale/Wallet.h @@ -9,15 +9,18 @@ #include #include -#include "../PublicKey.h" +#include "PublicKey.h" #include "Address.h" -#include "Cell.h" -#include "CellBuilder.h" -#include "CellSlice.h" +#include "CommonTON/Cell.h" +#include "CommonTON/CellBuilder.h" +#include "CommonTON/CellSlice.h" +#include "CommonTON/Messages.h" const uint32_t WALLET_ID = 0x4BA92D8A; +using namespace TW::CommonTON; + namespace TW::Everscale { class Wallet { @@ -49,14 +52,6 @@ class Wallet { static const Data code; }; -class StateInit { -public: - Cell::Ref code; - Cell::Ref data; - - [[nodiscard]] CellBuilder writeTo() const; -}; - class InitData { uint32_t _seqno; uint32_t _walletId; @@ -70,7 +65,7 @@ class InitData { [[nodiscard]] CellBuilder writeTo() const; [[nodiscard]] StateInit makeStateInit() const; - [[nodiscard]] Address computeAddr(int8_t workchainId) const; + [[nodiscard]] AddressData computeAddr(int8_t workchainId) const; [[nodiscard]] CellBuilder makeTransferPayload(uint32_t expireAt, const Wallet::Gift& gift) const; }; diff --git a/src/Everscale/WorkchainType.h b/src/Everscale/WorkchainType.h index 786343e1065..cd52b72d15e 100644 --- a/src/Everscale/WorkchainType.h +++ b/src/Everscale/WorkchainType.h @@ -6,11 +6,8 @@ #pragma once -namespace TW::Everscale { - -enum WorkchainType { - Masterchain = -1, - Basechain = 0, -}; +#include "CommonTON/WorkchainType.h" +namespace TW::Everscale { + using WorkchainType = CommonTON::WorkchainType; } // namespace TW::Everscale diff --git a/src/HexCoding.h b/src/HexCoding.h index 8cf121ae3e0..f047065a85b 100644 --- a/src/HexCoding.h +++ b/src/HexCoding.h @@ -17,6 +17,15 @@ namespace TW { +inline bool is_hex_encoded(const std::string& s) +{ + bool with_0x = s.compare(0, 2, "0x") == 0 + && s.size() > 2 + && s.find_first_not_of("0123456789abcdefABCDEF", 2) == std::string::npos; + bool without_0x = s.find_first_not_of("0123456789abcdefABCDEF") == std::string::npos; + return with_0x || without_0x; +} + std::tuple value(uint8_t c); /// Converts a range of bytes to a hexadecimal string representation. diff --git a/src/TheOpenNetwork/Address.cpp b/src/TheOpenNetwork/Address.cpp new file mode 100644 index 00000000000..8f6a3b2b9a3 --- /dev/null +++ b/src/TheOpenNetwork/Address.cpp @@ -0,0 +1,125 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Address.h" + +#include "Base64.h" +#include "Crc.h" + +#include "WorkchainType.h" + +namespace TW::TheOpenNetwork { + +using AddressImpl = TW::CommonTON::RawAddress; + +static inline Data decodeUserFriendlyAddress(const std::string& string) { + Data decoded; + if (string.find('-') != std::string::npos || string.find('_') != std::string::npos) { + decoded = Base64::decodeBase64Url(string); + } else { + decoded = Base64::decode(string); + } + return decoded; +} + +bool Address::isValid(const std::string& string) noexcept { + if (AddressImpl::isValid(string)) { + return true; + } + + if (string.size() != b64UserFriendlyAddressLen) { + return false; + } + + if (!Base64::isBase64orBase64Url(string)) { + return false; + } + Data decoded = decodeUserFriendlyAddress(string); + + if (decoded.size() != userFriendlyAddressLen) { + return false; + } + + byte tag = decoded[0]; + if (tag & AddressTag::TEST_ONLY) { + tag ^= AddressTag::TEST_ONLY; + } + + if (tag != AddressTag::BOUNCEABLE && tag != AddressTag::NON_BOUNCEABLE) { + return false; + } + + int8_t workchainId = decoded[1]; + if (workchainId != WorkchainType::Basechain && workchainId != WorkchainType::Masterchain) { + return false; + } + + Data data(decoded.begin(), decoded.end() - 2); + Data givenCrc(decoded.end() - 2, decoded.end()); + + const uint16_t crc16 = Crc::crc16(data.data(), (uint32_t) data.size()); + const byte b1 = (crc16 >> 8) & 0xff; + const byte b2 = crc16 & 0xff; + if (b1 != givenCrc[0] || b2 != givenCrc[1]) { + return false; + } + + return true; +} + +Address::Address(const std::string& string) { + if (!Address::isValid(string)) { + throw std::invalid_argument("Invalid address string"); + } + + if (string.find(':') != std::string::npos) { + addressData = AddressImpl::splitAddress(string); + } else { + isUserFriendly = true; + + Data decoded = decodeUserFriendlyAddress(string); + addressData.workchainId = decoded[1]; + + byte tag = decoded[0]; + if (tag & AddressTag::TEST_ONLY) { + isTestOnly = true; + tag ^= AddressTag::TEST_ONLY; + } + isBounceable = (tag == AddressTag::BOUNCEABLE); + + std::copy(decoded.begin() + 2, decoded.end() - 2, addressData.hash.begin()); + } +} + +std::string Address::string() const { + return this->string(isUserFriendly, isBounceable, isTestOnly); +} + +std::string Address::string(bool userFriendly, bool bounceable, bool testOnly) const { + if (!userFriendly) { + return AddressImpl::to_string(addressData); + } + + Data data; + Data hashData(addressData.hash.begin(), addressData.hash.end()); + + byte tag = bounceable ? AddressTag::BOUNCEABLE : AddressTag::NON_BOUNCEABLE; + if (testOnly) { + tag |= AddressTag::TEST_ONLY; + } + + append(data, tag); + append(data, addressData.workchainId); + append(data, hashData); + + const uint16_t crc16 = Crc::crc16(data.data(), (uint32_t) data.size()); + append(data, (crc16 >> 8) & 0xff); + append(data, crc16 & 0xff); + + return Base64::encodeBase64Url(data); +} + +} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/Address.h b/src/TheOpenNetwork/Address.h new file mode 100644 index 00000000000..2175926f381 --- /dev/null +++ b/src/TheOpenNetwork/Address.h @@ -0,0 +1,63 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" +#include "PublicKey.h" + +#include "Everscale/CommonTON/RawAddress.h" + +#include + +namespace TW::TheOpenNetwork { + +enum AddressTag : uint8_t { + BOUNCEABLE = 0x11, + NON_BOUNCEABLE = 0x51, + TEST_ONLY = 0x80, +}; + +using AddressData = CommonTON::AddressData; + +class Address { +public: + AddressData addressData; + + /// User-friendly address lens + static const size_t b64UserFriendlyAddressLen = 48; + static const size_t userFriendlyAddressLen = 36; + + /// Determines whether the address is user-friendly + bool isUserFriendly = false; + + /// Determines whether the address is bounceable + bool isBounceable = false; + + /// Determines whether the address is for tests only + bool isTestOnly = false; + + /// Determines whether a string makes a valid address. + [[nodiscard]] static bool isValid(const std::string& string) noexcept; + + /// Initializes an address with a string representation. + explicit Address(const std::string& string); + + /// Initializes an address with its parts + explicit Address( + int8_t workchainId, std::array hash, + bool userFriendly = true, bool bounceable = true, bool testOnly = false + ) : addressData(workchainId, hash), + isUserFriendly(userFriendly), + isBounceable(bounceable), + isTestOnly(testOnly) {} + + /// Returns a string representation of the address. + [[nodiscard]] std::string string() const; + [[nodiscard]] std::string string(bool userFriendly, bool bounceable = true, bool testOnly = false) const; +}; + +} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/Entry.cpp b/src/TheOpenNetwork/Entry.cpp new file mode 100644 index 00000000000..21f2e19de1b --- /dev/null +++ b/src/TheOpenNetwork/Entry.cpp @@ -0,0 +1,33 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Entry.h" + +#include "Address.h" +#include "Signer.h" + +#include "TheOpenNetwork/wallet/WalletV4R2.h" +#include "WorkchainType.h" + +namespace TW::TheOpenNetwork { + +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, [[maybe_unused]] const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { + return Address::isValid(address); +} + +std::string Entry::normalizeAddress([[maybe_unused]] TWCoinType coin, const std::string& address) const { + return Address(address).string(true, true, false); +} + +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { + return WalletV4R2(publicKey, WorkchainType::Basechain).getAddress().string(); +} + +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { + signTemplate(dataIn, dataOut); +} + +} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/Entry.h b/src/TheOpenNetwork/Entry.h new file mode 100644 index 00000000000..a432b493bda --- /dev/null +++ b/src/TheOpenNetwork/Entry.h @@ -0,0 +1,21 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "CoinEntry.h" + +namespace TW::TheOpenNetwork { + +class Entry final : public CoinEntry { +public: + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; + std::string normalizeAddress(TWCoinType coin, const std::string& address) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; +}; + +} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/Message.cpp b/src/TheOpenNetwork/Message.cpp new file mode 100644 index 00000000000..cf76cb7df72 --- /dev/null +++ b/src/TheOpenNetwork/Message.cpp @@ -0,0 +1,38 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Message.h" + +namespace TW::TheOpenNetwork { + +Cell::Ref Message::intoCell() const { + CellBuilder builder; + + // info:CommonMsgInfo + _messageData.header->writeTo(builder); + + // init:(Maybe (Either StateInit ^StateInit)) + if (_messageData.init.has_value()) { + builder.appendBitOne(); // Maybe + + builder.appendBitOne(); // Either as ^X + builder.appendReferenceCell(_messageData.init.value().writeTo().intoCell()); + } else { + builder.appendBitZero(); + } + + // body:(Either X ^X) + if (_messageData.body.has_value()) { + builder.appendBitOne(); // Either as ^X + builder.appendReferenceCell(_messageData.body.value()); + } else { + builder.appendBitZero(); + } + + return builder.intoCell(); +} + +} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/Message.h b/src/TheOpenNetwork/Message.h new file mode 100644 index 00000000000..5b7aee9cc84 --- /dev/null +++ b/src/TheOpenNetwork/Message.h @@ -0,0 +1,28 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Everscale/CommonTON/Messages.h" + +using namespace TW::CommonTON; + +namespace TW::TheOpenNetwork { + +class Message { +private: + MessageData _messageData; + +public: + explicit Message(MessageData messageData) : _messageData(std::move(messageData)) {} + + [[nodiscard]] Cell::Ref intoCell() const; + + inline void setBody(const Cell::Ref& body) { _messageData.body = body; } + inline void setStateInit(const StateInit& stateInit) { _messageData.init = stateInit; } +}; + +} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/Signer.cpp b/src/TheOpenNetwork/Signer.cpp new file mode 100644 index 00000000000..df5e6db1a27 --- /dev/null +++ b/src/TheOpenNetwork/Signer.cpp @@ -0,0 +1,65 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Signer.h" + +#include "Base64.h" + +#include "TheOpenNetwork/wallet/WalletV4R2.h" +#include "WorkchainType.h" + +namespace TW::TheOpenNetwork { + +Data Signer::createTransferMessage(std::shared_ptr wallet, const PrivateKey& privateKey, const Proto::Transfer& transfer) { + const auto msg = wallet->createTransferMessage( + privateKey, + Address(transfer.dest()), + transfer.amount(), + transfer.sequence_number(), + static_cast(transfer.mode()), + transfer.expire_at(), + transfer.comment() + ); + + Data result{}; + msg->serialize(result); + return result; +} + +Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept { + const auto& privateKey = PrivateKey(input.private_key()); + const auto& publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519); + + auto protoOutput = Proto::SigningOutput(); + + switch (input.action_oneof_case()) { + case Proto::SigningInput::ActionOneofCase::kTransfer: { + const auto& transfer = input.transfer(); + + try { + switch (transfer.wallet_version()) { + case Proto::WalletVersion::WALLET_V4_R2: { + const int8_t workchainId = WorkchainType::Basechain; + auto wallet = std::make_shared(publicKey, workchainId); + const auto& transferMessage = Signer::createTransferMessage(wallet, privateKey, transfer); + protoOutput.set_encoded(TW::Base64::encode(transferMessage)); + break; + } + default: + protoOutput.set_error(Common::Proto::Error_invalid_params); + protoOutput.set_error_message("Unsupported wallet version"); + break; + } + } catch (...) { } + break; + } + default: + break; + } + return protoOutput; +} + +} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/Signer.h b/src/TheOpenNetwork/Signer.h new file mode 100644 index 00000000000..2ca74fa7cb8 --- /dev/null +++ b/src/TheOpenNetwork/Signer.h @@ -0,0 +1,30 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" +#include "PrivateKey.h" +#include "wallet/Wallet.h" + +#include "proto/TheOpenNetwork.pb.h" + +namespace TW::TheOpenNetwork { + +/// Helper class that performs TheOpenNetwork transaction signing. +class Signer { +public: + /// Hide default constructor + Signer() = delete; + + /// Creates a signed transfer message + static Data createTransferMessage(std::shared_ptr wallet, const PrivateKey& privateKey, const Proto::Transfer& transfer); + + /// Signs a Proto::SigningInput transaction + static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept; +}; + +} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/WorkchainType.h b/src/TheOpenNetwork/WorkchainType.h new file mode 100644 index 00000000000..9d5e4f43386 --- /dev/null +++ b/src/TheOpenNetwork/WorkchainType.h @@ -0,0 +1,13 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Everscale/CommonTON/WorkchainType.h" + +namespace TW::TheOpenNetwork { + using WorkchainType = CommonTON::WorkchainType; +} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/wallet/Wallet.cpp b/src/TheOpenNetwork/wallet/Wallet.cpp new file mode 100644 index 00000000000..8a381ecf8a3 --- /dev/null +++ b/src/TheOpenNetwork/wallet/Wallet.cpp @@ -0,0 +1,94 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Wallet.h" + +#include "HexCoding.h" + +namespace TW::TheOpenNetwork { + +static const uint32_t standard_wallet_id = 698983191; + +Wallet::Wallet(PublicKey publicKey, int8_t workchainId, Data walletCode) + : publicKey(std::move(publicKey)) + , workchainId(workchainId) + , walletCode(std::move(walletCode)) + , walletId(standard_wallet_id + workchainId) { +} + +Address Wallet::getAddress() const { + const auto stateInit = this->createStateInit(); + return Address(workchainId, stateInit.writeTo().intoCell()->hash); +} + +CommonTON::StateInit Wallet::createStateInit() const { + Cell::Ref code = Cell::deserialize(walletCode.data(), walletCode.size()); + Cell::Ref data = this->createDataCell(); + return StateInit{code, data}; +} + +Cell::Ref Wallet::createSigningMessage( + const Address& dest, + uint64_t amount, + uint32_t sequence_number, + uint8_t mode, + uint32_t expireAt, + const std::string& comment +) const { + CellBuilder builder; + this->writeSigningPayload(builder, sequence_number, expireAt); + builder.appendU8(mode); + + { // Add internal message as a reference cell + const auto header = std::make_shared(true, dest.isBounceable, dest.addressData, amount); + TheOpenNetwork::Message internalMessage = TheOpenNetwork::Message(MessageData(header)); + + CellBuilder bodyBuilder; + if (!comment.empty()) { + const auto& data = Data(comment.begin(), comment.end()); + bodyBuilder.appendU32(0); + bodyBuilder.appendRaw(data, static_cast(data.size()) * 8); + } + internalMessage.setBody(bodyBuilder.intoCell()); + + builder.appendReferenceCell(internalMessage.intoCell()); + } + + return builder.intoCell(); +} + +Cell::Ref Wallet::createTransferMessage( + const PrivateKey& privateKey, + const Address& dest, + uint64_t amount, + uint32_t sequence_number, + uint8_t mode, + uint32_t expireAt, + const std::string& comment +) const { + const auto transferMessageHeader = std::make_shared(this->getAddress().addressData); + Message transferMessage = Message(MessageData(transferMessageHeader)); + if (sequence_number == 0) { + const auto stateInit = this->createStateInit(); + transferMessage.setStateInit(stateInit); + } + + { // Set body of transfer message + CellBuilder bodyBuilder; + const Cell::Ref signingMessage = this->createSigningMessage(dest, amount, sequence_number, mode, expireAt, comment); + Data data(signingMessage->hash.begin(), signingMessage->hash.end()); + const auto signature = privateKey.sign(data, TWCurveED25519); + + bodyBuilder.appendRaw(signature, static_cast(signature.size()) * 8); + bodyBuilder.appendCellSlice(CellSlice(signingMessage.get())); + + transferMessage.setBody(bodyBuilder.intoCell()); + } + + return transferMessage.intoCell(); +} + +} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/wallet/Wallet.h b/src/TheOpenNetwork/wallet/Wallet.h new file mode 100644 index 00000000000..8e081363957 --- /dev/null +++ b/src/TheOpenNetwork/wallet/Wallet.h @@ -0,0 +1,59 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "PublicKey.h" +#include "PrivateKey.h" + +#include "TheOpenNetwork/Address.h" +#include "TheOpenNetwork/Message.h" + +#include "Everscale/CommonTON/Messages.h" + +namespace TW::TheOpenNetwork { + +class Wallet { +protected: + PublicKey publicKey; + int8_t workchainId; + + // Explore standard codes: https://github.com/toncenter/tonweb/blob/master/src/contract/wallet/WalletSources.md + const Data walletCode; + const uint32_t walletId; + +public: + explicit Wallet(PublicKey publicKey, int8_t workchainId, Data walletCode); + virtual ~Wallet() noexcept = default; + + [[nodiscard]] Address getAddress() const; + [[nodiscard]] Cell::Ref createTransferMessage( + const PrivateKey& privateKey, + const Address& dest, + uint64_t amount, + uint32_t sequence_number, + uint8_t mode, + uint32_t expireAt = 0, + const std::string& comment = "" + ) const; + +protected: + [[nodiscard]] virtual Cell::Ref createDataCell() const = 0; + virtual void writeSigningPayload(CellBuilder& builder, uint32_t sequence_number = 0, uint32_t expireAt = 0) const = 0; + +private: + [[nodiscard]] Cell::Ref createSigningMessage( + const Address& dest, + uint64_t amount, + uint32_t sequence_number, + uint8_t mode, + uint32_t expireAt = 0, + const std::string& comment = "" + ) const; + [[nodiscard]] CommonTON::StateInit createStateInit() const; +}; + +} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/wallet/WalletV4R2.cpp b/src/TheOpenNetwork/wallet/WalletV4R2.cpp new file mode 100644 index 00000000000..392129c48d7 --- /dev/null +++ b/src/TheOpenNetwork/wallet/WalletV4R2.cpp @@ -0,0 +1,54 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "WalletV4R2.h" + +#include "HexCoding.h" + +#include + +namespace TW::TheOpenNetwork { + +// WalletV4R2 contract func https://github.com/ton-blockchain/wallet-contract/blob/4111fd9e3313ec17d99ca9b5b1656445b5b49d8f/func/wallet-v4-code.fc +// Contract codes https://github.com/toncenter/tonweb/blob/master/src/contract/wallet/WalletSources.md +const Data WalletV4R2::code = parse_hex("B5EE9C72410214010002D4000114FF00F4A413F4BCF2C80B010201200203020148040504F8F28308D71820D31FD31FD31F02F823BBF264ED44D0D31FD31FD3FFF404D15143BAF2A15151BAF2A205F901541064F910F2A3F80024A4C8CB1F5240CB1F5230CBFF5210F400C9ED54F80F01D30721C0009F6C519320D74A96D307D402FB00E830E021C001E30021C002E30001C0039130E30D03A4C8CB1F12CB1FCBFF1011121302E6D001D0D3032171B0925F04E022D749C120925F04E002D31F218210706C7567BD22821064737472BDB0925F05E003FA403020FA4401C8CA07CBFFC9D0ED44D0810140D721F404305C810108F40A6FA131B3925F07E005D33FC8258210706C7567BA923830E30D03821064737472BA925F06E30D06070201200809007801FA00F40430F8276F2230500AA121BEF2E0508210706C7567831EB17080185004CB0526CF1658FA0219F400CB6917CB1F5260CB3F20C98040FB0006008A5004810108F45930ED44D0810140D720C801CF16F400C9ED540172B08E23821064737472831EB17080185005CB055003CF1623FA0213CB6ACB1FCB3FC98040FB00925F03E20201200A0B0059BD242B6F6A2684080A06B90FA0218470D4080847A4937D29910CE6903E9FF9837812801B7810148987159F31840201580C0D0011B8C97ED44D0D70B1F8003DB29DFB513420405035C87D010C00B23281F2FFF274006040423D029BE84C600201200E0F0019ADCE76A26840206B90EB85FFC00019AF1DF6A26840106B90EB858FC0006ED207FA00D4D422F90005C8CA0715CBFFC9D077748018C8CB05CB0222CF165005FA0214CB6B12CCCCC973FB00C84014810108F451F2A7020070810108D718FA00D33FC8542047810108F451F2A782106E6F746570748018C8CB05CB025006CF165004FA0214CB6A12CB1FCB3FC973FB0002006C810108D718FA00D33F305224810108F459F2A782106473747270748018C8CB05CB025005CF165003FA0213CB6ACB1F12CB3FC973FB00000AF400C9ED54696225E5"); + +WalletV4R2::WalletV4R2(PublicKey publicKey, int8_t workchainId) + : Wallet( + std::move(publicKey), + workchainId, + WalletV4R2::code + ) { +} + +Cell::Ref WalletV4R2::createDataCell() const { + CellBuilder builder; + + builder.appendU32(0); // sequence_number + builder.appendU32(walletId); + builder.appendRaw(publicKey.bytes, 256); + builder.appendBitZero(); // no plugins + + return builder.intoCell(); +} + +void WalletV4R2::writeSigningPayload(CellBuilder& builder, uint32_t sequence_number, uint32_t expireAt) const { + builder.appendU32(walletId); + if (sequence_number == 0) { + builder.appendU32(0xffffffff); + } else { + if (expireAt == 0) { + expireAt = (uint32_t) duration_cast( + std::chrono::system_clock::now().time_since_epoch() + ).count() + 60; // TON v4 wallet requires uint32 for now + } + builder.appendU32(expireAt); + } + builder.appendU32(sequence_number); + builder.appendU8(0); +} + +} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/wallet/WalletV4R2.h b/src/TheOpenNetwork/wallet/WalletV4R2.h new file mode 100644 index 00000000000..82ec5f34959 --- /dev/null +++ b/src/TheOpenNetwork/wallet/WalletV4R2.h @@ -0,0 +1,24 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Wallet.h" + +namespace TW::TheOpenNetwork { + +class WalletV4R2 : public Wallet { +public: + explicit WalletV4R2(PublicKey publicKey, int8_t workchainId); + + static const Data code; + +private: + [[nodiscard]] Cell::Ref createDataCell() const override; + void writeSigningPayload(CellBuilder& builder, uint32_t sequence_number = 0, uint32_t expireAt = 0) const override; +}; + +} // namespace TW::TheOpenNetwork diff --git a/src/proto/TheOpenNetwork.proto b/src/proto/TheOpenNetwork.proto new file mode 100644 index 00000000000..12d818a828c --- /dev/null +++ b/src/proto/TheOpenNetwork.proto @@ -0,0 +1,75 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +syntax = "proto3"; + +package TW.TheOpenNetwork.Proto; +option java_package = "wallet.core.jni.proto"; + +import "Common.proto"; + +enum WalletVersion { + WALLET_V3_R1 = 0; + WALLET_V3_R2 = 1; + WALLET_V4_R2 = 2; +}; + +enum SendMode { + DEFAULT = 0; + PAY_FEES_SEPARATELY = 1; + IGNORE_ACTION_PHASE_ERRORS = 2; + DESTROY_ON_ZERO_BALANCE = 32; + ATTACH_ALL_INBOUND_MESSAGE_VALUE = 64; + ATTACH_ALL_CONTRACT_BALANCE = 128; +}; + +message Transfer { + // Wallet version + WalletVersion wallet_version = 1; + + // Recipient address + string dest = 2; + + // Amount to send in nanotons + uint64 amount = 3; + + // Message counter (optional, 0 by default used for the first deploy) + // This field is required, because we need to protect the smart contract against "replay attacks" + // Learn more: https://ton.org/docs/develop/smart-contracts/guidelines/external-messages + uint32 sequence_number = 4; + + // Send mode (optional, 0 by default) + // Learn more: https://ton.org/docs/develop/func/stdlib#send_raw_message + uint32 mode = 5; + + // Expiration UNIX timestamp (optional, now() + 60 by default) + uint32 expire_at = 6; + + // Transfer comment message (optional, empty by default) + string comment = 7; +} + +message SigningInput { + // The secret private key used for signing (32 bytes). + bytes private_key = 1; + + // The payload transfer + oneof action_oneof { + Transfer transfer = 2; + } +} + +// Transaction signing output. +message SigningOutput { + // Signed and base64 encoded BOC message + string encoded = 1; + + // error code, 0 is ok, other codes will be treated as errors + Common.Proto.SigningError error = 2; + + // error code description + string error_message = 3; +} diff --git a/swift/Tests/Blockchains/TheOpenNetworkTests.swift b/swift/Tests/Blockchains/TheOpenNetworkTests.swift new file mode 100644 index 00000000000..506d007fb9d --- /dev/null +++ b/swift/Tests/Blockchains/TheOpenNetworkTests.swift @@ -0,0 +1,62 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import WalletCore +import XCTest + +class TheOpenNetworkTests: XCTestCase { + func testAddressFromPrivateKey() { + let data = Data(hexString: "63474e5fe9511f1526a50567ce142befc343e71a49b865ac3908f58667319cb8") + let privateKey = PrivateKey(data: data!)! + let publicKey = privateKey.getPublicKeyEd25519() + let address = AnyAddress(publicKey: publicKey, coin: .ton) + XCTAssertEqual(address.description, "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q") + } + + func testAddressFromPublicKey() { + let data = Data(hexString: "f42c77f931bea20ec5d0150731276bbb2e2860947661245b2319ef8133ee8d41") + let publicKey = PublicKey(data: data!, type: PublicKeyType.ed25519)! + let address = AnyAddress(publicKey: publicKey, coin: .ton) + XCTAssertEqual(address.description, "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q") + } + + func testAddressFromRawString() { + let addressString = "0:66fbe3c5c03bf5c82792f904c9f8bf28894a6aa3d213d41c20569b654aadedb3" + let address = AnyAddress(string: addressString, coin: .ton) + XCTAssertEqual(address!.description, "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q") + } + + func testAddressFromUserFriendlyString() { + let addressString = "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q" + let address = AnyAddress(string: addressString, coin: .ton) + XCTAssertEqual(address!.description, "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q") + } + + func testSign() { + let privateKeyData = Data(hexString: "c38f49de2fb13223a9e7d37d5d0ffbdd89a5eb7c8b0ee4d1c299f2cefe7dc4a0")! + + let transfer = TheOpenNetworkTransfer.with { + $0.walletVersion = TheOpenNetworkWalletVersion.walletV4R2 + $0.dest = "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q" + $0.amount = 10 + $0.sequenceNumber = 6 + $0.mode = UInt32(TheOpenNetworkSendMode.payFeesSeparately.rawValue | TheOpenNetworkSendMode.ignoreActionPhaseErrors.rawValue) + $0.expireAt = 1671132440 + } + + let input = TheOpenNetworkSigningInput.with { + $0.transfer = transfer + $0.privateKey = privateKeyData + } + + let output: TheOpenNetworkSigningOutput = AnySigner.sign(input: input, coin: .ton) + + // tx: https://tonscan.org/tx/3Z4tHpXNLyprecgu5aTQHWtY7dpHXEoo11MAX61Xyg0= + let expectedString = "te6ccgICAAQAAQAAALAAAAFFiAGwt/q8k4SrjbFbQCjJZfQr64ExRxcUMsWqaQODqTUijgwAAQGcEUPkil2aZ4s8KKparSep/OKHMC8vuXafFbW2HGp/9AcTRv0J5T4dwyW1G0JpHw+g5Ov6QI3Xo0O9RFr3KidICimpoxdjm3UYAAAABgADAAIBYmIAM33x4uAd+uQTyXyCZPxflESlNVHpCeoOECtNsqVW9tmIUAAAAAAAAAAAAAAAAAEAAwAA" + + XCTAssertEqual(output.encoded, expectedString) + } +} diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 6b5a84791be..3d46f67044c 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -253,6 +253,9 @@ class CoinAddressDerivationTests: XCTestCase { case .everscale: let expectedResult = "0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04"; assertCoinDerivation(coin, expectedResult, derivedAddress, address) + case .ton: + let expectedResult = "EQDgEMqToTacHic7SnvnPFmvceG5auFkCcAw0mSCvzvKUfk9"; + assertCoinDerivation(coin, expectedResult, derivedAddress, address) case .aptos: let expectedResult = "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"; assertCoinDerivation(coin, expectedResult, derivedAddress, address) diff --git a/tests/chains/Everscale/CellBuilderTest.cpp b/tests/chains/Everscale/CellBuilderTest.cpp index 860f3bac6e5..9bc0d05bb2f 100644 --- a/tests/chains/Everscale/CellBuilderTest.cpp +++ b/tests/chains/Everscale/CellBuilderTest.cpp @@ -8,13 +8,12 @@ #include "HexCoding.h" #include "PublicKey.h" -#include "Everscale/Cell.h" -#include "Everscale/CellBuilder.h" +#include "Everscale/CommonTON/Cell.h" +#include "Everscale/CommonTON/CellBuilder.h" #include "Everscale/Wallet.h" #include -using namespace TW; using boost::multiprecision::uint128_t; namespace TW::Everscale { diff --git a/tests/chains/Everscale/CellTests.cpp b/tests/chains/Everscale/CellTests.cpp index c9b1b821cb9..28bd22b81d2 100644 --- a/tests/chains/Everscale/CellTests.cpp +++ b/tests/chains/Everscale/CellTests.cpp @@ -5,16 +5,14 @@ // file LICENSE at the root of the source code distribution tree. #include "Base64.h" -#include "Everscale/Cell.h" -#include "Everscale/Wallet.h" #include "HexCoding.h" -#include -#include + +#include "Everscale/CommonTON/Cell.h" +#include "Everscale/Wallet.h" + #include #include -using namespace TW; - namespace TW::Everscale { // All hashes could be verified using https://ever.bytie.moe/visualizer diff --git a/tests/chains/TheOpenNetwork/AddressTests.cpp b/tests/chains/TheOpenNetwork/AddressTests.cpp new file mode 100644 index 00000000000..8bc16cdb0a0 --- /dev/null +++ b/tests/chains/TheOpenNetwork/AddressTests.cpp @@ -0,0 +1,116 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "PublicKey.h" +#include "PrivateKey.h" + +#include "TheOpenNetwork/Address.h" +#include "TheOpenNetwork/wallet/WalletV4R2.h" +#include "TheOpenNetwork/WorkchainType.h" + +#include + +namespace TW::TheOpenNetwork::tests { + +TEST(TheOpenNetworkAddress, Valid) { + ASSERT_TRUE(Address::isValid("-1:8a8627861a5dd96c9db3ce0807b122da5ed473934ce7568a5b4b1c361cbb28ae")); + ASSERT_TRUE(Address::isValid("0:8a8627861a5dd96c9db3ce0807b122da5ed473934ce7568a5b4b1c361cbb28ae")); + + // user-friendly, b64urlsafe + ASSERT_TRUE(Address::isValid("EQCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorkdl")); + ASSERT_TRUE(Address::isValid("EQBGqFmKe3oY8PChYN9g92ZEV2ybkzVB-hCiesQRn5mFnrNv")); + ASSERT_TRUE(Address::isValid("Ef8JfFPRpHBV_tZpCurvxMJW69nt2js3SuGEWojGnOpCVPRe")); + ASSERT_TRUE(Address::isValid("Ef_drj6m7jcME0fWTA-OwFC-6F0Le2SuOUQ6ibRc3Vz8HL8H")); + + // user-friendly, b64 + ASSERT_TRUE(Address::isValid("EQAN6Dr3vziti1Kp9D3aEFqJX4bBVfCaV57Z+9jwKTBXICv8")); + ASSERT_TRUE(Address::isValid("EQCmGW+z+UL00FmnhWaMvJq/i86YY5GlJP3uJW19KC5Tzq4C")); +} + +TEST(TheOpenNetworkAddress, Invalid) { + ASSERT_FALSE(Address::isValid("random string")); + + // invalid size + ASSERT_FALSE(Address::isValid("EQIcIZpPoMnWXd8FbC1KaLtcyIgVUlwsbFK_3P6f5uf_YyzoE")); + ASSERT_FALSE(Address::isValid("EQIcIZpPoMnWXd8FbC1KaLtcyIgVUlwsbFK_3P6f5uf_YyE")); + + // invalid size after decode + ASSERT_FALSE(Address::isValid("EQIcIZpPoMnWXd8FbC1KaLtcyIgVUlwsbFK_3P6f5uf_Yyw=")); + + // invalid workchain + ASSERT_FALSE(Address::isValid("1:0ccd5119f27f7fe4614476c34f7e5e93c7ae098e577cf2012f8b8043165cb809")); + ASSERT_FALSE(Address::isValid("EQEMzVEZ8n9_5GFEdsNPfl6Tx64Jjld88gEvi4BDFly4CSyl")); + ASSERT_FALSE(Address::isValid("-2:e0e98cfcf743292298ad9e379a3c2e6401797b9cbfc0fe98b4e14fd0ce07ecdf")); + ASSERT_FALSE(Address::isValid("Ef7g6Yz890MpIpitnjeaPC5kAXl7nL_A_pi04U_Qzgfs3-Cj")); + + // invalid tag + ASSERT_FALSE(Address::isValid("MwCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorsn8")); // 0x33 + ASSERT_FALSE(Address::isValid("swCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsornJ2")); // 0x80 + 0x33 + + // invalid crc + ASSERT_FALSE(Address::isValid("EQCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsormVH")); // crc[a, b] = crc[b, a] + ASSERT_FALSE(Address::isValid("EQCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorpcF")); // crc=0x9705 +} + +TEST(TheOpenNetworkAddress, FromString) { + auto raw_address = Address("0:8a8627861a5dd96c9db3ce0807b122da5ed473934ce7568a5b4b1c361cbb28ae"); + ASSERT_EQ(raw_address.string(), "0:8a8627861a5dd96c9db3ce0807b122da5ed473934ce7568a5b4b1c361cbb28ae"); + ASSERT_FALSE(raw_address.isUserFriendly); + + auto raw_address_uppercase = Address("0:8A8627861A5DD96C9DB3CE0807B122DA5ED473934CE7568A5B4B1C361CBB28AE"); + ASSERT_EQ(raw_address_uppercase.string(), "0:8a8627861a5dd96c9db3ce0807b122da5ed473934ce7568a5b4b1c361cbb28ae"); + ASSERT_FALSE(raw_address_uppercase.isUserFriendly); + + // 0x11 + auto bounceable_address = Address("EQCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorkdl"); + ASSERT_EQ(bounceable_address.string(), "EQCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorkdl"); + ASSERT_TRUE(bounceable_address.isUserFriendly); + ASSERT_TRUE(bounceable_address.isBounceable); + ASSERT_FALSE(bounceable_address.isTestOnly); + + // 0x51 + auto non_bounceable_address = Address("UQCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorhqg"); + ASSERT_EQ(non_bounceable_address.string(), "UQCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorhqg"); + ASSERT_TRUE(non_bounceable_address.isUserFriendly); + ASSERT_FALSE(non_bounceable_address.isBounceable); + ASSERT_FALSE(non_bounceable_address.isTestOnly); + + // 0x11 | 0x80 + auto test_bounceable_address = Address("kQCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorvzv"); + ASSERT_EQ(test_bounceable_address.string(), "kQCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorvzv"); + ASSERT_TRUE(test_bounceable_address.isUserFriendly); + ASSERT_TRUE(test_bounceable_address.isBounceable); + ASSERT_TRUE(test_bounceable_address.isTestOnly); + + // 0x51 | 0x80 + auto test_non_bounceable_address = Address("0QCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorqEq"); + ASSERT_EQ(test_non_bounceable_address.string(), "0QCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorqEq"); + ASSERT_TRUE(test_non_bounceable_address.isUserFriendly); + ASSERT_FALSE(test_non_bounceable_address.isBounceable); + ASSERT_TRUE(test_non_bounceable_address.isTestOnly); +} + +TEST(TheOpenNetworkAddress, FromPrivateKeyV4R2) { + const auto privateKey = PrivateKey(parse_hex("ff3ceb81a22c726e9d61d3f336fc783de5d60020972ca3abc27b99e3cf573a88")); + const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519); + + WalletV4R2 wallet(publicKey, WorkchainType::Basechain); + const auto address = wallet.getAddress(); + + ASSERT_EQ(address.string(), "EQCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorkdl"); +} + +TEST(TheOpenNetworkAddress, FromPublicKeyV4R2) { + const auto publicKey = PublicKey(parse_hex("c2036a1ca901059e1d1ab38cd7a7a4709b5e8f9d85b387f0514d7adae70b6afe"), TWPublicKeyTypeED25519); + + WalletV4R2 wallet(publicKey, WorkchainType::Basechain); + const auto address = wallet.getAddress(); + + ASSERT_EQ(address.string(), "EQCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorkdl"); +} + +} // namespace TW::TheOpenNetwork::tests diff --git a/tests/chains/TheOpenNetwork/SignerTests.cpp b/tests/chains/TheOpenNetwork/SignerTests.cpp new file mode 100644 index 00000000000..2a108204b01 --- /dev/null +++ b/tests/chains/TheOpenNetwork/SignerTests.cpp @@ -0,0 +1,166 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" + +#include "TheOpenNetwork/Signer.h" +#include "Everscale/CommonTON/Cell.h" + +#include + +namespace TW::TheOpenNetwork::tests { + +TEST(TheOpenNetworkSigner, TransferAndDeploy) { + auto input = Proto::SigningInput(); + + auto& transfer = *input.mutable_transfer(); + transfer.set_wallet_version(Proto::WALLET_V4_R2); + transfer.set_dest("EQDYW_1eScJVxtitoBRksvoV9cCYo4uKGWLVNIHB1JqRR3n0"); + transfer.set_amount(10); + transfer.set_mode(Proto::SendMode::PAY_FEES_SEPARATELY | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS); + transfer.set_expire_at(1671135440); + + const auto privateKey = parse_hex("63474e5fe9511f1526a50567ce142befc343e71a49b865ac3908f58667319cb8"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input); + + ASSERT_EQ(hex(CommonTON::Cell::fromBase64(output.encoded())->hash), "b3d9462c13a8c67e19b62002447839c386de51415ace3ff6473b1e6294299819"); + + // tx: https://tonscan.org/tx/6ZzWOFKZt_m3kZjbwfbATwLaVwmUOdDp0xjhuY7PO3k= + ASSERT_EQ(output.encoded(), "te6ccgICABoAAQAAA8sAAAJFiADN98eLgHfrkE8l8gmT8X5REpTVR6QnqDhArTbKlVvbZh4ABAABAZznxvGBhoRXhPogxNY8QmHlihJWxg5t6KptqcAIZlVks1r+Z+r1avCWNCeqeLC/oaiVN4mDx/E1+Zhi33G25rcIKamjF/////8AAAAAAAMAAgFiYgBsLf6vJOEq42xW0AoyWX0K+uBMUcXFDLFqmkDg6k1Io4hQAAAAAAAAAAAAAAAAAQADAAACATQABgAFAFEAAAAAKamjF/Qsd/kxvqIOxdAVBzEna7suKGCUdmEkWyMZ74Ez7o1BQAEU/wD0pBP0vPLICwAHAgEgAA0ACAT48oMI1xgg0x/TH9MfAvgju/Jk7UTQ0x/TH9P/9ATRUUO68qFRUbryogX5AVQQZPkQ8qP4ACSkyMsfUkDLH1Iwy/9SEPQAye1U+A8B0wchwACfbFGTINdKltMH1AL7AOgw4CHAAeMAIcAC4wABwAORMOMNA6TIyx8Syx/L/wAMAAsACgAJAAr0AMntVABsgQEI1xj6ANM/MFIkgQEI9Fnyp4IQZHN0cnB0gBjIywXLAlAFzxZQA/oCE8tqyx8Syz/Jc/sAAHCBAQjXGPoA0z/IVCBHgQEI9FHyp4IQbm90ZXB0gBjIywXLAlAGzxZQBPoCFMtqEssfyz/Jc/sAAgBu0gf6ANTUIvkABcjKBxXL/8nQd3SAGMjLBcsCIs8WUAX6AhTLaxLMzMlz+wDIQBSBAQj0UfKnAgIBSAAXAA4CASAAEAAPAFm9JCtvaiaECAoGuQ+gIYRw1AgIR6STfSmRDOaQPp/5g3gSgBt4EBSJhxWfMYQCASAAEgARABG4yX7UTQ1wsfgCAVgAFgATAgEgABUAFAAZrx32omhAEGuQ64WPwAAZrc52omhAIGuQ64X/wAA9sp37UTQgQFA1yH0BDACyMoHy//J0AGBAQj0Cm+hMYALm0AHQ0wMhcbCSXwTgItdJwSCSXwTgAtMfIYIQcGx1Z70ighBkc3RyvbCSXwXgA/pAMCD6RAHIygfL/8nQ7UTQgQFA1yH0BDBcgQEI9ApvoTGzkl8H4AXTP8glghBwbHVnupI4MOMNA4IQZHN0crqSXwbjDQAZABgAilAEgQEI9Fkw7UTQgQFA1yDIAc8W9ADJ7VQBcrCOI4IQZHN0coMesXCAGFAFywVQA88WI/oCE8tqyx/LP8mAQPsAkl8D4gB4AfoA9AQw+CdvIjBQCqEhvvLgUIIQcGx1Z4MesXCAGFAEywUmzxZY+gIZ9ADLaRfLH1Jgyz8gyYBA+wAG"); +} + +TEST(TheOpenNetworkSigner, TransferOrdinary) { + auto input = Proto::SigningInput(); + + auto& transfer = *input.mutable_transfer(); + transfer.set_wallet_version(Proto::WALLET_V4_R2); + transfer.set_dest("EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q"); + transfer.set_amount(10); + transfer.set_sequence_number(6); + transfer.set_mode(Proto::SendMode::PAY_FEES_SEPARATELY | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS); + transfer.set_expire_at(1671132440); + + const auto privateKey = parse_hex("c38f49de2fb13223a9e7d37d5d0ffbdd89a5eb7c8b0ee4d1c299f2cefe7dc4a0"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input); + + ASSERT_EQ(hex(CommonTON::Cell::fromBase64(output.encoded())->hash), "3908cf8b570c1d3d261c62620c9f368db11f6e821a07614cff64de2e7319f81b"); + + // tx: https://tonscan.org/tx/3Z4tHpXNLyprecgu5aTQHWtY7dpHXEoo11MAX61Xyg0= + ASSERT_EQ(output.encoded(), "te6ccgICAAQAAQAAALAAAAFFiAGwt/q8k4SrjbFbQCjJZfQr64ExRxcUMsWqaQODqTUijgwAAQGcEUPkil2aZ4s8KKparSep/OKHMC8vuXafFbW2HGp/9AcTRv0J5T4dwyW1G0JpHw+g5Ov6QI3Xo0O9RFr3KidICimpoxdjm3UYAAAABgADAAIBYmIAM33x4uAd+uQTyXyCZPxflESlNVHpCeoOECtNsqVW9tmIUAAAAAAAAAAAAAAAAAEAAwAA"); +} + +TEST(TheOpenNetworkSigner, TransferAllBalance) { + auto input = Proto::SigningInput(); + + auto& transfer = *input.mutable_transfer(); + transfer.set_wallet_version(Proto::WALLET_V4_R2); + transfer.set_dest("EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q"); + transfer.set_amount(0); + transfer.set_sequence_number(7); + transfer.set_mode(Proto::SendMode::ATTACH_ALL_CONTRACT_BALANCE | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS); + transfer.set_expire_at(1681102222); + + const auto privateKey = parse_hex("c38f49de2fb13223a9e7d37d5d0ffbdd89a5eb7c8b0ee4d1c299f2cefe7dc4a0"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input); + + ASSERT_EQ(hex(CommonTON::Cell::fromBase64(output.encoded())->hash), "d5c5980c9083f697a7f114426effbbafac6d5c88554297d290eb65c8def3008e"); + + // tx: https://tonscan.org/tx/cVcXgI9DWNWlN2iyTsteaWJckTswVqWZnRVvX5krXeA= + ASSERT_EQ(output.encoded(), "te6ccgICAAQAAQAAAK8AAAFFiAGwt/q8k4SrjbFbQCjJZfQr64ExRxcUMsWqaQODqTUijgwAAQGc58rMUQc/u78bg+Wtt8ETkyM0udf7S+F7wWk7lnPib2KChnBx9dZ7a/zLzhfLq+W9LjLZZfx995J17+0sbkvGCympoxdkM5WOAAAABwCCAAIBYGIAM33x4uAd+uQTyXyCZPxflESlNVHpCeoOECtNsqVW9tmAAAAAAAAAAAAAAAAAAQADAAA="); +} + +TEST(TheOpenNetworkSigner, TransferAllBalanceNonBounceable) { + auto input = Proto::SigningInput(); + + auto& transfer = *input.mutable_transfer(); + transfer.set_wallet_version(Proto::WALLET_V4_R2); + transfer.set_dest("UQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts4DV"); + transfer.set_amount(0); + transfer.set_sequence_number(8); + transfer.set_mode(Proto::SendMode::ATTACH_ALL_CONTRACT_BALANCE | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS); + transfer.set_expire_at(1681102222); + + const auto privateKey = parse_hex("c38f49de2fb13223a9e7d37d5d0ffbdd89a5eb7c8b0ee4d1c299f2cefe7dc4a0"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input); + + ASSERT_EQ(hex(CommonTON::Cell::fromBase64(output.encoded())->hash), "e9c816780fa8e578bae309c2e098db8eb16aa25545b3ad2b61bb711ec9562795"); + + // tx: https://tonscan.org/tx/0sJkPKu6u6uObVRuSWGd_bVGiyy5lJuzEKDqSXifQEA= + ASSERT_EQ(output.encoded(), "te6ccgICAAQAAQAAAK8AAAFFiAGwt/q8k4SrjbFbQCjJZfQr64ExRxcUMsWqaQODqTUijgwAAQGcRQQvxdU1u4QoE2Pas0AsZQMc9lea3+wtSvaC6QfLUlyJ9oISMCFnaErpyFHelDhPu4iuZqhkoLwjkR1VYhFSCimpoxdkM5WOAAAACACCAAIBYEIAM33x4uAd+uQTyXyCZPxflESlNVHpCeoOECtNsqVW9tmAAAAAAAAAAAAAAAAAAQADAAA="); +} + +TEST(TheOpenNetworkSigner, TransferWithASCIIComment) { + auto input = Proto::SigningInput(); + + auto& transfer = *input.mutable_transfer(); + transfer.set_wallet_version(Proto::WALLET_V4_R2); + transfer.set_dest("EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q"); + transfer.set_amount(10); + transfer.set_sequence_number(10); + transfer.set_mode(Proto::SendMode::PAY_FEES_SEPARATELY | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS); + transfer.set_expire_at(1681102222); + transfer.set_comment("test comment"); + + const auto privateKey = parse_hex("c38f49de2fb13223a9e7d37d5d0ffbdd89a5eb7c8b0ee4d1c299f2cefe7dc4a0"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input); + + ASSERT_EQ(hex(CommonTON::Cell::fromBase64(output.encoded())->hash), "a8c6943d5587f590c43fcdb0e894046f1965c615e19bcaf0c8407e9ccb74518d"); + + // tx: https://tonscan.org/tx/9wjD-VrgEDpa0D9u1g03KSD7kvTNsxRocR7LEdQtCNQ= + ASSERT_EQ(output.encoded(), "te6ccgICAAQAAQAAAMAAAAFFiAGwt/q8k4SrjbFbQCjJZfQr64ExRxcUMsWqaQODqTUijgwAAQGcY4XlvKqu7spxyjL6vyBSKjbskDgqkHhqBsdTe900RGrzExtpvwc04j94v8HOczEWSMCXjTXk0z+CVUXSL54qCimpoxdkM5WOAAAACgADAAIBYmIAM33x4uAd+uQTyXyCZPxflESlNVHpCeoOECtNsqVW9tmIUAAAAAAAAAAAAAAAAAEAAwAgAAAAAHRlc3QgY29tbWVudA=="); +} + +TEST(TheOpenNetworkSigner, TransferWithUTF8Comment) { + auto input = Proto::SigningInput(); + + auto& transfer = *input.mutable_transfer(); + transfer.set_wallet_version(Proto::WALLET_V4_R2); + transfer.set_dest("EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q"); + transfer.set_amount(10); + transfer.set_sequence_number(11); + transfer.set_mode(Proto::SendMode::PAY_FEES_SEPARATELY | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS); + transfer.set_expire_at(1681102222); + transfer.set_comment("тестовый комментарий"); + + const auto privateKey = parse_hex("c38f49de2fb13223a9e7d37d5d0ffbdd89a5eb7c8b0ee4d1c299f2cefe7dc4a0"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input); + + ASSERT_EQ(hex(CommonTON::Cell::fromBase64(output.encoded())->hash), "1091dfae81583d3972825633592c24eab0d3d74c91f60fda9d4afe7535103633"); + + // tx: https://tonscan.org/tx/VOTt8HW6eRuWHmuM_P3aC-Dy4TMu4cCRePoTAiDfcoQ= + ASSERT_EQ(output.encoded(), "te6ccgICAAQAAQAAANsAAAFFiAGwt/q8k4SrjbFbQCjJZfQr64ExRxcUMsWqaQODqTUijgwAAQGchoDa7EdGQuPuehHy3+0X9WNVEvYxdBtaEWn15oYUX8PEKyzztYy94Xq0T2XdhVvj2H7PTSQ+D/Ny1IBRCxk0BimpoxdkM5WOAAAACwADAAIBYmIAM33x4uAd+uQTyXyCZPxflESlNVHpCeoOECtNsqVW9tmIUAAAAAAAAAAAAAAAAAEAAwBWAAAAANGC0LXRgdGC0L7QstGL0Lkg0LrQvtC80LzQtdC90YLQsNGA0LjQuQ=="); +} + +TEST(TheOpenNetworkSigner, InvalidWalletVersion) { + auto input = Proto::SigningInput(); + + auto& transfer = *input.mutable_transfer(); + transfer.set_wallet_version(Proto::WALLET_V3_R2); + transfer.set_dest("EQDYW_1eScJVxtitoBRksvoV9cCYo4uKGWLVNIHB1JqRR3n0"); + transfer.set_amount(10); + transfer.set_mode(Proto::SendMode::PAY_FEES_SEPARATELY | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS); + transfer.set_expire_at(1671135440); + + const auto privateKey = parse_hex("63474e5fe9511f1526a50567ce142befc343e71a49b865ac3908f58667319cb8"); + input.set_private_key(privateKey.data(), privateKey.size()); + + auto output = Signer::sign(input); + ASSERT_EQ(output.error(), 22); +} + +} // namespace TW::TheOpenNetwork::tests diff --git a/tests/chains/TheOpenNetwork/TWAnyAddressTests.cpp b/tests/chains/TheOpenNetwork/TWAnyAddressTests.cpp new file mode 100644 index 00000000000..e84bcc6061c --- /dev/null +++ b/tests/chains/TheOpenNetwork/TWAnyAddressTests.cpp @@ -0,0 +1,33 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Data.h" + +#include +#include + +#include "TestUtilities.h" +#include + +using namespace TW; + +namespace TW::TheOpenNetwork::tests { + +TEST(TWTheOpenNetwork, Address) { + const auto mnemonic = STRING("stuff diamond cycle federal scan spread pigeon people engage teach snack grain"); + const auto passphrase = STRING(""); + + const auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(mnemonic.get(), passphrase.get())); + + const auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKey(wallet.get(), TWCoinTypeTON, WRAPS(TWCoinTypeDerivationPath(TWCoinTypeTON)).get())); + const auto publicKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKeyEd25519(privateKey.get())); + const auto address = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKey(publicKey.get(), TWCoinTypeTON)); + const auto addressStr = WRAPS(TWAnyAddressDescription(address.get())); + + assertStringsEqual(addressStr, "EQDYW_1eScJVxtitoBRksvoV9cCYo4uKGWLVNIHB1JqRR3n0"); +} + +} // namespace TW::TheOpenNetwork::tests diff --git a/tests/chains/TheOpenNetwork/TWAnySignerTests.cpp b/tests/chains/TheOpenNetwork/TWAnySignerTests.cpp new file mode 100644 index 00000000000..3becb96799a --- /dev/null +++ b/tests/chains/TheOpenNetwork/TWAnySignerTests.cpp @@ -0,0 +1,37 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" + +#include "proto/TheOpenNetwork.pb.h" +#include + +#include "TestUtilities.h" +#include + +namespace TW::TheOpenNetwork::tests { + +TEST(TWAnySignerTheOpenNetwork, SingMessageToTransferAndDeployWallet) { + Proto::SigningInput input; + + auto& transfer = *input.mutable_transfer(); + transfer.set_wallet_version(Proto::WALLET_V4_R2); + transfer.set_dest("EQDYW_1eScJVxtitoBRksvoV9cCYo4uKGWLVNIHB1JqRR3n0"); + transfer.set_amount(10); + transfer.set_mode(Proto::SendMode::PAY_FEES_SEPARATELY | Proto::SendMode::IGNORE_ACTION_PHASE_ERRORS); + transfer.set_expire_at(1671135440); + + const auto privateKey = parse_hex("63474e5fe9511f1526a50567ce142befc343e71a49b865ac3908f58667319cb8"); + input.set_private_key(privateKey.data(), privateKey.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeTON); + + ASSERT_EQ(output.encoded(), "te6ccgICABoAAQAAA8sAAAJFiADN98eLgHfrkE8l8gmT8X5REpTVR6QnqDhArTbKlVvbZh4ABAABAZznxvGBhoRXhPogxNY8QmHlihJWxg5t6KptqcAIZlVks1r+Z+r1avCWNCeqeLC/oaiVN4mDx/E1+Zhi33G25rcIKamjF/////8AAAAAAAMAAgFiYgBsLf6vJOEq42xW0AoyWX0K+uBMUcXFDLFqmkDg6k1Io4hQAAAAAAAAAAAAAAAAAQADAAACATQABgAFAFEAAAAAKamjF/Qsd/kxvqIOxdAVBzEna7suKGCUdmEkWyMZ74Ez7o1BQAEU/wD0pBP0vPLICwAHAgEgAA0ACAT48oMI1xgg0x/TH9MfAvgju/Jk7UTQ0x/TH9P/9ATRUUO68qFRUbryogX5AVQQZPkQ8qP4ACSkyMsfUkDLH1Iwy/9SEPQAye1U+A8B0wchwACfbFGTINdKltMH1AL7AOgw4CHAAeMAIcAC4wABwAORMOMNA6TIyx8Syx/L/wAMAAsACgAJAAr0AMntVABsgQEI1xj6ANM/MFIkgQEI9Fnyp4IQZHN0cnB0gBjIywXLAlAFzxZQA/oCE8tqyx8Syz/Jc/sAAHCBAQjXGPoA0z/IVCBHgQEI9FHyp4IQbm90ZXB0gBjIywXLAlAGzxZQBPoCFMtqEssfyz/Jc/sAAgBu0gf6ANTUIvkABcjKBxXL/8nQd3SAGMjLBcsCIs8WUAX6AhTLaxLMzMlz+wDIQBSBAQj0UfKnAgIBSAAXAA4CASAAEAAPAFm9JCtvaiaECAoGuQ+gIYRw1AgIR6STfSmRDOaQPp/5g3gSgBt4EBSJhxWfMYQCASAAEgARABG4yX7UTQ1wsfgCAVgAFgATAgEgABUAFAAZrx32omhAEGuQ64WPwAAZrc52omhAIGuQ64X/wAA9sp37UTQgQFA1yH0BDACyMoHy//J0AGBAQj0Cm+hMYALm0AHQ0wMhcbCSXwTgItdJwSCSXwTgAtMfIYIQcGx1Z70ighBkc3RyvbCSXwXgA/pAMCD6RAHIygfL/8nQ7UTQgQFA1yH0BDBcgQEI9ApvoTGzkl8H4AXTP8glghBwbHVnupI4MOMNA4IQZHN0crqSXwbjDQAZABgAilAEgQEI9Fkw7UTQgQFA1yDIAc8W9ADJ7VQBcrCOI4IQZHN0coMesXCAGFAFywVQA88WI/oCE8tqyx/LP8mAQPsAkl8D4gB4AfoA9AQw+CdvIjBQCqEhvvLgUIIQcGx1Z4MesXCAGFAEywUmzxZY+gIZ9ADLaRfLH1Jgyz8gyYBA+wAG"); +} + +} // namespace TW::TheOpenNetwork::tests + diff --git a/tests/chains/TheOpenNetwork/TWCoinTypeTests.cpp b/tests/chains/TheOpenNetwork/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..83e8e08d400 --- /dev/null +++ b/tests/chains/TheOpenNetwork/TWCoinTypeTests.cpp @@ -0,0 +1,36 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include + +#include "TestUtilities.h" +#include + + +TEST(TWTONCoinType, TWCoinType) { + const auto coin = TWCoinTypeTON; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("fJXfn0EVhV09HFuEgUHu4Cchb24nUQtIMwSzmzk2tLs=")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "ton"); + assertStringsEqual(name, "TON"); + assertStringsEqual(symbol, "TON"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 9); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainTheOpenNetwork); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); + assertStringsEqual(txUrl, "https://tonscan.org/tx/fJXfn0EVhV09HFuEgUHu4Cchb24nUQtIMwSzmzk2tLs="); + assertStringsEqual(accUrl, "https://tonscan.org/address/EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N"); +} diff --git a/tests/common/Base64Tests.cpp b/tests/common/Base64Tests.cpp index 64787ffaaf8..1d61102f7ff 100644 --- a/tests/common/Base64Tests.cpp +++ b/tests/common/Base64Tests.cpp @@ -61,4 +61,15 @@ TEST(Base64, UrlFormat) { EXPECT_EQ(const1, hex(decoded)); } +TEST(Base64, isBase64) { + EXPECT_TRUE(isBase64orBase64Url("Ef+BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb")); + EXPECT_TRUE(isBase64orBase64Url("Ef+BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSk=")); + EXPECT_TRUE(isBase64orBase64Url("Ef+BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODS==")); + EXPECT_TRUE(isBase64orBase64Url("EQA_qoVWKJl17JkayZlN-2E6vsTqAA1QlOY3kID1lOVZszC4")); + EXPECT_FALSE(isBase64orBase64Url("Ef+BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcOD===")); + EXPECT_FALSE(isBase64orBase64Url("Ef+BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb=")); + EXPECT_FALSE(isBase64orBase64Url("Ef+BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSk")); + EXPECT_FALSE(isBase64orBase64Url("MwCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsors=#")); +} + } // namespace TW::Base64::tests diff --git a/tests/common/CoinAddressDerivationTests.cpp b/tests/common/CoinAddressDerivationTests.cpp index 167041878b2..71982cf50cd 100644 --- a/tests/common/CoinAddressDerivationTests.cpp +++ b/tests/common/CoinAddressDerivationTests.cpp @@ -153,6 +153,9 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeEverscale: EXPECT_EQ(address, "0:ef64d51f95ef17973b737277cfecbd2a8d551141be2f58f5fb362575fc3eb5b0"); break; + case TWCoinTypeTON: + EXPECT_EQ(address, "EQAoYT8nMLfeNh6h0uIoK_wLm9JkvxiGxJDr6GRXJGu2ZhpY"); + break; case TWCoinTypeFIO: EXPECT_EQ(address, "FIO5TrYnZP1RkDSUMzBY4GanCy6AP68kCMdkAb5EACkAwkdgRLShz"); break; diff --git a/tests/common/CoinAddressValidationTests.cpp b/tests/common/CoinAddressValidationTests.cpp index a1816d6e911..5f899c5c9f5 100644 --- a/tests/common/CoinAddressValidationTests.cpp +++ b/tests/common/CoinAddressValidationTests.cpp @@ -409,4 +409,11 @@ TEST(Coin, ValidateAddressEverscale) { ASSERT_EQ(normalizeAddress(TWCoinTypeEverscale, "0:83A0352908060FA87839195D8A763A8D9AB28F8FA41468832B398A719CC6469A"), "0:83a0352908060fa87839195d8a763a8d9ab28f8fa41468832b398a719cc6469a"); } +TEST(Coin, ValidateAddressTheOpenNetwork) { + EXPECT_TRUE(validateAddress(TWCoinTypeTON, "0:8a8627861a5dd96c9db3ce0807b122da5ed473934ce7568a5b4b1c361cbb28ae")); + EXPECT_FALSE(validateAddress(TWCoinTypeTON, "8a8627861a5dd96c9db3ce0807b122da5ed473934ce7568a5b4b1c361cbb28ae")); + + ASSERT_EQ(normalizeAddress(TWCoinTypeTON, "0:8a8627861a5dd96c9db3ce0807b122da5ed473934ce7568a5b4b1c361cbb28ae"), "EQCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsorkdl"); +} + } // namespace TW diff --git a/tests/common/HexCodingTests.cpp b/tests/common/HexCodingTests.cpp index 57a40717fed..91ebe83150d 100644 --- a/tests/common/HexCodingTests.cpp +++ b/tests/common/HexCodingTests.cpp @@ -28,4 +28,11 @@ TEST(HexCoding, OddLength) { ASSERT_EQ(number, 11000000000); } +TEST(HexCoding, isHexEncoded) { + ASSERT_TRUE(is_hex_encoded("66fbe3c5c03bf5c82792f904c9f8bf28894a6aa3d213d41c20569b654aadedb3")); + ASSERT_TRUE(is_hex_encoded("0x66fbe3c5c03bf5c82792f904c9f8bf28894a6aa3d213d41c20569b654aadedb3")); + ASSERT_FALSE(is_hex_encoded("1x66fbe3c5c03bf5c82792f904c9f8bf28894a6aa3d213d41c20569b654aadedb3")); + ASSERT_FALSE(is_hex_encoded("0xyahoo")); +} + } diff --git a/wasm/tests/Blockchain/TheOpenNetwork.test.ts b/wasm/tests/Blockchain/TheOpenNetwork.test.ts new file mode 100644 index 00000000000..81ce7f523ff --- /dev/null +++ b/wasm/tests/Blockchain/TheOpenNetwork.test.ts @@ -0,0 +1,100 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import "mocha"; +import { assert } from "chai"; +import { Buffer } from "buffer"; +import { TW } from "../../dist"; +import Long = require("long"); + +describe("TheOpenNetwork", () => { + it("test address from private key TheOpenNetwork", () => { + const { PrivateKey, HexCoding, AnyAddress, CoinType, Curve } = globalThis.core; + let data = HexCoding.decode("63474e5fe9511f1526a50567ce142befc343e71a49b865ac3908f58667319cb8"); + let privateKey = PrivateKey.createWithData(data); + + assert.isTrue(PrivateKey.isValid(data, Curve.ed25519)); + + let publicKey = privateKey.getPublicKeyEd25519(); + let address = AnyAddress.createWithPublicKey(publicKey, CoinType.ton) + + assert.equal(publicKey.description(), "f42c77f931bea20ec5d0150731276bbb2e2860947661245b2319ef8133ee8d41"); + assert.equal(address.description(), "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q"); + }); + + it("test address from public key TheOpenNetwork", () => { + const { PublicKey, PublicKeyType, HexCoding, AnyAddress, CoinType } = globalThis.core; + let publicKey = PublicKey.createWithData(HexCoding.decode("f42c77f931bea20ec5d0150731276bbb2e2860947661245b2319ef8133ee8d41"), PublicKeyType.ed25519); + let address = AnyAddress.createWithPublicKey(publicKey, CoinType.ton); + assert.equal(address.description(), "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q"); + }); + + it("test address from raw string TheOpenNetwork", () => { + const { AnyAddress, CoinType } = globalThis.core; + let addressString = "0:66fbe3c5c03bf5c82792f904c9f8bf28894a6aa3d213d41c20569b654aadedb3"; + let address = AnyAddress.createWithString(addressString, CoinType.ton); + assert.equal(address.description(), "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q"); + }); + + it("test address invalid hex TheOpenNetwork", () => { + const { AnyAddress, CoinType } = globalThis.core; + let addressString = "0:yahoo3c5c03bf5c82792f904c9f8bf28894a6aa3d213d41c20569b654aadedb3"; + let valid = AnyAddress.isValid(addressString, CoinType.ton); + assert.isFalse(valid); + }); + + it("test address invalid workchain id TheOpenNetwork", () => { + const { AnyAddress, CoinType } = globalThis.core; + let addressString = "a:66fbe3c5c03bf5c82792f904c9f8bf28894a6aa3d213d41c20569b654aadedb3"; + let valid = AnyAddress.isValid(addressString, CoinType.ton); + assert.isFalse(valid); + }); + + it("test address from user friendly string TheOpenNetwork", () => { + const { AnyAddress, CoinType } = globalThis.core; + let addressString = "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q"; + let address = AnyAddress.createWithString(addressString, CoinType.ton); + assert.equal(address.description(), "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q"); + }); + + it("test address from user friendly invalid base64 decoding TheOpenNetwork", () => { + const { AnyAddress, CoinType } = globalThis.core; + let addressString = "MwCKhieGGl3ZbJ2zzggHsSLaXtRzk0znVopbSxw2HLsors=#"; + let valid = AnyAddress.isValid(addressString, CoinType.ton); + assert.isFalse(valid); + }); + + it("test sign TheOpenNetwork", () => { + const { PrivateKey, HexCoding, CoinType, AnySigner } = globalThis.core; + + let privateKeyData = HexCoding.decode("c38f49de2fb13223a9e7d37d5d0ffbdd89a5eb7c8b0ee4d1c299f2cefe7dc4a0"); + + let transfer = TW.TheOpenNetwork.Proto.Transfer.create({ + walletVersion: TW.TheOpenNetwork.Proto.WalletVersion.WALLET_V4_R2, + dest: "EQBm--PFwDv1yCeS-QTJ-L8oiUpqo9IT1BwgVptlSq3ts90Q", + amount: new Long(10), + sequenceNumber: 6, + mode: (TW.TheOpenNetwork.Proto.SendMode.PAY_FEES_SEPARATELY | TW.TheOpenNetwork.Proto.SendMode.IGNORE_ACTION_PHASE_ERRORS), + expireAt: 1671132440 + }); + + let input = TW.TheOpenNetwork.Proto.SigningInput.create({ + transfer: transfer, + privateKey: PrivateKey.createWithData(privateKeyData).data(), + }); + + const encoded = TW.TheOpenNetwork.Proto.SigningInput.encode(input).finish(); + let outputData = AnySigner.sign(encoded, CoinType.ton); + let output = TW.TheOpenNetwork.Proto.SigningOutput.decode(outputData); + + // tx: https://tonscan.org/tx/3Z4tHpXNLyprecgu5aTQHWtY7dpHXEoo11MAX61Xyg0= + let expectedString = "te6ccgICAAQAAQAAALAAAAFFiAGwt/q8k4SrjbFbQCjJZfQr64ExRxcUMsWqaQODqTUijgwAAQGcEUPkil2aZ4s8KKparSep/OKHMC8vuXafFbW2HGp/9AcTRv0J5T4dwyW1G0JpHw+g5Ov6QI3Xo0O9RFr3KidICimpoxdjm3UYAAAABgADAAIBYmIAM33x4uAd+uQTyXyCZPxflESlNVHpCeoOECtNsqVW9tmIUAAAAAAAAAAAAAAAAAEAAwAA"; + + assert.equal(output.encoded, expectedString) + }); +}); + + From 14a14b2f0c9f059fd4adb1c258cda30f56b6ba70 Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Fri, 13 Jan 2023 14:40:39 +0000 Subject: [PATCH 170/497] [WAX]: Add WAX chain (#2783) --- .../blockchains/CoinAddressDerivationTests.kt | 1 + docs/registry.md | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 26 +++++++++ swift/Tests/CoinAddressDerivationTests.swift | 2 +- tests/chains/WAX/TWAnySignerTests.cpp | 56 +++++++++++++++++++ tests/chains/WAX/TWCoinTypeTests.cpp | 30 ++++++++++ tests/common/CoinAddressDerivationTests.cpp | 1 + 8 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 tests/chains/WAX/TWAnySignerTests.cpp create mode 100644 tests/chains/WAX/TWCoinTypeTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index d1eec662f19..dd3b7491a5c 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -75,6 +75,7 @@ class CoinAddressDerivationTests { QTUM -> assertEquals("QhceuaTdeCZtcxmVc6yyEDEJ7Riu5gWFoF", address) NULS -> assertEquals("NULSd6HgU8MoRnNjBgvJpa9tqvGxYdv5ne4en", address) EOS -> assertEquals("EOS6hs8sRvGSzuQtq223zwJipMzqTJpXUVjyvHPvPwBSZWWrJTJkg", address) + WAX -> assertEquals("EOS6hs8sRvGSzuQtq223zwJipMzqTJpXUVjyvHPvPwBSZWWrJTJkg", address) IOTEX -> assertEquals("io1qw9cccecw09q7p5kzyqtuhfhvah2mhfrc84jfk", address) ZILLIQA -> assertEquals("zil1mk6pqphhkmaguhalq6n3cq0h38ltcehg0rfmv6", address) ZELCASH -> assertEquals("t1UKbRPzL4WN8Rs8aZ8RNiWoD2ftCMHKGUf", address) diff --git a/docs/registry.md b/docs/registry.md index 51cb097e664..0f0784f6e60 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -73,6 +73,7 @@ This list is generated from [./registry.json](../registry.json) | 3030 | Hedera | HBAR | | | | 6060 | GoChain | GO | | | | 8964 | NULS | NULS | | | +| 14001 | WAX | WAXP | | | | 18000 | Meter | MTR | | | | 19167 | Flux | FLUX | | | | 52752 | Celo | CELO | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 661ccebf68d..39b3c9bdeb0 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -43,6 +43,7 @@ enum TWCoinType { TWCoinTypeDigiByte = 20, TWCoinTypeDogecoin = 3, TWCoinTypeEOS = 194, + TWCoinTypeWAX = 14001, TWCoinTypeEthereum = 60, TWCoinTypeEthereumClassic = 61, TWCoinTypeFIO = 235, diff --git a/registry.json b/registry.json index 81df647a241..2bfa2e3ad3c 100644 --- a/registry.json +++ b/registry.json @@ -759,6 +759,32 @@ "documentation": "https://developers.eos.io/eosio-nodeos/reference" } }, + { + "id": "wax", + "name": "WAX", + "coinId": 14001, + "symbol": "WAXP", + "decimals": 4, + "blockchain": "EOS", + "derivation": [ + { + "path": "m/44'/194'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "explorer": { + "url": "https://wax.bloks.io", + "txPath": "/transaction/", + "accountPath": "/account/" + }, + "info": { + "url": "http://wax.io", + "source": "https://github.com/worldwide-asset-exchange/wax-blockchain", + "rpc": "https://wax.blacklusion.io", + "documentation": "https://https://developer.wax.io" + } + }, { "id": "tron", "name": "Tron", diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 3d46f67044c..1863b13d3b5 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -67,7 +67,7 @@ class CoinAddressDerivationTests: XCTestCase { case .elrond: let expectedResult = "erd1jfcy8aeru6vlx4fe6h3pc3vlpe2cnnur5zetxdhp879yagq7vqvs8na4f8" assertCoinDerivation(coin, expectedResult, derivedAddress, address) - case .eos: + case .eos, .wax: let expectedResult = "EOS6hs8sRvGSzuQtq223zwJipMzqTJpXUVjyvHPvPwBSZWWrJTJkg" assertCoinDerivation(coin, expectedResult, derivedAddress, address) case .ethereum, diff --git a/tests/chains/WAX/TWAnySignerTests.cpp b/tests/chains/WAX/TWAnySignerTests.cpp new file mode 100644 index 00000000000..4074293d5e3 --- /dev/null +++ b/tests/chains/WAX/TWAnySignerTests.cpp @@ -0,0 +1,56 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "TestUtilities.h" +#include +#include "HexCoding.h" +#include "PublicKey.h" +#include "PrivateKey.h" +#include "EOS/Address.h" +#include "Base58.h" +#include "proto/EOS.pb.h" + +#include + +namespace TW::EOS::tests { + +TEST(TWAnySignerWAX, Sign) { + Proto::SigningInput input; + const auto chainId = parse_hex("1064487b3cd1a897ce03ae5b6a865651747e2e152090f99c1d19d44e01aea5a4"); + const auto refBlock = parse_hex("0cffaeda15039f3468398c5b4295d220fcc217f7cf96030c3729773097c6bd76"); + const auto key = parse_hex("d30d185a296b9591d648cb92fe0aa8f8a42de30ed9d2a21da9e7f69c67e8e355"); + + const auto pubKey = PublicKey(PrivateKey(key).getPublicKey(TWPublicKeyTypeSECP256k1)); + const auto address = Address(pubKey); + EXPECT_EQ(address.string(), "EOS7rC6zYUjuxWkiokZTrwwHqwFvZ15Qdrn5WNxMKVXtHiDDmBWog"); + + auto& asset = *input.mutable_asset(); + asset.set_amount(100000000); + asset.set_decimals(4); + asset.set_symbol("WAX"); + + input.set_chain_id(chainId.data(), chainId.size()); + input.set_reference_block_id(refBlock.data(), refBlock.size()); + input.set_reference_block_time(1670507804); + input.set_currency("eosio.token"); + input.set_sender("k52o1qdeh.gm"); + input.set_recipient("c2lrpvzxb.gm"); + input.set_memo("sent from wallet-core"); + input.set_private_key(key.data(), key.size()); + input.set_private_key_type(Proto::KeyType::MODERNK1); + + // https://wax.bloks.io/transaction/4548f7b28ee608663caea61234049ac0018415e02dd0abcea1c215c8da00d10a + { + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeEOS); + + EXPECT_EQ(output.error(), Common::Proto::OK); + auto expected = R"({"compression":"none","packed_context_free_data":"","packed_trx":"3aed9163daae68398c5b000000000100a6823403ea3055000000572d3ccdcd012019682ad940458100000000a8ed3232362019682ad9404581201938fdef7aa34000e1f5050000000004574158000000001573656e742066726f6d2077616c6c65742d636f726500","signatures":["SIG_K1_KAroa9t89dpujjfBgBMgDcZrVhML5yP7iFk5sGNnNqbT4SxTCLqjQwwLZDi1ryx4W7Hy9DE9p1MqUSFVKeY8NtKyiySFjE"]})"; + EXPECT_EQ(output.json_encoded(), expected); + } +} + +} // namespace TW::EOS::tests diff --git a/tests/chains/WAX/TWCoinTypeTests.cpp b/tests/chains/WAX/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..95e2880dc77 --- /dev/null +++ b/tests/chains/WAX/TWCoinTypeTests.cpp @@ -0,0 +1,30 @@ +// Copyright © 2017-2020 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "TestUtilities.h" +#include +#include + + +TEST(TWWAXCoinType, TWCoinType) { + auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeWAX)); + auto txId = WRAPS(TWStringCreateWithUTF8Bytes("4548f7b28ee608663caea61234049ac0018415e02dd0abcea1c215c8da00d10a")); + auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeWAX, txId.get())); + auto accId = WRAPS(TWStringCreateWithUTF8Bytes("k52o1qdeh.gm")); + auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeWAX, accId.get())); + auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeWAX)); + auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeWAX)); + + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeWAX), 4); + ASSERT_EQ(TWBlockchainEOS, TWCoinTypeBlockchain(TWCoinTypeWAX)); + ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeWAX)); + ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeWAX)); + assertStringsEqual(symbol, "WAXP"); + assertStringsEqual(txUrl, "https://wax.bloks.io/transaction/4548f7b28ee608663caea61234049ac0018415e02dd0abcea1c215c8da00d10a"); + assertStringsEqual(accUrl, "https://wax.bloks.io/account/k52o1qdeh.gm"); + assertStringsEqual(id, "wax"); + assertStringsEqual(name, "WAX"); +} diff --git a/tests/common/CoinAddressDerivationTests.cpp b/tests/common/CoinAddressDerivationTests.cpp index 71982cf50cd..34b27fce10e 100644 --- a/tests/common/CoinAddressDerivationTests.cpp +++ b/tests/common/CoinAddressDerivationTests.cpp @@ -145,6 +145,7 @@ TEST(Coin, DeriveAddress) { EXPECT_EQ(address, "ecash:qz7eyzytkl5z6cg6nw20hd62pyyp22mcfuywezks2y"); break; case TWCoinTypeEOS: + case TWCoinTypeWAX: EXPECT_EQ(address, "EOS5TrYnZP1RkDSUMzBY4GanCy6AP68kCMdkAb5EACkAwkdgRLShz"); break; case TWCoinTypeElrond: From fd2fac821c6552c6147b87ce7341bca2d70e1cb4 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 17 Jan 2023 16:08:29 +0100 Subject: [PATCH 171/497] [Misc]: add SECURITY.MD (#2872) --- SECURITY.MD | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 SECURITY.MD diff --git a/SECURITY.MD b/SECURITY.MD new file mode 100644 index 00000000000..720baa249ff --- /dev/null +++ b/SECURITY.MD @@ -0,0 +1,29 @@ +# Security Policy + +The security of our users' assets is of the utmost importance to us. We take a number of steps to ensure that our crypto wallet is as secure as possible. + +## Reporting a Security Vulnerability + +If you believe you have found a security vulnerability in our wallet, please contact us immediately at [Bug Bounty Binance](https://bugcrowd.com/binance). We will investigate all reports and do our best to quickly fix any vulnerabilities. + +## Responsible Disclosure + +IMPORTANT: Do not file public issues on GitHub for security vulnerabilities. Do not publicly disclose the vulnerability until we have had a chance to patch it. This gives us time to fix the problem and protect our users’ assets. + +## Encryption + +All private keys are encrypted and stored on the user's device. The encryption uses industry-standard algorithms and is designed to protect against brute-force attacks. + +## Regular Audits + +We regularly conduct security audits of our code to ensure that it is free of vulnerabilities. We also stay up-to-date with the latest security best practices and technologies. + +## Bug Bounty Program + +As a part of Binance security program, TrustWallet also participate in their bug bounty program. For more information on eligible scope, rewards, and how to submit a report, please visit [https://bugcrowd.com/binance](https://bugcrowd.com/binance) + +## Disclaimer + +As with any software, there are always potential security risks. We do our best to minimize these risks and keep our users' assets safe, but we cannot guarantee that our wallet will be completely immune to all security threats. + + From de91d9068865129ccaca1562c7f6f51f7fd77da5 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 18 Jan 2023 09:05:26 +0100 Subject: [PATCH 172/497] [ThorSwap]: fee optimization for EVM chains (#2868) --- .../thorchain/TestTHORSwapSigning.kt | 4 +- src/THORChain/Swap.cpp | 35 +- .../Blockchains/THORChainSwapTests.swift | 4 +- tests/chains/THORChain/SwapTests.cpp | 526 ++++++++---------- tests/chains/THORChain/TWSwapTests.cpp | 4 +- 5 files changed, 265 insertions(+), 308 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt index fcc0dd64986..68f0f8acc55 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/thorchain/TestTHORSwapSigning.kt @@ -48,7 +48,7 @@ class TestTHORChainSwap { // invoke swap val outputData = buildSwap(inputSerialized) - assertEquals(outputData.count(), 375) + assertEquals(outputData.count(), 192) // parse result in proto val outputProto = THORChainSwap.SwapOutput.newBuilder().mergeFrom(outputData) @@ -70,6 +70,6 @@ class TestTHORChainSwap { // sign and encode resulting input val output = AnySigner.sign(txInputFull, ETHEREUM, SigningOutput.parser()) - assertEquals(Numeric.toHexString(output.encoded.toByteArray()), "0xf90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000000000026a0ee68bd41da9a9b1ad87fd547e83e4b8022460de024839f4f5f528abc6aecf2aea0402205812d62a075138743f6048ba2a1c073f4a3a14224009a34ee74d3dccef1") + assertEquals(Numeric.toHexString(output.encoded.toByteArray()), "0x02f8d90103808083013880941091c4de6a3cf09cda00abdaed42c7c3b69c83ec87b1a2bc2ec50000b86e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a3130c001a05c16871b66fd0fa8f658d6f171310bab332d09e0533d6c97329a59ddc93a9a11a05ed2be94e6dbb640e58920c8be4fa597cd5f0a918123245acb899042dd43777f") } } diff --git a/src/THORChain/Swap.cpp b/src/THORChain/Swap.cpp index 8cf5c44be2d..cb42e556b81 100644 --- a/src/THORChain/Swap.cpp +++ b/src/THORChain/Swap.cpp @@ -7,6 +7,7 @@ #include "Swap.h" #include "Coin.h" +#include "HexCoding.h" #include // ATOM @@ -228,13 +229,15 @@ SwapBundled SwapBuilder::buildBinance(Proto::Asset fromAsset, uint64_t amount, c SwapBundled SwapBuilder::buildEth(uint64_t amount, const std::string& memo) { Data out; auto input = Ethereum::Proto::SigningInput(); + // EIP-1559 + input.set_tx_mode(Ethereum::Proto::Enveloped); const auto& toTokenId = mFromAsset.token_id(); // some sanity check / address conversion Data vaultAddressBin = ethAddressStringToData(mVaultAddress); if (!Ethereum::Address::isValid(mVaultAddress) || vaultAddressBin.size() != Ethereum::Address::size) { return {.status_code = static_cast(Proto::ErrorCode::Error_Invalid_vault_address), .error = "Invalid vault address: " + mVaultAddress}; } - if (!Ethereum::Address::isValid(*mRouterAddress)) { + if (!toTokenId.empty() && !Ethereum::Address::isValid(*mRouterAddress)) { return {.status_code = static_cast(Proto::ErrorCode::Error_Invalid_router_address), .error = "Invalid router address: " + *mRouterAddress}; } Data toAssetAddressBin = ethAddressStringToData(toTokenId); @@ -252,17 +255,25 @@ SwapBundled SwapBuilder::buildEth(uint64_t amount, const std::string& memo) { // ... end input.set_to_address(*mRouterAddress); - auto& transfer = *input.mutable_transaction()->mutable_contract_generic(); - auto func = Ethereum::ABI::Function("deposit", std::vector>{ - std::make_shared(vaultAddressBin), - std::make_shared(toAssetAddressBin), - std::make_shared(uint256_t(amount)), - std::make_shared(memo)}); - Data payload; - func.encode(payload); - transfer.set_data(payload.data(), payload.size()); - Data amountData = store(toTokenId.empty() ? uint256_t(amount) : uint256_t(0)); - transfer.set_amount(amountData.data(), amountData.size()); + if (!toTokenId.empty()) { + auto& transfer = *input.mutable_transaction()->mutable_contract_generic(); + auto func = Ethereum::ABI::Function("deposit", std::vector>{ + std::make_shared(vaultAddressBin), + std::make_shared(toAssetAddressBin), + std::make_shared(uint256_t(amount)), + std::make_shared(memo)}); + Data payload; + func.encode(payload); + transfer.set_data(payload.data(), payload.size()); + Data amountData = store(uint256_t(0)); + transfer.set_amount(amountData.data(), amountData.size()); + } else { + input.set_to_address(mVaultAddress); + auto& transfer = *input.mutable_transaction()->mutable_transfer(); + Data amountData = store(uint256_t(amount)); + transfer.set_amount(amountData.data(), amountData.size()); + transfer.set_data(memo.data(), memo.size()); + } auto serialized = input.SerializeAsString(); out.insert(out.end(), serialized.begin(), serialized.end()); diff --git a/swift/Tests/Blockchains/THORChainSwapTests.swift b/swift/Tests/Blockchains/THORChainSwapTests.swift index 73500bd9e25..8a7dc4a2ff6 100644 --- a/swift/Tests/Blockchains/THORChainSwapTests.swift +++ b/swift/Tests/Blockchains/THORChainSwapTests.swift @@ -36,7 +36,7 @@ class THORSwapTests: XCTestCase { // invoke swap let outputData = THORChainSwap.buildSwap(input: inputSerialized) - XCTAssertEqual(outputData.count, 375) + XCTAssertEqual(outputData.count, 192) // parse result in proto let outputProto = try THORChainSwapSwapOutput(serializedData: outputData) @@ -55,7 +55,7 @@ class THORSwapTests: XCTestCase { // sign and encode resulting input let output: EthereumSigningOutput = AnySigner.sign(input: txInput, coin: .ethereum) - XCTAssertEqual(output.encoded.hexString, "f90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000000000026a0ee68bd41da9a9b1ad87fd547e83e4b8022460de024839f4f5f528abc6aecf2aea0402205812d62a075138743f6048ba2a1c073f4a3a14224009a34ee74d3dccef1") + XCTAssertEqual(output.encoded.hexString, "02f8d90103808083013880941091c4de6a3cf09cda00abdaed42c7c3b69c83ec87b1a2bc2ec50000b86e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a3130c001a05c16871b66fd0fa8f658d6f171310bab332d09e0533d6c97329a59ddc93a9a11a05ed2be94e6dbb640e58920c8be4fa597cd5f0a918123245acb899042dd43777f") } func testSignerBnbBtc() throws { diff --git a/tests/chains/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp index 2ecd1094172..f47bc022a34 100644 --- a/tests/chains/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -13,8 +13,8 @@ #include "Ethereum/Address.h" #include "THORChain/Swap.h" #include "proto/Binance.pb.h" -#include "proto/Cosmos.pb.h" #include "proto/Bitcoin.pb.h" +#include "proto/Cosmos.pb.h" #include "proto/Ethereum.pb.h" #include "proto/THORChainSwap.pb.h" @@ -48,15 +48,15 @@ TEST(THORChainSwap, SwapBtcEth) { Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::ETH)); toAsset.set_symbol("ETH"); - auto && [out, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Btc) - .toAddress(Address1Eth) - .vault(VaultBtc) - .fromAmount("1000000") - .toAmountLimit("140000000000000000") - .build(); + auto&& [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Btc) + .toAddress(Address1Eth) + .vault(VaultBtc) + .fromAmount("1000000") + .toAmountLimit("140000000000000000") + .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); EXPECT_EQ(hex(out), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a473d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a313430303030303030303030303030303030"); @@ -92,19 +92,19 @@ TEST(THORChainSwap, SwapBtcEth) { ANY_SIGN(tx, TWCoinTypeBitcoin); EXPECT_EQ(output.error(), 0); EXPECT_EQ(hex(output.encoded()), // printed using prettyPrintTransaction - "01000000" // version - "0001" // marker & flag - "01" // inputs - "1234000000000000000000000000000000000000000000000000000000005678" "00000000" "00" "" "ffffffff" - "03" // outputs - "40420f0000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" - "d49ceb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" - "0000000000000000" "49" "6a473d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a313430303030303030303030303030303030" - // witness - "02" - "48" "3045022100a67f84cbde5affbb46ffff2b33c1453ff2de70ef990fc974175d9a609e5a87ed0220589c57d958208f866c9477c7d6c9075dea4c58622debb02eab85032b8b6d373001" - "21" "021e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" - "00000000" // nLockTime + "01000000" // version + "0001" // marker & flag + "01" // inputs + "1234000000000000000000000000000000000000000000000000000000005678" "00000000" "00" "" "ffffffff" + "03" // outputs + "40420f0000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" + "d49ceb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" + "0000000000000000" "49" "6a473d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a313430303030303030303030303030303030" + // witness + "02" + "48" "3045022100a67f84cbde5affbb46ffff2b33c1453ff2de70ef990fc974175d9a609e5a87ed0220589c57d958208f866c9477c7d6c9075dea4c58622debb02eab85032b8b6d373001" + "21" "021e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" + "00000000" // nLockTime ); } @@ -119,7 +119,7 @@ TEST(THORChainSwap, SwapDogeBusd) { auto vaultDoge = "DExct9oTfqr7pfnbP2hkCHP1Z2eUDgqXya"; auto fromAddressDoge = "DKftkYCtCyYxQy2TRAuAzQXoyKDdYsEBnw"; auto toAddressBnb = "bnb1s4kallxngpyspzm6nrezkml9rgyw6kxpw4fhr2"; - auto && [out, errorCode, error] = SwapBuilder::builder() + auto&& [out, errorCode, error] = SwapBuilder::builder() .from(fromAsset) .to(toAsset) .fromAddress(fromAddressDoge) @@ -184,7 +184,7 @@ TEST(THORChainSwap, SwapLtcBusd) { auto vaultLTC = "ltc1qmca5runvg3hygarulu34evdulcdfda7z7zquhn"; auto fromAddressLTC = "ltc1qyu9qvkukx99r6yadxlk3t2x78a7dxe73s3r4x3"; auto toAddressBnb = "bnb1s4kallxngpyspzm6nrezkml9rgyw6kxpw4fhr2"; - auto && [out, errorCode, error] = SwapBuilder::builder() + auto&& [out, errorCode, error] = SwapBuilder::builder() .from(fromAsset) .to(toAsset) .fromAddress(fromAddressLTC) @@ -248,7 +248,7 @@ TEST(THORChainSwap, SwapBchBusd) { auto vaultBCH = "qpsfh5xvk7mgf9e6kl4e045nm6awl5hmks9x7h5ad6"; auto fromAddressBCH = "qr50u7hy3xcr3j0w9j5nfx2gevjqgfm42ykc2hqgy4"; auto toAddressBnb = "bnb1s4kallxngpyspzm6nrezkml9rgyw6kxpw4fhr2"; - auto && [out, errorCode, error] = SwapBuilder::builder() + auto&& [out, errorCode, error] = SwapBuilder::builder() .from(fromAsset) .to(toAsset) .fromAddress(fromAddressBCH) @@ -308,15 +308,15 @@ TEST(THORChainSwap, SwapBtcBnb) { toAsset.set_chain(static_cast(Chain::BNB)); toAsset.set_symbol("BNB"); - auto && [out, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Btc) - .toAddress(Address1Bnb) - .vault(VaultBtc) - .fromAmount("200000") - .toAmountLimit("140000000") - .build(); + auto&& [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Btc) + .toAddress(Address1Bnb) + .vault(VaultBtc) + .fromAmount("200000") + .toAmountLimit("140000000") + .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); EXPECT_EQ(hex(out), "080110c09a0c1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a3e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a313430303030303030"); @@ -353,19 +353,19 @@ TEST(THORChainSwap, SwapBtcBnb) { ANY_SIGN(tx, TWCoinTypeBitcoin); EXPECT_EQ(output.error(), 0); EXPECT_EQ(hex(output.encoded()), // printed using prettyPrintTransaction - "01000000" // version - "0001" // marker & flag - "01" // inputs - "eb48da786cbd9430bf5ef3d1d3bc7206a4182fd7d5ac3f4e8d05754c3a5cae8e" "00000000" "00" "" "fcffffff" - "03" // outputs - "400d030000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" - "b08d030000000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" - "0000000000000000" "40" "6a3e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a313430303030303030" - // witness - "02" - "48" "3045022100e17d8cf207c79edfb7afa16102842b434e1f908bd9858553fd54970f1a8b4334022059583f89c3a126df0da46d92947bcbe7c265a1bb838b696c0e7ea7fc8761c2bf01210" - "21" "e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" - "00000000" // nLockTime + "01000000" // version + "0001" // marker & flag + "01" // inputs + "eb48da786cbd9430bf5ef3d1d3bc7206a4182fd7d5ac3f4e8d05754c3a5cae8e" "00000000" "00" "" "fcffffff" + "03" // outputs + "400d030000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" + "b08d030000000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" + "0000000000000000" "40" "6a3e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a313430303030303030" + // witness + "02" + "48" "3045022100e17d8cf207c79edfb7afa16102842b434e1f908bd9858553fd54970f1a8b4334022059583f89c3a126df0da46d92947bcbe7c265a1bb838b696c0e7ea7fc8761c2bf01210" + "21" "e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" + "00000000" // nLockTime ); // similar real transaction: @@ -382,7 +382,7 @@ TEST(THORChainSwap, SwapAtomBnb) { toAsset.set_chain(static_cast(Chain::BNB)); toAsset.set_symbol("BNB"); - auto && [out, errorCode, error] = SwapBuilder::builder() + auto&& [out, errorCode, error] = SwapBuilder::builder() .from(fromAsset) .to(toAsset) .fromAddress("cosmos1v4e6vpehwrfez2dqepnw9g6t4fl83xzegd5ac9") @@ -407,7 +407,6 @@ TEST(THORChainSwap, SwapAtomBnb) { fee_amount.set_denom("uatom"); fee_amount.set_amount("500"); - tx.set_account_number(1483163); tx.set_sequence(1); @@ -442,7 +441,7 @@ TEST(THORChainSwap, SwapErc20Rune) { Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::THOR)); toAsset.set_symbol("RUNE"); - auto && [out, errorCode, error] = SwapBuilder::builder() + auto&& [out, errorCode, error] = SwapBuilder::builder() .from(fromAsset) .to(toAsset) .fromAddress("0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37") @@ -454,7 +453,7 @@ TEST(THORChainSwap, SwapErc20Rune) { .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); - EXPECT_EQ(hex(out), "0a01001201002201002a0100422a307844333742624535373434443733306131643938643844433937633432463043613436614437313436528d02328a020a01001284021fece7b400000000000000000000000097673df37e718df203a834bd095f69f6b4f314fa000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000413d3a54484f522e52554e453a74686f7231647538346337666a3579376b706871377a667970387567777867726d79366e3037786d39796a3a34313834313035323000000000000000000000000000000000000000000000000000000000000000"); + EXPECT_EQ(hex(out), "0a010012010018012201002a0100422a307844333742624535373434443733306131643938643844433937633432463043613436614437313436528d02328a020a01001284021fece7b400000000000000000000000097673df37e718df203a834bd095f69f6b4f314fa000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000413d3a54484f522e52554e453a74686f7231647538346337666a3579376b706871377a667970387567777867726d79366e3037786d39796a3a34313834313035323000000000000000000000000000000000000000000000000000000000000000"); auto tx = Ethereum::Proto::SigningInput(); ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); @@ -493,7 +492,7 @@ TEST(THORChainSwap, SwapErc20Rune) { // sign and encode resulting input Ethereum::Proto::SigningOutput output; ANY_SIGN(tx, TWCoinTypeEthereum); - EXPECT_EQ(hex(output.encoded()), "f9016b078506fc23ac008301388094d37bbe5744d730a1d98d8dc97c42f0ca46ad714680b901041fece7b400000000000000000000000097673df37e718df203a834bd095f69f6b4f314fa000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000413d3a54484f522e52554e453a74686f7231647538346337666a3579376b706871377a667970387567777867726d79366e3037786d39796a3a3431383431303532300000000000000000000000000000000000000000000000000000000000000026a03b9082870fda839820dd36d4da3d8985807c799a8cf8e1971374a461da5899a7a0383d9ceaacf6c90205d4381b403687c17c2bbfaac1c1329ac65c0ce22d940451"); + EXPECT_EQ(hex(output.encoded()), "02f90169010780808301388094d37bbe5744d730a1d98d8dc97c42f0ca46ad714680b901041fece7b400000000000000000000000097673df37e718df203a834bd095f69f6b4f314fa000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000413d3a54484f522e52554e453a74686f7231647538346337666a3579376b706871377a667970387567777867726d79366e3037786d39796a3a34313834313035323000000000000000000000000000000000000000000000000000000000000000c001a01ff085d06b39d6efeb6663b065758f463564a555e41070ca8a8398bb1fc3426ba018bd8c6897f86d6ca4af7fe4cfac92e3fcb6224f896df62376ac1df556744ac6"); // https://viewblock.io/thorchain/tx/56D2A63608E6EC09FA1D2934457CC09196683013905F69EDFC72B33EC68681AA // https://etherscan.io/tx/0x56d2a63608e6ec09fa1d2934457cc09196683013905f69edfc72b33ec68681aa // https://viewblock.io/thorchain/tx/BC1464CF3B56B07E40CF57985511814AEC9EAE2F1329CEE059A21529FDDFDB8C @@ -505,57 +504,48 @@ TEST(THORChainSwap, SwapAvaxBnb) { Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::BNB)); toAsset.set_symbol("BNB"); - auto && [out, errorCode, error] = SwapBuilder::builder() + auto&& [out, errorCode, error] = SwapBuilder::builder() .from(fromAsset) .to(toAsset) - .fromAddress("0x4340fb8bb31357559607142b37C2173418E36785") - .toAddress("bnb1hy9a63tgsvham463vw2tkkw2j5y20v5drhw8p2") - .vault("0x53595320f158d4546677B4795Cc66dfF59D154Db") - .router("0x8f66c4ae756bebc49ec8b81966dd8bba9f127549") - .fromAmount("20000000000000000") + .fromAddress("0xbB7cF2f05a01DB5394234FE1257D907059edFa66") + .toAddress("bnb16gk7gczst59wy8rnxrqnt3yn6f60uw6ec0w6uv") + .vault("0x3bd92906c60e5843ce01b2dc54e6dc3575b5215a") + .fromAmount("150000000000000000") + .toAmountLimit("297039") + .affFeeAddress("t") + .affFeeRate("0") .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); - EXPECT_EQ(hex(out), "0a01001201002201002a0100422a30783866363663346165373536626562633439656338623831393636646438626261396631323735343952f30132f0010a07470de4df82000012e4011fece7b400000000000000000000000053595320f158d4546677b4795cc66dff59d154db000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470de4df820000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000343d3a424e422e424e423a626e62316879396136337467737668616d343633767732746b6b77326a35793230763564726877387032000000000000000000000000"); + EXPECT_EQ(hex(out), "0a010012010018012201002a0100422a307833626439323930366336306535383433636530316232646335346536646333353735623532313561524d0a4b0a080214e8348c4f0000123f3d3a424e422e424e423a626e623136676b3767637a73743539777938726e7872716e7433796e36663630757736656330773675763a3239373033393a743a30"); auto tx = Ethereum::Proto::SigningInput(); ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields - EXPECT_EQ(tx.to_address(), "0x8f66c4ae756bebc49ec8b81966dd8bba9f127549"); - ASSERT_TRUE(tx.transaction().has_contract_generic()); - - Data vaultAddressBin = SwapTest_ethAddressStringToData("0x53595320f158d4546677B4795Cc66dfF59D154Db"); - EXPECT_EQ(hex(vaultAddressBin), "53595320f158d4546677b4795cc66dff59d154db"); - auto func = Ethereum::ABI::Function("deposit", std::vector>{ - std::make_shared(vaultAddressBin), - std::make_shared(parse_hex("0000000000000000000000000000000000000000")), - std::make_shared(uint256_t(20000000000000000)), - std::make_shared("=:BNB.BNB:bnb1hy9a63tgsvham463vw2tkkw2j5y20v5drhw8p2")}); - Data payload; - func.encode(payload); - EXPECT_EQ(hex(payload), "1fece7b400000000000000000000000053595320f158d4546677b4795cc66dff59d154db000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470de4df820000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000343d3a424e422e424e423a626e62316879396136337467737668616d343633767732746b6b77326a35793230763564726877387032000000000000000000000000"); - EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().amount())), "470de4df820000"); - EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().data())), hex(payload)); + EXPECT_EQ(tx.to_address(), "0x3bd92906c60e5843ce01b2dc54e6dc3575b5215a"); + ASSERT_FALSE(tx.transaction().has_contract_generic()); EXPECT_EQ(hex(TW::data(tx.private_key())), ""); // set few fields before signing auto chainId = store(uint256_t(43114)); tx.set_chain_id(chainId.data(), chainId.size()); - auto nonce = store(uint256_t(4)); + auto nonce = store(uint256_t(5)); tx.set_nonce(nonce.data(), nonce.size()); - auto gasPrice = store(uint256_t(30000000000)); - tx.set_gas_price(gasPrice.data(), gasPrice.size()); + auto maxInclusionFeePerGas = store(uint256_t(2000000000)); + auto maxFeePerGas = store(uint256_t(25000000000)); + tx.set_max_inclusion_fee_per_gas(maxInclusionFeePerGas.data(), maxInclusionFeePerGas.size()); + tx.set_max_fee_per_gas(maxFeePerGas.data(), maxFeePerGas.size()); auto gasLimit = store(uint256_t(108810)); tx.set_gas_limit(gasLimit.data(), gasLimit.size()); - auto privKey = parse_hex("42dcdf1cc2020a98f874a2f754eeb127e556ee62714973299e62ebdaadb48218"); + auto privKey = parse_hex("09da019c250b7e2b140645df36fd839806c5ae8eecf4d8f35e8ff57cf3bd1e57"); tx.set_private_key(privKey.data(), privKey.size()); // sign and encode resulting input Ethereum::Proto::SigningOutput output; ANY_SIGN(tx, TWCoinTypeAvalancheCChain); - EXPECT_EQ(hex(output.encoded()), "f90154048506fc23ac008301a90a948f66c4ae756bebc49ec8b81966dd8bba9f12754987470de4df820000b8e41fece7b400000000000000000000000053595320f158d4546677b4795cc66dff59d154db000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470de4df820000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000343d3a424e422e424e423a626e62316879396136337467737668616d343633767732746b6b77326a35793230763564726877387032000000000000000000000000830150f8a09491c6b06fc1773bfc2a067787da96143f3d56eaf9fa9667298fdb298d33944ea04e2e2618e7c822b21af1ccc27746bfa46fa703b1c7f14cb0e33bd7f88acf2045"); + EXPECT_EQ(hex(output.encoded()), "02f8b682a86a0584773594008505d21dba008301a90a943bd92906c60e5843ce01b2dc54e6dc3575b5215a880214e8348c4f0000b83f3d3a424e422e424e423a626e623136676b3767637a73743539777938726e7872716e7433796e36663630757736656330773675763a3239373033393a743a30c001a06546e903b35a6a3704e2692cc80ecf49901edb9586fd28f5e084a1f334bad455a0277c2e122948df3b8efce3f7f2b73d5bc1f96c80bfbe5a45fe0914dc6fce5843"); // https://viewblock.io/thorchain/tx/8A29B132443BF1B0A0BD3E00F8155D10FEEEC7737BDC912C4A1AFB0A52E4FD4F // https://snowtrace.io/tx/0x8A29B132443BF1B0A0BD3E00F8155D10FEEEC7737BDC912C4A1AFB0A52E4FD4F // https://binance.mintscan.io/txs/9D250C8BAC8205B942A597AFB345045439A55CAB8DD588B75870D4E47D751C16 @@ -567,46 +557,25 @@ TEST(THORChainSwap, SwapEthBnb) { Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::BNB)); toAsset.set_symbol("BNB"); - auto && [out, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Eth) - .toAddress(Address1Bnb) - .vault(VaultEth) - .router(RouterEth) - .fromAmount("50000000000000000") - .toAmountLimit("600003") - .build(); + auto&& [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Eth) + .toAddress(Address1Bnb) + .vault(VaultEth) + .fromAmount("50000000000000000") + .toAmountLimit("600003") + .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); - EXPECT_EQ(hex(out), "0a01001201002201002a0100422a30783432413545643435363635306130394463313045426336333631413734383066446436316632374252f30132f0010a07b1a2bc2ec5000012e4011fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003b3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030330000000000"); + EXPECT_EQ(hex(out), "0a010012010018012201002a0100422a30783130393163344465366133634630394364413030416244416544343263376333423639433833454352480a460a07b1a2bc2ec50000123b3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a363030303033"); auto tx = Ethereum::Proto::SigningInput(); ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields - EXPECT_EQ(tx.to_address(), RouterEth); - ASSERT_TRUE(tx.transaction().has_contract_generic()); - - Data vaultAddressBin = SwapTest_ethAddressStringToData(VaultEth); - EXPECT_EQ(hex(vaultAddressBin), "1091c4de6a3cf09cda00abdaed42c7c3b69c83ec"); - auto func = Ethereum::ABI::Function("deposit", std::vector>{ - std::make_shared(vaultAddressBin), - std::make_shared(parse_hex("0000000000000000000000000000000000000000")), - std::make_shared(uint256_t(50000000000000000)), - std::make_shared("=:BNB.BNB:bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx:600003")}); - Data payload; - func.encode(payload); - EXPECT_EQ(hex(payload), "1fece7b4" - "0000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec" - "0000000000000000000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000b1a2bc2ec50000" - "0000000000000000000000000000000000000000000000000000000000000080" - "000000000000000000000000000000000000000000000000000000000000003b" - "3d3a424e422e424e423a626e62317573343777646866783038636839377a6475" - "656833783375356d757266727833306a656372783a3630303030330000000000"); - EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().amount())), "b1a2bc2ec50000"); - EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().data())), hex(payload)); + EXPECT_EQ(tx.to_address(), VaultEth); + ASSERT_FALSE(tx.transaction().has_contract_generic()); EXPECT_EQ(hex(TW::data(tx.private_key())), ""); @@ -625,7 +594,7 @@ TEST(THORChainSwap, SwapEthBnb) { // sign and encode resulting input Ethereum::Proto::SigningOutput output; ANY_SIGN(tx, TWCoinTypeEthereum); - EXPECT_EQ(hex(output.encoded()), "f90151038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b8e41fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003b3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a363030303033000000000026a0669563be8a0022fcd32fdf82ccca7dc66012ea28c57e95a2d9348dbf37afc377a03505f5eb041038c565d2f2888207c9dbcad8ca12f10ce5c5bd2ca41de01a9e89"); + EXPECT_EQ(hex(output.encoded()), "02f8a60103808083013880941091c4de6a3cf09cda00abdaed42c7c3b69c83ec87b1a2bc2ec50000b83b3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a363030303033c080a00d605807f983650fafbfdcf0c33bdf0c524c7185eae8c1501ae24892faf16b1ba03b51b0a35e4754ab21d1e48fed635d8486048df50c253ba9af4cebdb6a92a450"); } TEST(THORChainSwap, SwapBnbBtc) { @@ -634,15 +603,15 @@ TEST(THORChainSwap, SwapBnbBtc) { Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::BTC)); toAsset.set_symbol("BTC"); - auto && [out, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Bnb) - .toAddress(Address1Btc) - .vault(VaultBnb) - .fromAmount("10000000") - .toAmountLimit("10000000") - .build(); + auto&& [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Bnb) + .toAddress(Address1Btc) + .vault(VaultBnb) + .fromAmount("10000000") + .toAmountLimit("10000000") + .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); EXPECT_EQ(hex(out), "2a3d3d3a4254432e4254433a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070383a313030303030303052480a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e421080ade204"); @@ -675,15 +644,15 @@ TEST(THORChainSwap, SwapBnbEth) { Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::ETH)); toAsset.set_symbol("ETH"); - auto && [out, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Bnb) - .toAddress(Address1Eth) - .vault(VaultBnb) - .fromAmount("27000000") - .toAmountLimit("123456") - .build(); + auto&& [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Bnb) + .toAddress(Address1Eth) + .vault(VaultBnb) + .fromAmount("27000000") + .toAmountLimit("123456") + .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); EXPECT_EQ(hex(out), "2a3b3d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a31323334353652480a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e4210c0f9ef0c12220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e4210c0f9ef0c"); @@ -723,15 +692,15 @@ TEST(THORChainSwap, SwapBnbRune) { Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::THOR)); toAsset.set_symbol("RUNE"); - auto && [out, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Bnb) - .toAddress(Address1Thor) - .vault(VaultBnb) - .fromAmount("4000000") - .toAmountLimit("121065076") - .build(); + auto&& [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Bnb) + .toAddress(Address1Thor) + .vault(VaultBnb) + .fromAmount("4000000") + .toAmountLimit("121065076") + .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); EXPECT_EQ(hex(out), "2a413d3a54484f522e52554e453a74686f72317a3533777765376d64366365777a39737177717a6e306161767061756e3067773065786e32723a31323130363530373652480a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e42108092f40112220a1499730371c7c77cb81ffa76b566dcef7c1e5dc19c120a0a03424e42108092f401"); @@ -772,7 +741,7 @@ TEST(THORChainSwap, SwapBusdTokenBnb) { Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::BNB)); toAsset.set_symbol("BNB"); - auto && [out, errorCode, error] = SwapBuilder::builder() + auto&& [out, errorCode, error] = SwapBuilder::builder() .from(fromAsset) .to(toAsset) .fromAddress("bnb1gddl87crh47wzynjx3c6pmcclzk7txlkm74x28") @@ -824,15 +793,15 @@ TEST(THORChainSwap, SwapBnbBnbToken) { toAsset.set_chain(static_cast(Chain::BNB)); toAsset.set_symbol("BNB"); toAsset.set_token_id("TWT-8C2"); - auto && [out, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress("bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx") - .toAddress("bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx") - .vault("bnb1qefsjm654cdw94ejj8g4s49w7z8te75veslusz") - .fromAmount("10000000") - .toAmountLimit("5400000000") - .build(); + auto&& [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress("bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx") + .toAddress("bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx") + .vault("bnb1qefsjm654cdw94ejj8g4s49w7z8te75veslusz") + .fromAmount("10000000") + .toAmountLimit("5400000000") + .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); EXPECT_EQ(hex(out), "2a433d3a424e422e5457542d3843323a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3534303030303030303052480a220a14e42be736e933cf8b97c26f33789a3ca6f8348cd1120a0a03424e421080ade20412220a140653096f54ae1ae2d73291d15854aef08ebcfa8c120a0a03424e421080ade204"); @@ -875,17 +844,17 @@ TEST(THORChainSwap, SwapBtcEthWithAffFee) { Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::ETH)); toAsset.set_symbol("ETH"); - auto && [out, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Btc) - .toAddress(Address1Eth) - .vault(VaultBtc) - .fromAmount("1000000") - .toAmountLimit("140000000000000000") - .affFeeAddress("thrnm") - .affFeeRate("10") - .build(); + auto&& [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Btc) + .toAddress(Address1Eth) + .vault(VaultBtc) + .fromAmount("1000000") + .toAmountLimit("140000000000000000") + .affFeeAddress("thrnm") + .affFeeRate("10") + .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); EXPECT_EQ(hex(out), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a503d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7468726e6d3a3130"); @@ -921,19 +890,19 @@ TEST(THORChainSwap, SwapBtcEthWithAffFee) { ANY_SIGN(tx, TWCoinTypeBitcoin); EXPECT_EQ(output.error(), 0); EXPECT_EQ(hex(output.encoded()), // printed using prettyPrintTransaction - "01000000" // version - "0001" // marker & flag - "01" // inputs - "1234000000000000000000000000000000000000000000000000000000005678" "00000000" "00" "" "ffffffff" - "03" // outputs - "40420f0000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" - "0c9ceb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" - "0000000000000000" "53" "6a4c503d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7468726e6d3a3130" - // witness - "02" - "47" "3044022056e918d8dea9431057b7b8b7f7c990ff72d653aef296eda9a85e546537e1eaa4022050b64766ea4ce56ecd3325f184d67b20924fd4539cb40bbad916ede1cc26017f01" - "21" "021e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" - "00000000" // nLockTime + "01000000" // version + "0001" // marker & flag + "01" // inputs + "1234000000000000000000000000000000000000000000000000000000005678" "00000000" "00" "" "ffffffff" + "03" // outputs + "40420f0000000000" "16" "0014d6cbc5021c3eee72798718d447758b91d14e8c5f" + "0c9ceb0200000000" "16" "00140cb9f5c6b62c03249367bc20a90dd2425e6926af" + "0000000000000000" "53" "6a4c503d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a7468726e6d3a3130" + // witness + "02" + "47" "3044022056e918d8dea9431057b7b8b7f7c990ff72d653aef296eda9a85e546537e1eaa4022050b64766ea4ce56ecd3325f184d67b20924fd4539cb40bbad916ede1cc26017f01" + "21" "021e582a887bd94d648a9267143eb600449a8d59a0db0653740b1378067a6d0cee" + "00000000" // nLockTime ); } @@ -943,51 +912,27 @@ TEST(THORChainSwap, SwapEthBnbWithAffFee) { Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::BNB)); toAsset.set_symbol("BNB"); - auto && [out, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Eth) - .toAddress(Address1Bnb) - .vault(VaultEth) - .router(RouterEth) - .fromAmount("50000000000000000") - .toAmountLimit("600003") - .affFeeAddress("tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy") - .affFeeRate("10") - .build(); + auto&& [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Eth) + .toAddress(Address1Bnb) + .vault(VaultEth) + .fromAmount("50000000000000000") + .toAmountLimit("600003") + .affFeeAddress("tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy") + .affFeeRate("10") + .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); - EXPECT_EQ(hex(out), "0a01001201002201002a0100422a30783432413545643435363635306130394463313045426336333631413734383066446436316632374252b30232b0020a07b1a2bc2ec5000012a4021fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a3130000000000000000000000000000000000000"); + EXPECT_EQ(hex(out), "0a010012010018012201002a0100422a307831303931633444653661336346303943644130304162444165443432633763334236394338334543527b0a790a07b1a2bc2ec50000126e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a3130"); auto tx = Ethereum::Proto::SigningInput(); ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields - EXPECT_EQ(tx.to_address(), RouterEth); - ASSERT_TRUE(tx.transaction().has_contract_generic()); - - Data vaultAddressBin = SwapTest_ethAddressStringToData(VaultEth); - EXPECT_EQ(hex(vaultAddressBin), "1091c4de6a3cf09cda00abdaed42c7c3b69c83ec"); - auto func = Ethereum::ABI::Function("deposit", std::vector>{ - std::make_shared(vaultAddressBin), - std::make_shared(parse_hex("0000000000000000000000000000000000000000")), - std::make_shared(uint256_t(50000000000000000)), - std::make_shared("=:BNB.BNB:bnb1us47wdhfx08ch97zdueh3x3u5murfrx30jecrx:600003:tthor1ql2tcqyrqsgnql2tcqyj2n8kfdmt9lh0yzql2tcqy:10")}); - Data payload; - func.encode(payload); - EXPECT_EQ(hex(payload), "1fece7b4" - "0000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec" - "0000000000000000000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000b1a2bc2ec50000" - "0000000000000000000000000000000000000000000000000000000000000080" - "000000000000000000000000000000000000000000000000000000000000006e" - "3d3a424e422e424e423a626e62317573343777646866783038636839377a6475" - "656833783375356d757266727833306a656372783a3630303030333a7474686f" - "7231716c3274637179727173676e716c32746371796a326e386b66646d74396c" - "6830797a716c32746371793a3130000000000000000000000000000000000000"); - - EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().amount())), "b1a2bc2ec50000"); - EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().data())), hex(payload)); + EXPECT_EQ(tx.to_address(), VaultEth); + ASSERT_FALSE(tx.transaction().has_contract_generic()); EXPECT_EQ(hex(TW::data(tx.private_key())), ""); @@ -1006,7 +951,7 @@ TEST(THORChainSwap, SwapEthBnbWithAffFee) { // sign and encode resulting input Ethereum::Proto::SigningOutput output; ANY_SIGN(tx, TWCoinTypeEthereum); - EXPECT_EQ(hex(output.encoded()), "f90192038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b901241fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a313000000000000000000000000000000000000026a0ee68bd41da9a9b1ad87fd547e83e4b8022460de024839f4f5f528abc6aecf2aea0402205812d62a075138743f6048ba2a1c073f4a3a14224009a34ee74d3dccef1"); + EXPECT_EQ(hex(output.encoded()), "02f8d90103808083013880941091c4de6a3cf09cda00abdaed42c7c3b69c83ec87b1a2bc2ec50000b86e3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a3630303030333a7474686f7231716c3274637179727173676e716c32746371796a326e386b66646d74396c6830797a716c32746371793a3130c001a05c16871b66fd0fa8f658d6f171310bab332d09e0533d6c97329a59ddc93a9a11a05ed2be94e6dbb640e58920c8be4fa597cd5f0a918123245acb899042dd43777f"); } TEST(THORChainSwap, SwapBtcNegativeMemoTooLong) { @@ -1015,18 +960,18 @@ TEST(THORChainSwap, SwapBtcNegativeMemoTooLong) { Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::ETH)); toAsset.set_symbol("ETH"); - auto && [out, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Btc) - .toAddress(Address1Eth) - .vault(VaultBtc) - .fromAmount("1000000") - .toAmountLimit("140000000000000000") - .affFeeAddress("affiliate_address") - .affFeeRate("10") - .extraMemo("extra_memo_very_loooooooooooooong") - .build(); + auto&& [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Btc) + .toAddress(Address1Eth) + .vault(VaultBtc) + .fromAmount("1000000") + .toAmountLimit("140000000000000000") + .affFeeAddress("affiliate_address") + .affFeeRate("10") + .extraMemo("extra_memo_very_loooooooooooooong") + .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); EXPECT_EQ(hex(out), "080110c0843d1801222a62633171366d397532717375386d68387937763872723279776176746a38673561727a6c796863656a372a2a62633171706a756c7433346b3973706a66796d38687373326a72776a676630786a6634307a65307070386a7e3d3a4554482e4554483a3078623966353737316332373636346266323238326439386530396437663530636563376362303161373a3134303030303030303030303030303030303a616666696c696174655f616464726573733a31303a65787472615f6d656d6f5f766572795f6c6f6f6f6f6f6f6f6f6f6f6f6f6f6f6e67"); @@ -1104,28 +1049,28 @@ TEST(THORChainSwap, WrongFromAddress) { toAsset.set_chain(static_cast(Chain::ETH)); toAsset.set_symbol("ETH"); { - auto && [_, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress("DummyAddress") - .toAddress(Address1Eth) - .vault(VaultEth) - .fromAmount("1000000") - .toAmountLimit("100000") - .build(); + auto&& [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress("DummyAddress") + .toAddress(Address1Eth) + .vault(VaultEth) + .fromAmount("1000000") + .toAmountLimit("100000") + .build(); EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Invalid_from_address); EXPECT_EQ(error, "Invalid from address"); } { - auto && [_, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Btc) - .toAddress(Address1Eth) - .vault(VaultEth) - .fromAmount("1000000") - .toAmountLimit("100000") - .build(); + auto&& [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Btc) + .toAddress(Address1Eth) + .vault(VaultEth) + .fromAmount("1000000") + .toAmountLimit("100000") + .build(); EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Invalid_from_address); EXPECT_EQ(error, "Invalid from address"); } @@ -1138,28 +1083,28 @@ TEST(THORChainSwap, WrongToAddress) { toAsset.set_chain(static_cast(Chain::ETH)); toAsset.set_symbol("ETH"); { - auto && [_, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Bnb) - .toAddress("DummyAddress") - .vault(VaultEth) - .fromAmount("100000") - .toAmountLimit("100000") - .build(); + auto&& [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Bnb) + .toAddress("DummyAddress") + .vault(VaultEth) + .fromAmount("100000") + .toAmountLimit("100000") + .build(); EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Invalid_to_address); EXPECT_EQ(error, "Invalid to address"); } { - auto && [_, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Bnb) - .toAddress(Address1Btc) - .vault(VaultEth) - .fromAmount("100000") - .toAmountLimit("100000") - .build(); + auto&& [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Bnb) + .toAddress(Address1Btc) + .vault(VaultEth) + .fromAmount("100000") + .toAmountLimit("100000") + .build(); EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Invalid_to_address); EXPECT_EQ(error, "Invalid to address"); } @@ -1171,14 +1116,14 @@ TEST(THORChainSwap, FromRuneNotSupported) { Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::BNB)); toAsset.set_symbol("BNB"); - auto && [_, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Thor) - .toAddress(Address1Bnb) - .fromAmount("1000") - .toAmountLimit("1000") - .build(); + auto&& [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Thor) + .toAddress(Address1Bnb) + .fromAmount("1000") + .toAmountLimit("1000") + .build(); EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Unsupported_from_chain); EXPECT_EQ(error, "Unsupported from chain: 0"); } @@ -1190,30 +1135,31 @@ TEST(THORChainSwap, EthInvalidVault) { toAsset.set_chain(static_cast(Chain::BNB)); toAsset.set_symbol("BNB"); { - auto && [_, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Eth) - .toAddress(Address1Bnb) - .vault("_INVALID_ADDRESS_") - .router(RouterEth) - .fromAmount("50000000000000000") - .toAmountLimit("600003") - .build(); + fromAsset.set_token_id("0x53595320f158d4546677b4795cc66dff59d154db"); + auto&& [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Eth) + .toAddress(Address1Bnb) + .vault("_INVALID_ADDRESS_") + .router(RouterEth) + .fromAmount("50000000000000000") + .toAmountLimit("600003") + .build(); EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Invalid_vault_address); EXPECT_EQ(error, "Invalid vault address: _INVALID_ADDRESS_"); } { - auto && [_, errorCode, error] = SwapBuilder::builder() - .from(fromAsset) - .to(toAsset) - .fromAddress(Address1Eth) - .toAddress(Address1Bnb) - .vault(VaultEth) - .router("_INVALID_ADDRESS_") - .fromAmount("50000000000000000") - .toAmountLimit("600003") - .build(); + auto&& [_, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Eth) + .toAddress(Address1Bnb) + .vault(VaultEth) + .router("_INVALID_ADDRESS_") + .fromAmount("50000000000000000") + .toAmountLimit("600003") + .build(); EXPECT_EQ(errorCode, Proto::ErrorCode::Error_Invalid_router_address); EXPECT_EQ(error, "Invalid router address: _INVALID_ADDRESS_"); } diff --git a/tests/chains/THORChain/TWSwapTests.cpp b/tests/chains/THORChain/TWSwapTests.cpp index 3d46e960f03..ce5f215241a 100644 --- a/tests/chains/THORChain/TWSwapTests.cpp +++ b/tests/chains/THORChain/TWSwapTests.cpp @@ -144,7 +144,7 @@ TEST(TWTHORChainSwap, SwapEthBnb) { // invoke swap const auto outputTWData_ = WRAPD(TWTHORChainSwapBuildSwap(inputTWData_.get())); const auto outputData = data(TWDataBytes(outputTWData_.get()), TWDataSize(outputTWData_.get())); - EXPECT_EQ(outputData.size(), 311ul); + EXPECT_EQ(outputData.size(), 141ul); // parse result in proto Proto::SwapOutput outputProto; EXPECT_TRUE(outputProto.ParseFromArray(outputData.data(), static_cast(outputData.size()))); @@ -171,7 +171,7 @@ TEST(TWTHORChainSwap, SwapEthBnb) { // sign and encode resulting input Ethereum::Proto::SigningOutput output; ANY_SIGN(txInput, TWCoinTypeEthereum); - EXPECT_EQ(hex(output.encoded()), "f90151038506fc23ac00830138809442a5ed456650a09dc10ebc6361a7480fdd61f27b87b1a2bc2ec50000b8e41fece7b40000000000000000000000001091c4de6a3cf09cda00abdaed42c7c3b69c83ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003b3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a363030303033000000000026a0669563be8a0022fcd32fdf82ccca7dc66012ea28c57e95a2d9348dbf37afc377a03505f5eb041038c565d2f2888207c9dbcad8ca12f10ce5c5bd2ca41de01a9e89"); + EXPECT_EQ(hex(output.encoded()), "02f8a60103808083013880941091c4de6a3cf09cda00abdaed42c7c3b69c83ec87b1a2bc2ec50000b83b3d3a424e422e424e423a626e62317573343777646866783038636839377a6475656833783375356d757266727833306a656372783a363030303033c080a00d605807f983650fafbfdcf0c33bdf0c524c7185eae8c1501ae24892faf16b1ba03b51b0a35e4754ab21d1e48fed635d8486048df50c253ba9af4cebdb6a92a450"); } TEST(TWTHORChainSwap, SwapBnbBtc) { From 299f9047e06d96783ce6d579690727836e892355 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 18 Jan 2023 09:05:43 +0100 Subject: [PATCH 173/497] feat(swift): update Package.swift (#2879) --- Package.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Package.swift b/Package.swift index 7448baba099..0fdcdb93fe9 100644 --- a/Package.swift +++ b/Package.swift @@ -12,13 +12,13 @@ let package = Package( targets: [ .binaryTarget( name: "WalletCore", - url: "https://github.com/trustwallet/wallet-core/releases/download/3.1.0/WalletCore.xcframework.zip", - checksum: "2487af30a8f6f4775a41f29456f792f15269f4f4daae2da7e4b9ef8747613e3a" + url: "https://github.com/trustwallet/wallet-core/releases/download/3.1.8/WalletCore.xcframework.zip", + checksum: "ce7e45a8eea666dacc5cd9076f597e4f824c030299414c7fdd91e71b29aa09cc" ), .binaryTarget( name: "SwiftProtobuf", - url: "https://github.com/trustwallet/wallet-core/releases/download/3.1.0/SwiftProtobuf.xcframework.zip", - checksum: "2038b1d43c9f6aeb4957e3763382b8558983a1a811b168dca71be3636bb8350a" + url: "https://github.com/trustwallet/wallet-core/releases/download/3.1.8/SwiftProtobuf.xcframework.zip", + checksum: "222a306b49d7733b9c5d790b07c0d8240f68f27315f1d127aa4ed743b1b11920" ) ] ) From 0257de2dd4ba03e26a49e365871aa2c71ddd0a38 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 18 Jan 2023 09:09:23 +0100 Subject: [PATCH 174/497] [EIP1014]: eip1014 support (#2873) --- .../ethereum/TestEthereumAddress.kt | 12 ++ .../core/app/utils/TestHDWallet.kt | 2 +- .../{TWEthereumEip2645.h => TWEthereum.h} | 14 ++- src/Ethereum/EIP1014.cpp | 34 ++++++ src/Ethereum/EIP1014.h | 16 +++ .../{TWEthereumEip2645.cpp => TWEthereum.cpp} | 13 +- swift/Tests/Blockchains/EthereumTests.swift | 8 ++ swift/Tests/HDWalletTests.swift | 2 +- tests/chains/Ethereum/EIP1014Tests.cpp | 113 ++++++++++++++++++ tests/interface/TWHDWalletTests.cpp | 2 +- 10 files changed, 209 insertions(+), 7 deletions(-) rename include/TrustWalletCore/{TWEthereumEip2645.h => TWEthereum.h} (57%) create mode 100644 src/Ethereum/EIP1014.cpp create mode 100644 src/Ethereum/EIP1014.h rename src/interface/{TWEthereumEip2645.cpp => TWEthereum.cpp} (57%) create mode 100644 tests/chains/Ethereum/EIP1014Tests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt index f4b29c5db5d..c860c1dbaac 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt @@ -1,10 +1,13 @@ package com.trustwallet.core.app.blockchains.ethereum +import com.trustwallet.core.app.utils.Numeric import org.junit.Assert.assertEquals import org.junit.Test import wallet.core.jni.AnyAddress import wallet.core.jni.CoinType import org.junit.Assert.assertFalse +import wallet.core.jni.Ethereum +import wallet.core.jni.Hash class TestEthereumAddress { @@ -12,6 +15,15 @@ class TestEthereumAddress { System.loadLibrary("TrustWalletCore") } + @Test + fun testEthereumCreate2Addresses() { + val from = "0x0000000000000000000000000000000000000000" + val salt = Numeric.hexStringToByteArray("0x0000000000000000000000000000000000000000000000000000000000000000") + val initCodeHash = Hash.keccak256(Numeric.hexStringToByteArray("0x0")) + val result = Ethereum.eip1014AddressCreate2(from, salt, initCodeHash) + assertEquals(result, "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38") + } + @Test fun testEthereumAddresses() { val any = AnyAddress("0x7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1", CoinType.ETHEREUM) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt index 07c91d0829b..bd0faaef521 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt @@ -29,7 +29,7 @@ class TestHDWallet { fun testCreateFromMnemonicImmutableXMainnetFromSignature() { // Successfully register: https://api.x.immutable.com/v1/users/0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37 val hd = HDWallet("obscure opera favorite shuffle mail tip age debate dirt pact cement loyal", "") - val derivationPath = EthereumEip2645.getPath("0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37", "starkex", "immutablex", "1") + val derivationPath = Ethereum.eip2645GetPath("0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37", "starkex", "immutablex", "1") assertEquals(derivationPath, "m/2645'/579218131'/211006541'/2124474935'/1609799702'/1") // Retrieve eth private key diff --git a/include/TrustWalletCore/TWEthereumEip2645.h b/include/TrustWalletCore/TWEthereum.h similarity index 57% rename from include/TrustWalletCore/TWEthereumEip2645.h rename to include/TrustWalletCore/TWEthereum.h index 95678fa8be6..3da4511af74 100644 --- a/include/TrustWalletCore/TWEthereumEip2645.h +++ b/include/TrustWalletCore/TWEthereum.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2022 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,12 +7,22 @@ #pragma once #include "TWBase.h" +#include "TWData.h" #include "TWString.h" TW_EXTERN_C_BEGIN TW_EXPORT_STRUCT -struct TWEthereumEip2645; +struct TWEthereum; + +/// EIP-1014: Skinny CREATE2 (guess smart contract create2 address) +/// +/// \param fromEthAddress valid eth address +/// \param salt always 32 bytes stack item +/// \param initCodeHash The init_code is the code that, when executed, produces the runtime bytecode that will be placed into the state, and which typically is used by high level languages to implement a ‘constructor’. Need to be provided hashed with keccak256 +/// \return Ethereum resulting address +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumEip1014AddressCreate2(TWString* _Nonnull fromEthAddress, TWData* _Nonnull salt, TWData* _Nonnull initCodeHash); /// Generate a layer 2 eip2645 derivation path from eth address, layer, application and given index. /// diff --git a/src/Ethereum/EIP1014.cpp b/src/Ethereum/EIP1014.cpp new file mode 100644 index 00000000000..4242126a8d1 --- /dev/null +++ b/src/Ethereum/EIP1014.cpp @@ -0,0 +1,34 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "EIP1014.h" +#include "AddressChecksum.h" +#include "Hash.h" +#include "HexCoding.h" + +namespace TW::Ethereum { + +Data create2Address(const std::string& from, const Data& salt, const Data& initCodeHash) { + if (salt.size() != 32) { + throw std::runtime_error("Error: salt must be 32 bytes."); + } + if (initCodeHash.size() != 32) { + throw std::runtime_error("Error: initCodeHash must be 32 bytes."); + } + Data input = {0xff}; + append(input, parse_hex(from)); + append(input, salt); + append(input, initCodeHash); + auto hash = Hash::keccak256(input); + return Data(hash.end() - 20, hash.end()); +} + +std::string create2AddressString(const std::string& from, const Data& salt, const Data& initCodeHash) { + auto addressData = create2Address(from, salt, initCodeHash); + return Ethereum::checksumed(Address(hexEncoded(addressData))); +} + +} // namespace TW::Ethereum diff --git a/src/Ethereum/EIP1014.h b/src/Ethereum/EIP1014.h new file mode 100644 index 00000000000..d1bde394e22 --- /dev/null +++ b/src/Ethereum/EIP1014.h @@ -0,0 +1,16 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" + +namespace TW::Ethereum { + +Data create2Address(const std::string& from, const Data& salt, const Data& initCodeHash); +std::string create2AddressString(const std::string& from, const Data& salt, const Data& initCodeHash); + +} diff --git a/src/interface/TWEthereumEip2645.cpp b/src/interface/TWEthereum.cpp similarity index 57% rename from src/interface/TWEthereumEip2645.cpp rename to src/interface/TWEthereum.cpp index 21a9082573a..e08c0f12c79 100644 --- a/src/interface/TWEthereumEip2645.cpp +++ b/src/interface/TWEthereum.cpp @@ -1,14 +1,23 @@ -// Copyright © 2017-2022 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -#include +#include "Data.h" +#include "Ethereum/EIP1014.h" #include "Ethereum/EIP2645.h" +#include #include +TWString* TWEthereumEip1014AddressCreate2(TWString* _Nonnull fromEthAddress, TWData* _Nonnull salt, TWData* _Nonnull initCodeHash) { + const auto& ethAddressStr = *reinterpret_cast(fromEthAddress); + const auto& saltData = *reinterpret_cast(salt); + const auto& initCodeHashData = *reinterpret_cast(initCodeHash); + return new std::string(TW::Ethereum::create2AddressString(ethAddressStr, saltData, initCodeHashData)); +} + TWString* TWEthereumEip2645GetPath(TWString* ethAddress, TWString* layer, TWString* application, TWString* index) { const auto& ethAddressStr = *reinterpret_cast(ethAddress); const auto& layerStr = *reinterpret_cast(layer); diff --git a/swift/Tests/Blockchains/EthereumTests.swift b/swift/Tests/Blockchains/EthereumTests.swift index e53e1cdebb1..1409816761f 100644 --- a/swift/Tests/Blockchains/EthereumTests.swift +++ b/swift/Tests/Blockchains/EthereumTests.swift @@ -9,6 +9,14 @@ import WalletCore class EthereumTests: XCTestCase { + func testCreate2Address() { + let address = "0x0000000000000000000000000000000000000000" + let salt = Data(hexString: "0x0000000000000000000000000000000000000000000000000000000000000000")! + let initCodeHash = Hash.keccak256(data: Data(hexString: "0x00")!) + let result = Ethereum.eip1014AddressCreate2(fromEthAddress: address, salt: salt, initCodeHash: initCodeHash) + XCTAssertEqual(result, "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38") + } + func testAddress() { let anyAddress = AnyAddress(string: "0x7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1", coin: .ethereum) diff --git a/swift/Tests/HDWalletTests.swift b/swift/Tests/HDWalletTests.swift index 6dccac4705f..537f8b0a961 100644 --- a/swift/Tests/HDWalletTests.swift +++ b/swift/Tests/HDWalletTests.swift @@ -15,7 +15,7 @@ class HDWalletTests: XCTestCase { func testFromMnemonicImmutableXMainnetFromSignature() { let wallet = HDWallet(mnemonic: "obscure opera favorite shuffle mail tip age debate dirt pact cement loyal", passphrase: "")! - let starkDerivationPath = EthereumEip2645.getPath(ethAddress: "0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37", layer: "starkex", application: "immutablex", index: "1") + let starkDerivationPath = Ethereum.eip2645GetPath(ethAddress: "0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37", layer: "starkex", application: "immutablex", index: "1") XCTAssertEqual(starkDerivationPath, "m/2645'/579218131'/211006541'/2124474935'/1609799702'/1") // Retrieve eth private key diff --git a/tests/chains/Ethereum/EIP1014Tests.cpp b/tests/chains/Ethereum/EIP1014Tests.cpp new file mode 100644 index 00000000000..2a9e38864bd --- /dev/null +++ b/tests/chains/Ethereum/EIP1014Tests.cpp @@ -0,0 +1,113 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "TestUtilities.h" +#include +#include +#include +#include +#include +#include + +#include + +namespace TW::Ethereum::tests { + TEST(EthereumEip1014, Example0) { + // C++ + { + const std::string& from = "0x0000000000000000000000000000000000000000"; + const Data salt = parse_hex("0x0000000000000000000000000000000000000000000000000000000000000000"); + Data initCodeHash = Hash::keccak256(parse_hex("0x00")); + const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); + ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38"); + ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38"); + } + + // C + { + const auto from = STRING("0x0000000000000000000000000000000000000000"); + const auto salt = DATA("0x0000000000000000000000000000000000000000000000000000000000000000"); + const auto initCodeHash = WRAPD(TWHashKeccak256(DATA("0x00").get())); + const auto& result = WRAPS(TWEthereumEip1014AddressCreate2(from.get(), salt.get(), initCodeHash.get())); + assertStringsEqual(result, "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38"); + } + } + + TEST(EthereumEip1014, Example1) { + // C++ + { + const std::string& from = "0xdeadbeef00000000000000000000000000000000"; + const Data salt = parse_hex("0x0000000000000000000000000000000000000000000000000000000000000000"); + Data initCodeHash = Hash::keccak256(parse_hex("0x00")); + const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); + ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0xB928f69Bb1D91Cd65274e3c79d8986362984fDA3"); + ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0xB928f69Bb1D91Cd65274e3c79d8986362984fDA3"); + } + + // C + { + const auto from = STRING("0xdeadbeef00000000000000000000000000000000"); + const auto salt = DATA("0x0000000000000000000000000000000000000000000000000000000000000000"); + const auto initCodeHash = WRAPD(TWHashKeccak256(DATA("0x00").get())); + const auto& result = WRAPS(TWEthereumEip1014AddressCreate2(from.get(), salt.get(), initCodeHash.get())); + assertStringsEqual(result, "0xB928f69Bb1D91Cd65274e3c79d8986362984fDA3"); + } + } + + TEST(EthereumEip1014, Example2) { + const std::string& from = "0xdeadbeef00000000000000000000000000000000"; + const Data salt = parse_hex("0x000000000000000000000000feed000000000000000000000000000000000000"); + Data initCodeHash = Hash::keccak256(parse_hex("0x00")); + const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); + ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0xD04116cDd17beBE565EB2422F2497E06cC1C9833"); + ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0xD04116cDd17beBE565EB2422F2497E06cC1C9833"); + } + + TEST(EthereumEip1014, Example3) { + const std::string& from = "0x0000000000000000000000000000000000000000"; + const Data salt = parse_hex("0x0000000000000000000000000000000000000000000000000000000000000000"); + Data initCodeHash = Hash::keccak256(parse_hex("0xdeadbeef")); + const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); + ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x70f2b2914A2a4b783FaEFb75f459A580616Fcb5e"); + ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0x70f2b2914A2a4b783FaEFb75f459A580616Fcb5e"); + } + + TEST(EthereumEip1014, Example4) { + const std::string& from = "0x00000000000000000000000000000000deadbeef"; + const Data salt = parse_hex("0x00000000000000000000000000000000000000000000000000000000cafebabe"); + Data initCodeHash = Hash::keccak256(parse_hex("0xdeadbeef")); + const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); + ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x60f3f640a8508fC6a86d45DF051962668E1e8AC7"); + ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0x60f3f640a8508fC6a86d45DF051962668E1e8AC7"); + } + + TEST(EthereumEip1014, Example5) { + const std::string& from = "0x00000000000000000000000000000000deadbeef"; + const Data salt = parse_hex("0x00000000000000000000000000000000000000000000000000000000cafebabe"); + Data initCodeHash = Hash::keccak256(parse_hex("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); + const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); + ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x1d8bfDC5D46DC4f61D6b6115972536eBE6A8854C"); + ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0x1d8bfDC5D46DC4f61D6b6115972536eBE6A8854C"); + } + + TEST(EthereumEip1014, Example6) { + const std::string& from = "0x0000000000000000000000000000000000000000"; + const Data salt = parse_hex("0x0000000000000000000000000000000000000000000000000000000000000000"); + Data initCodeHash = Hash::keccak256(parse_hex("0x")); + const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); + ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0"); + ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0"); + } + + TEST(EthereumEip1014, Example7) { + const std::string& from = "0x7EF2e0048f5bAeDe046f6BF797943daF4ED8CB47"; + const Data salt = parse_hex("0x0000000000000000000000000000000000000000000000000000000000000000"); + Data initCodeHash = Hash::keccak256(parse_hex("0x608060405260405162000c5138038062000c51833981810160405281019062000029919062000580565b6200003d828260006200004560201b60201c565b5050620007d7565b62000056836200008860201b60201c565b600082511180620000645750805b156200008357620000818383620000df60201b620000371760201c565b505b505050565b62000099816200011560201b60201c565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b60606200010d838360405180606001604052806027815260200162000c2a60279139620001eb60201b60201c565b905092915050565b6200012b816200027d60201b620000641760201c565b6200016d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000164906200066d565b60405180910390fd5b80620001a77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b620002a060201b620000871760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60606000808573ffffffffffffffffffffffffffffffffffffffff1685604051620002179190620006dc565b600060405180830381855af49150503d806000811462000254576040519150601f19603f3d011682016040523d82523d6000602084013e62000259565b606091505b50915091506200027286838387620002aa60201b60201c565b925050509392505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b606083156200031a5760008351036200031157620002ce856200027d60201b60201c565b62000310576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620003079062000745565b60405180910390fd5b5b8290506200032d565b6200032c83836200033560201b60201c565b5b949350505050565b600082511115620003495781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200037f9190620007b3565b60405180910390fd5b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620003c9826200039c565b9050919050565b620003db81620003bc565b8114620003e757600080fd5b50565b600081519050620003fb81620003d0565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b62000456826200040b565b810181811067ffffffffffffffff821117156200047857620004776200041c565b5b80604052505050565b60006200048d62000388565b90506200049b82826200044b565b919050565b600067ffffffffffffffff821115620004be57620004bd6200041c565b5b620004c9826200040b565b9050602081019050919050565b60005b83811015620004f6578082015181840152602081019050620004d9565b60008484015250505050565b6000620005196200051384620004a0565b62000481565b90508281526020810184848401111562000538576200053762000406565b5b62000545848285620004d6565b509392505050565b600082601f83011262000565576200056462000401565b5b81516200057784826020860162000502565b91505092915050565b600080604083850312156200059a576200059962000392565b5b6000620005aa85828601620003ea565b925050602083015167ffffffffffffffff811115620005ce57620005cd62000397565b5b620005dc858286016200054d565b9150509250929050565b600082825260208201905092915050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b600062000655602d83620005e6565b91506200066282620005f7565b604082019050919050565b60006020820190508181036000830152620006888162000646565b9050919050565b600081519050919050565b600081905092915050565b6000620006b2826200068f565b620006be81856200069a565b9350620006d0818560208601620004d6565b80840191505092915050565b6000620006ea8284620006a5565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b60006200072d601d83620005e6565b91506200073a82620006f5565b602082019050919050565b6000602082019050818103600083015262000760816200071e565b9050919050565b600081519050919050565b60006200077f8262000767565b6200078b8185620005e6565b93506200079d818560208601620004d6565b620007a8816200040b565b840191505092915050565b60006020820190508181036000830152620007cf818462000772565b905092915050565b61044380620007e76000396000f3fe6080604052366100135761001161001d565b005b61001b61001d565b005b610025610091565b610035610030610093565b6100a2565b565b606061005c83836040518060600160405280602781526020016103e7602791396100c8565b905092915050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b565b600061009d61014e565b905090565b3660008037600080366000845af43d6000803e80600081146100c3573d6000f35b3d6000fd5b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516100f291906102db565b600060405180830381855af49150503d806000811461012d576040519150601f19603f3d011682016040523d82523d6000602084013e610132565b606091505b5091509150610143868383876101a5565b925050509392505050565b600061017c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b610087565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606083156102075760008351036101ff576101bf85610064565b6101fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101f59061034f565b60405180910390fd5b5b829050610212565b610211838361021a565b5b949350505050565b60008251111561022d5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161026191906103c4565b60405180910390fd5b600081519050919050565b600081905092915050565b60005b8381101561029e578082015181840152602081019050610283565b60008484015250505050565b60006102b58261026a565b6102bf8185610275565b93506102cf818560208601610280565b80840191505092915050565b60006102e782846102aa565b915081905092915050565b600082825260208201905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000610339601d836102f2565b915061034482610303565b602082019050919050565b600060208201905081810360008301526103688161032c565b9050919050565b600081519050919050565b6000601f19601f8301169050919050565b60006103968261036f565b6103a081856102f2565b93506103b0818560208601610280565b6103b98161037a565b840191505092915050565b600060208201905081810360008301526103de818461038b565b90509291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220e57dd3eafc9985be746025b6d82d4f011b9a7bb3db56f9a1eb7eadfddd376b6064736f6c63430008110033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564000000000000000000000000d9ec9e840bb5df076dbbb488d01485058f421e5800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000024c4d66de8000000000000000000000000be8fa0112dcb7d21dc63645b633073651e19934800000000000000000000000000000000000000000000000000000000")); + const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); + ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x4455e5f0038795939c001aa4d296A45956C460AA"); + ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0x4455e5f0038795939c001aa4d296A45956C460AA"); + } +} diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp index 9cbf538898b..f97644e1ad5 100644 --- a/tests/interface/TWHDWalletTests.cpp +++ b/tests/interface/TWHDWalletTests.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include From eb92d06340613d63b1705ffb3b0a137271647b73 Mon Sep 17 00:00:00 2001 From: safocl Date: Mon, 23 Jan 2023 17:58:23 +0400 Subject: [PATCH 175/497] fixed error of the [array with mismatched bound] in trezor-crypto/crypto/sha2.c (#2884) --- trezor-crypto/crypto/sha2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trezor-crypto/crypto/sha2.c b/trezor-crypto/crypto/sha2.c index bea30dae7cf..47d7eebbcdb 100644 --- a/trezor-crypto/crypto/sha2.c +++ b/trezor-crypto/crypto/sha2.c @@ -589,7 +589,7 @@ void sha1_Update(SHA1_CTX* context, const sha2_byte *data, size_t len) { usedspace = freespace = 0; } -void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { +void sha1_Final(SHA1_CTX* context, sha2_byte digest[SHA1_DIGEST_LENGTH]) { unsigned int usedspace = 0; /* If no digest buffer is passed, we don't bother doing this: */ @@ -896,7 +896,7 @@ void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { usedspace = freespace = 0; } -void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { +void sha256_Final(SHA256_CTX* context, sha2_byte digest[SHA256_DIGEST_LENGTH]) { unsigned int usedspace = 0; /* If no digest buffer is passed, we don't bother doing this: */ @@ -1250,7 +1250,7 @@ static void sha512_Last(SHA512_CTX* context) { sha512_Transform(context->state, context->buffer, context->state); } -void sha512_Final(SHA512_CTX* context, sha2_byte digest[]) { +void sha512_Final(SHA512_CTX* context, sha2_byte digest[SHA512_DIGEST_LENGTH]) { /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { sha512_Last(context); From 2f0be459b4acb107547ec9624bc02a570aa07a9c Mon Sep 17 00:00:00 2001 From: Ruslan Serebriakov Date: Tue, 24 Jan 2023 05:53:15 +0000 Subject: [PATCH 176/497] [EIP4337]: deployment address calculation (#2885) --- .../ethereum/TestEthereumAddress.kt | 9 ++++ include/TrustWalletCore/TWEthereum.h | 8 ++++ src/Ethereum/EIP1967.cpp | 31 ++++++++++++ src/Ethereum/EIP1967.h | 15 ++++++ src/Ethereum/EIP4337.cpp | 34 ++++++++++++++ src/Ethereum/EIP4337.h | 16 +++++++ src/interface/TWEthereum.cpp | 8 ++++ swift/Tests/Blockchains/EthereumTests.swift | 8 ++++ tests/chains/Ethereum/EIP1967Tests.cpp | 28 +++++++++++ tests/chains/Ethereum/EIP4337Tests.cpp | 47 +++++++++++++++++++ 10 files changed, 204 insertions(+) create mode 100644 src/Ethereum/EIP1967.cpp create mode 100644 src/Ethereum/EIP1967.h create mode 100644 src/Ethereum/EIP4337.cpp create mode 100644 src/Ethereum/EIP4337.h create mode 100644 tests/chains/Ethereum/EIP1967Tests.cpp create mode 100644 tests/chains/Ethereum/EIP4337Tests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt index c860c1dbaac..3089d9bd510 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt @@ -32,4 +32,13 @@ class TestEthereumAddress { assertFalse(AnyAddress.isValid("0xMQqpqMQgCBuiPkoXfgZZsJvuzCeI1zc00z6vHJj4", CoinType.ETHEREUM)) } + + @Test + fun testEthereumEIP4337DeploymentAddress() { + val factoryAddress = "0xd9145CCE52D386f254917e481eB44e9943F39138" + val logicAddress = "0x5C9eb5D6a6C2c1B3EFc52255C0b356f116f6f66D" + val ownerAddress = "0xA5a1dddEF094095AfB7b6e322dE72961DF2e1988" + val result = Ethereum.eip4337GetDeploymentAddress(factoryAddress, logicAddress, ownerAddress) + assertEquals(result, "0xbEaA87cEEaC906C21aaacd258FbFB87CfA3c90a8") + } } diff --git a/include/TrustWalletCore/TWEthereum.h b/include/TrustWalletCore/TWEthereum.h index 3da4511af74..9fab0ddba90 100644 --- a/include/TrustWalletCore/TWEthereum.h +++ b/include/TrustWalletCore/TWEthereum.h @@ -35,4 +35,12 @@ TWString* _Nonnull TWEthereumEip1014AddressCreate2(TWString* _Nonnull fromEthAdd TW_EXPORT_STATIC_METHOD TWString* _Nonnull TWEthereumEip2645GetPath(TWString* _Nonnull ethAddress, TWString* _Nonnull layer, TWString* _Nonnull application, TWString* _Nonnull index); +/// Generates a deployment address for a ERC-4337 compatible smart contract wallet +/// +/// \param factoryAddress non-null address of the account factory +/// \param logicAddress non-null address of the wallet's logic smart contract +/// \param ownerAddress non-null address of the signing key that controls the smart contract wallet +/// \return Ethereum resulting address +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumEip4337GetDeploymentAddress(TWString* _Nonnull factoryAddress, TWString* _Nonnull logicAddress, TWString* _Nonnull ownerAddress); TW_EXTERN_C_END diff --git a/src/Ethereum/EIP1967.cpp b/src/Ethereum/EIP1967.cpp new file mode 100644 index 00000000000..55a6907d8f1 --- /dev/null +++ b/src/Ethereum/EIP1967.cpp @@ -0,0 +1,31 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "EIP1014.h" +#include "AddressChecksum.h" +#include "Hash.h" +#include "HexCoding.h" +#include +#include "ABI.h" + +namespace TW::Ethereum { + +static const std::string eip1967ProxyBytecodeHex = R"(0x608060405260405162000c5138038062000c51833981810160405281019062000029919062000580565b6200003d828260006200004560201b60201c565b5050620007d7565b62000056836200008860201b60201c565b600082511180620000645750805b156200008357620000818383620000df60201b620000371760201c565b505b505050565b62000099816200011560201b60201c565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b60606200010d838360405180606001604052806027815260200162000c2a60279139620001eb60201b60201c565b905092915050565b6200012b816200027d60201b620000641760201c565b6200016d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000164906200066d565b60405180910390fd5b80620001a77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b620002a060201b620000871760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60606000808573ffffffffffffffffffffffffffffffffffffffff1685604051620002179190620006dc565b600060405180830381855af49150503d806000811462000254576040519150601f19603f3d011682016040523d82523d6000602084013e62000259565b606091505b50915091506200027286838387620002aa60201b60201c565b925050509392505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b606083156200031a5760008351036200031157620002ce856200027d60201b60201c565b62000310576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620003079062000745565b60405180910390fd5b5b8290506200032d565b6200032c83836200033560201b60201c565b5b949350505050565b600082511115620003495781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200037f9190620007b3565b60405180910390fd5b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620003c9826200039c565b9050919050565b620003db81620003bc565b8114620003e757600080fd5b50565b600081519050620003fb81620003d0565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b62000456826200040b565b810181811067ffffffffffffffff821117156200047857620004776200041c565b5b80604052505050565b60006200048d62000388565b90506200049b82826200044b565b919050565b600067ffffffffffffffff821115620004be57620004bd6200041c565b5b620004c9826200040b565b9050602081019050919050565b60005b83811015620004f6578082015181840152602081019050620004d9565b60008484015250505050565b6000620005196200051384620004a0565b62000481565b90508281526020810184848401111562000538576200053762000406565b5b62000545848285620004d6565b509392505050565b600082601f83011262000565576200056462000401565b5b81516200057784826020860162000502565b91505092915050565b600080604083850312156200059a576200059962000392565b5b6000620005aa85828601620003ea565b925050602083015167ffffffffffffffff811115620005ce57620005cd62000397565b5b620005dc858286016200054d565b9150509250929050565b600082825260208201905092915050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b600062000655602d83620005e6565b91506200066282620005f7565b604082019050919050565b60006020820190508181036000830152620006888162000646565b9050919050565b600081519050919050565b600081905092915050565b6000620006b2826200068f565b620006be81856200069a565b9350620006d0818560208601620004d6565b80840191505092915050565b6000620006ea8284620006a5565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b60006200072d601d83620005e6565b91506200073a82620006f5565b602082019050919050565b6000602082019050818103600083015262000760816200071e565b9050919050565b600081519050919050565b60006200077f8262000767565b6200078b8185620005e6565b93506200079d818560208601620004d6565b620007a8816200040b565b840191505092915050565b60006020820190508181036000830152620007cf818462000772565b905092915050565b61044380620007e76000396000f3fe6080604052366100135761001161001d565b005b61001b61001d565b005b610025610091565b610035610030610093565b6100a2565b565b606061005c83836040518060600160405280602781526020016103e7602791396100c8565b905092915050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b565b600061009d61014e565b905090565b3660008037600080366000845af43d6000803e80600081146100c3573d6000f35b3d6000fd5b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516100f291906102db565b600060405180830381855af49150503d806000811461012d576040519150601f19603f3d011682016040523d82523d6000602084013e610132565b606091505b5091509150610143868383876101a5565b925050509392505050565b600061017c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b610087565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606083156102075760008351036101ff576101bf85610064565b6101fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101f59061034f565b60405180910390fd5b5b829050610212565b610211838361021a565b5b949350505050565b60008251111561022d5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161026191906103c4565b60405180910390fd5b600081519050919050565b600081905092915050565b60005b8381101561029e578082015181840152602081019050610283565b60008484015250505050565b60006102b58261026a565b6102bf8185610275565b93506102cf818560208601610280565b80840191505092915050565b60006102e782846102aa565b915081905092915050565b600082825260208201905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000610339601d836102f2565b915061034482610303565b602082019050919050565b600060208201905081810360008301526103688161032c565b9050919050565b600081519050919050565b6000601f19601f8301169050919050565b60006103968261036f565b6103a081856102f2565b93506103b0818560208601610280565b6103b98161037a565b840191505092915050565b600060208201905081810360008301526103de818461038b565b90509291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220e57dd3eafc9985be746025b6d82d4f011b9a7bb3db56f9a1eb7eadfddd376b6064736f6c63430008110033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564)"; + +Data getEIP1967ProxyInitCode(const std::string& logicAddress, const Data& data) { + Data initCode = parse_hex(eip1967ProxyBytecodeHex); + + auto proxyConstructorParams = ABI::ParamTuple(); + proxyConstructorParams.addParam(std::make_shared(parse_hex(logicAddress))); + proxyConstructorParams.addParam(std::make_shared(data)); + Data proxyConstructorParamsEncoded; + proxyConstructorParams.encode(proxyConstructorParamsEncoded); + + append(initCode, proxyConstructorParamsEncoded); + return initCode; +} + +} // namespace TW::Ethereum diff --git a/src/Ethereum/EIP1967.h b/src/Ethereum/EIP1967.h new file mode 100644 index 00000000000..b9b65210f97 --- /dev/null +++ b/src/Ethereum/EIP1967.h @@ -0,0 +1,15 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" + +namespace TW::Ethereum { + +Data getEIP1967ProxyInitCode(const std::string& logicAddress, const Data& data); + +} diff --git a/src/Ethereum/EIP4337.cpp b/src/Ethereum/EIP4337.cpp new file mode 100644 index 00000000000..dd770fc16e5 --- /dev/null +++ b/src/Ethereum/EIP4337.cpp @@ -0,0 +1,34 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "EIP1014.h" +#include "EIP1967.h" +#include "AddressChecksum.h" +#include "Hash.h" +#include "HexCoding.h" +#include +#include "ABI.h" + +namespace TW::Ethereum { + +Data getEIP4337LogicInitializeBytecode(const std::string& ownerAddress) { + auto initializeFunc = ABI::Function("initialize", std::vector>{ + std::make_shared(parse_hex(ownerAddress)) + }); + Data initializeFuncEncoded; + initializeFunc.encode(initializeFuncEncoded); + return initializeFuncEncoded; +} + +std::string getEIP4337DeploymentAddress(const std::string& factoryAddress, const std::string& logicAddress, const std::string& ownerAddress) { + const Data logicInitializeBytecode = getEIP4337LogicInitializeBytecode(ownerAddress); + const Data proxyInitCode = getEIP1967ProxyInitCode(logicAddress, logicInitializeBytecode); + const Data salt = parse_hex("0x0000000000000000000000000000000000000000000000000000000000000000"); + const Data initCodeHash = Hash::keccak256(proxyInitCode); + return create2AddressString(factoryAddress, salt, initCodeHash); +} + +} // namespace TW::Ethereum diff --git a/src/Ethereum/EIP4337.h b/src/Ethereum/EIP4337.h new file mode 100644 index 00000000000..540bd2dd6e4 --- /dev/null +++ b/src/Ethereum/EIP4337.h @@ -0,0 +1,16 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" + +namespace TW::Ethereum { + +std::string getEIP4337DeploymentAddress(const std::string& factoryAddress, const std::string& logicAddress, const std::string& ownerAddress); +Data getEIP4337LogicInitializeBytecode(const std::string& ownerAddress); + +} diff --git a/src/interface/TWEthereum.cpp b/src/interface/TWEthereum.cpp index e08c0f12c79..ee8c42a7b85 100644 --- a/src/interface/TWEthereum.cpp +++ b/src/interface/TWEthereum.cpp @@ -6,6 +6,7 @@ #include "Data.h" #include "Ethereum/EIP1014.h" +#include "Ethereum/EIP4337.h" #include "Ethereum/EIP2645.h" #include @@ -25,3 +26,10 @@ TWString* TWEthereumEip2645GetPath(TWString* ethAddress, TWString* layer, TWStri const auto& indexStr = *reinterpret_cast(index); return new std::string(TW::Ethereum::accountPathFromAddress(ethAddressStr, layerStr, applicationStr, indexStr)); } + +TWString* TWEthereumEip4337GetDeploymentAddress(TWString* _Nonnull factoryAddress, TWString* _Nonnull logicAddress, TWString* _Nonnull ownerAddress) { + const auto& factoryAddressStr = *reinterpret_cast(factoryAddress); + const auto& logicAddressStr = *reinterpret_cast(logicAddress); + const auto& ownerAddressStr = *reinterpret_cast(ownerAddress); + return new std::string(TW::Ethereum::getEIP4337DeploymentAddress(factoryAddressStr, logicAddressStr, ownerAddressStr)); +} \ No newline at end of file diff --git a/swift/Tests/Blockchains/EthereumTests.swift b/swift/Tests/Blockchains/EthereumTests.swift index 1409816761f..766e5d310ff 100644 --- a/swift/Tests/Blockchains/EthereumTests.swift +++ b/swift/Tests/Blockchains/EthereumTests.swift @@ -16,6 +16,14 @@ class EthereumTests: XCTestCase { let result = Ethereum.eip1014AddressCreate2(fromEthAddress: address, salt: salt, initCodeHash: initCodeHash) XCTAssertEqual(result, "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38") } + + func testEIP4337DeploymentAddress() { + let factoryAddress = "0xd9145CCE52D386f254917e481eB44e9943F39138" + let logicAddress = "0x5C9eb5D6a6C2c1B3EFc52255C0b356f116f6f66D" + let ownerAddress = "0xA5a1dddEF094095AfB7b6e322dE72961DF2e1988" + let result = Ethereum.eip4337GetDeploymentAddress(factoryAddress: factoryAddress, logicAddress: logicAddress, ownerAddress: ownerAddress) + XCTAssertEqual(result, "0xbEaA87cEEaC906C21aaacd258FbFB87CfA3c90a8") + } func testAddress() { let anyAddress = AnyAddress(string: "0x7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1", coin: .ethereum) diff --git a/tests/chains/Ethereum/EIP1967Tests.cpp b/tests/chains/Ethereum/EIP1967Tests.cpp new file mode 100644 index 00000000000..58a7313dfb1 --- /dev/null +++ b/tests/chains/Ethereum/EIP1967Tests.cpp @@ -0,0 +1,28 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "TestUtilities.h" +#include +#include +#include +#include +#include + +#include + +namespace TW::Ethereum::tests { + +TEST(EthereumEip1967, Example0) { + // C++ + { + const std::string& login_address = "0x5C9eb5D6a6C2c1B3EFc52255C0b356f116f6f66D"; + const Data data = parse_hex("0xc4d66de8000000000000000000000000a5a1dddef094095afb7b6e322de72961df2e1988"); + const Data initCode = Ethereum::getEIP1967ProxyInitCode(login_address, data); + ASSERT_EQ(hexEncoded(initCode), "0x608060405260405162000c5138038062000c51833981810160405281019062000029919062000580565b6200003d828260006200004560201b60201c565b5050620007d7565b62000056836200008860201b60201c565b600082511180620000645750805b156200008357620000818383620000df60201b620000371760201c565b505b505050565b62000099816200011560201b60201c565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b60606200010d838360405180606001604052806027815260200162000c2a60279139620001eb60201b60201c565b905092915050565b6200012b816200027d60201b620000641760201c565b6200016d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000164906200066d565b60405180910390fd5b80620001a77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b620002a060201b620000871760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60606000808573ffffffffffffffffffffffffffffffffffffffff1685604051620002179190620006dc565b600060405180830381855af49150503d806000811462000254576040519150601f19603f3d011682016040523d82523d6000602084013e62000259565b606091505b50915091506200027286838387620002aa60201b60201c565b925050509392505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b606083156200031a5760008351036200031157620002ce856200027d60201b60201c565b62000310576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620003079062000745565b60405180910390fd5b5b8290506200032d565b6200032c83836200033560201b60201c565b5b949350505050565b600082511115620003495781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200037f9190620007b3565b60405180910390fd5b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620003c9826200039c565b9050919050565b620003db81620003bc565b8114620003e757600080fd5b50565b600081519050620003fb81620003d0565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b62000456826200040b565b810181811067ffffffffffffffff821117156200047857620004776200041c565b5b80604052505050565b60006200048d62000388565b90506200049b82826200044b565b919050565b600067ffffffffffffffff821115620004be57620004bd6200041c565b5b620004c9826200040b565b9050602081019050919050565b60005b83811015620004f6578082015181840152602081019050620004d9565b60008484015250505050565b6000620005196200051384620004a0565b62000481565b90508281526020810184848401111562000538576200053762000406565b5b62000545848285620004d6565b509392505050565b600082601f83011262000565576200056462000401565b5b81516200057784826020860162000502565b91505092915050565b600080604083850312156200059a576200059962000392565b5b6000620005aa85828601620003ea565b925050602083015167ffffffffffffffff811115620005ce57620005cd62000397565b5b620005dc858286016200054d565b9150509250929050565b600082825260208201905092915050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b600062000655602d83620005e6565b91506200066282620005f7565b604082019050919050565b60006020820190508181036000830152620006888162000646565b9050919050565b600081519050919050565b600081905092915050565b6000620006b2826200068f565b620006be81856200069a565b9350620006d0818560208601620004d6565b80840191505092915050565b6000620006ea8284620006a5565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b60006200072d601d83620005e6565b91506200073a82620006f5565b602082019050919050565b6000602082019050818103600083015262000760816200071e565b9050919050565b600081519050919050565b60006200077f8262000767565b6200078b8185620005e6565b93506200079d818560208601620004d6565b620007a8816200040b565b840191505092915050565b60006020820190508181036000830152620007cf818462000772565b905092915050565b61044380620007e76000396000f3fe6080604052366100135761001161001d565b005b61001b61001d565b005b610025610091565b610035610030610093565b6100a2565b565b606061005c83836040518060600160405280602781526020016103e7602791396100c8565b905092915050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b565b600061009d61014e565b905090565b3660008037600080366000845af43d6000803e80600081146100c3573d6000f35b3d6000fd5b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516100f291906102db565b600060405180830381855af49150503d806000811461012d576040519150601f19603f3d011682016040523d82523d6000602084013e610132565b606091505b5091509150610143868383876101a5565b925050509392505050565b600061017c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b610087565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606083156102075760008351036101ff576101bf85610064565b6101fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101f59061034f565b60405180910390fd5b5b829050610212565b610211838361021a565b5b949350505050565b60008251111561022d5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161026191906103c4565b60405180910390fd5b600081519050919050565b600081905092915050565b60005b8381101561029e578082015181840152602081019050610283565b60008484015250505050565b60006102b58261026a565b6102bf8185610275565b93506102cf818560208601610280565b80840191505092915050565b60006102e782846102aa565b915081905092915050565b600082825260208201905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000610339601d836102f2565b915061034482610303565b602082019050919050565b600060208201905081810360008301526103688161032c565b9050919050565b600081519050919050565b6000601f19601f8301169050919050565b60006103968261036f565b6103a081856102f2565b93506103b0818560208601610280565b6103b98161037a565b840191505092915050565b600060208201905081810360008301526103de818461038b565b90509291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220e57dd3eafc9985be746025b6d82d4f011b9a7bb3db56f9a1eb7eadfddd376b6064736f6c63430008110033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65640000000000000000000000005c9eb5d6a6c2c1b3efc52255c0b356f116f6f66d00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000024c4d66de8000000000000000000000000a5a1dddef094095afb7b6e322de72961df2e198800000000000000000000000000000000000000000000000000000000"); + } +} + +} diff --git a/tests/chains/Ethereum/EIP4337Tests.cpp b/tests/chains/Ethereum/EIP4337Tests.cpp new file mode 100644 index 00000000000..294a3dc75e5 --- /dev/null +++ b/tests/chains/Ethereum/EIP4337Tests.cpp @@ -0,0 +1,47 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "TestUtilities.h" +#include +#include +#include +#include +#include + +#include + +namespace TW::Ethereum::tests { + +TEST(EthereumEip4337, GetEIP4337LogicInitializeBytecode) { + { + const std::string& ownerAddress = "0xA5a1dddEF094095AfB7b6e322dE72961DF2e1988"; + const auto& initializeEncoded = Ethereum::getEIP4337LogicInitializeBytecode(ownerAddress); + ASSERT_EQ(hexEncoded(initializeEncoded), "0xc4d66de8000000000000000000000000a5a1dddef094095afb7b6e322de72961df2e1988"); + } +} + +// https://goerli.etherscan.io/address/0x5a87209b755781cf65feeedd3855ade0317f4a92#readContract +TEST(EthereumEip4337, GetEIP4337DeploymentAddress) { + // C++ + { + const std::string& factoryAddress = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92"; + const std::string& logicAddress = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620"; + const std::string& ownerAddress = "0x78d9C32b96Bb872D66D51818227563f44e67E238"; + const std::string& deploymentAddress = Ethereum::getEIP4337DeploymentAddress(factoryAddress, logicAddress, ownerAddress); + ASSERT_EQ(deploymentAddress, "0x8cE23B8769ac01d0df0d5f47Be1A38FeA97F3879"); + } + + // C + { + const auto factoryAddress = STRING("0x5A87209b755781cF65fEeEdd3855ade0317f4a92"); + const auto logicAddress = STRING("0x21cc27d7db4fa19857a3702653a7a67ee30ca620"); + const auto ownerAddress = STRING("0x78d9C32b96Bb872D66D51818227563f44e67E238"); + const auto& result = WRAPS(TWEthereumEip4337GetDeploymentAddress(factoryAddress.get(), logicAddress.get(), ownerAddress.get())); + assertStringsEqual(result, "0x8cE23B8769ac01d0df0d5f47Be1A38FeA97F3879"); + } +} + +} From af8b9784d83935cc93eb4ad4fcdc5f92edbf206d Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 24 Jan 2023 10:36:41 +0100 Subject: [PATCH 177/497] [Eip155-Eip712]: add eip-155 + eip712 support to sign message (#2877) --- .../ethereum/TestEthereumMessageSigner.kt | 100 ++++++- .../core/app/utils/TestHDWallet.kt | 4 +- .../TrustWalletCore/TWEthereumMessageSigner.h | 34 +++ src/Ethereum/EIP191.cpp | 38 --- src/Ethereum/MessageSigner.cpp | 75 ++++++ src/Ethereum/{EIP191.h => MessageSigner.h} | 21 +- src/interface/TWEthereumMessageSigner.cpp | 39 ++- swift/Tests/Blockchains/EthereumTests.swift | 92 ++++++- swift/Tests/HDWalletTests.swift | 4 +- tests/chains/Ethereum/EIP1014Tests.cpp | 20 +- tests/chains/Ethereum/EIP191Tests.cpp | 37 --- .../Ethereum/EthereumMessageSignerTests.cpp | 246 ++++++++++++++++++ tests/chains/Ethereum/SignerTests.cpp | 2 +- tests/common/HDWallet/HDWalletTests.cpp | 12 +- tests/interface/TWHDWalletTests.cpp | 4 +- 15 files changed, 623 insertions(+), 105 deletions(-) delete mode 100644 src/Ethereum/EIP191.cpp create mode 100644 src/Ethereum/MessageSigner.cpp rename src/Ethereum/{EIP191.h => MessageSigner.h} (60%) delete mode 100644 tests/chains/Ethereum/EIP191Tests.cpp create mode 100644 tests/chains/Ethereum/EthereumMessageSignerTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumMessageSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumMessageSigner.kt index 0f0aae9efc4..6b86f698769 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumMessageSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumMessageSigner.kt @@ -15,13 +15,109 @@ class TestEthereumMessageSigner { } @Test - fun testEthereumSignAndVerifyMessage() { + fun testEthereumSignAndVerifyMessageImmutableX() { val data = Numeric.hexStringToByteArray("3b0a61f46fdae924007146eacb6db6642de7a5603ad843ec58e10331d89d4b84") val privateKey = PrivateKey(data) val publicKey = privateKey.getPublicKey(CoinType.ETHEREUM) val msg = "Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3" - val signature = EthereumMessageSigner.signMessage(privateKey, msg) + val signature = EthereumMessageSigner.signMessageImmutableX(privateKey, msg) assertEquals(signature, "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01"); assertTrue(EthereumMessageSigner.verifyMessage(publicKey, msg, signature)) } + + @Test + fun testEthereumSignAndVerifyMessageLegacy() { + val data = Numeric.hexStringToByteArray("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKey(CoinType.ETHEREUM) + val msg = "Foo" + val signature = EthereumMessageSigner.signMessage(privateKey, msg) + assertEquals(signature, "21a779d499957e7fd39392d49a079679009e60e492d9654a148829be43d2490736ec72bc4a5644047d979c3cf4ebe2c1c514044cf436b063cb89fc6676be71101b"); + assertTrue(EthereumMessageSigner.verifyMessage(publicKey, msg, signature)) + } + + @Test + fun testEthereumSignAndVerifyMessage712Legacy() { + val data = Numeric.hexStringToByteArray("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKey(CoinType.ETHEREUM) + val msg = """ + { + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Person": [ + {"name": "name", "type": "string"}, + {"name": "wallet", "type": "address"} + ] + }, + "primaryType": "Person", + "domain": { + "name": "Ether Person", + "version": "1", + "chainId": 0, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "name": "Cow", + "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + } + } + """.trimIndent() + val signature = EthereumMessageSigner.signTypedMessage(privateKey, msg) + assertEquals(signature, "446434e4c34d6b7456e5f07a1b994b88bf85c057234c68d1e10c936b1c85706c4e19147c0ac3a983bc2d56ebfd7146f8b62bcea6114900fe8e7d7351f44bf3761c"); + assertTrue(EthereumMessageSigner.verifyMessage(publicKey, msg, signature)) + } + + @Test + fun testEthereumSignAndVerifyMessage712Eip155() { + val data = Numeric.hexStringToByteArray("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKey(CoinType.ETHEREUM) + val msg = """ + { + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Person": [ + {"name": "name", "type": "string"}, + {"name": "wallet", "type": "address"} + ] + }, + "primaryType": "Person", + "domain": { + "name": "Ether Person", + "version": "1", + "chainId": 0, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "name": "Cow", + "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + } + } + """.trimIndent() + val signature = EthereumMessageSigner.signTypedMessageEip155(privateKey, msg, 0) + assertEquals(signature, "446434e4c34d6b7456e5f07a1b994b88bf85c057234c68d1e10c936b1c85706c4e19147c0ac3a983bc2d56ebfd7146f8b62bcea6114900fe8e7d7351f44bf37624"); + assertTrue(EthereumMessageSigner.verifyMessage(publicKey, msg, signature)) + } + + @Test + fun testEthereumSignAndVerifyMessageEip155() { + val data = Numeric.hexStringToByteArray("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d") + val privateKey = PrivateKey(data) + val publicKey = privateKey.getPublicKey(CoinType.ETHEREUM) + val msg = "Foo" + val signature = EthereumMessageSigner.signMessageEip155(privateKey, msg, 0) + assertEquals(signature, "21a779d499957e7fd39392d49a079679009e60e492d9654a148829be43d2490736ec72bc4a5644047d979c3cf4ebe2c1c514044cf436b063cb89fc6676be711023"); + assertTrue(EthereumMessageSigner.verifyMessage(publicKey, msg, signature)) + } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt index bd0faaef521..45806099afb 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestHDWallet.kt @@ -41,7 +41,7 @@ class TestHDWallet { // Retrieve Stark Private key part val ethMsg = "Only sign this request if you’ve initiated an action with Immutable X." - val ethSignature = EthereumMessageSigner.signMessage(ethPrivateKey, ethMsg) + val ethSignature = EthereumMessageSigner.signMessageImmutableX(ethPrivateKey, ethMsg) assertEquals(ethSignature, "18b1be8b78807d3326e28bc286d7ee3d068dcd90b1949ce1d25c1f99825f26e70992c5eb7f44f76b202aceded00d74f771ed751f2fe538eec01e338164914fe001") val starkPrivateKey = StarkWare.getStarkKeyFromSignature(starkDerivationPath, ethSignature) val starkPublicKey = starkPrivateKey.getPublicKeyByType(PublicKeyType.STARKEX) @@ -50,7 +50,7 @@ class TestHDWallet { // Account register val ethMsgToRegister = "Only sign this key linking request from Immutable X" - val ethSignatureToRegister = EthereumMessageSigner.signMessage(ethPrivateKey, ethMsgToRegister) + val ethSignatureToRegister = EthereumMessageSigner.signMessageImmutableX(ethPrivateKey, ethMsgToRegister) assertEquals(ethSignatureToRegister, "646da4160f7fc9205e6f502fb7691a0bf63ecbb74bbb653465cd62388dd9f56325ab1e4a9aba99b1661e3e6251b42822855a71e60017b310b9f90e990a12e1dc01") val starkMsg = "463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf" val starkSignature = StarkExMessageSigner.signMessage(starkPrivateKey, starkMsg) diff --git a/include/TrustWalletCore/TWEthereumMessageSigner.h b/include/TrustWalletCore/TWEthereumMessageSigner.h index e33a3e3dad1..5a1db56a516 100644 --- a/include/TrustWalletCore/TWEthereumMessageSigner.h +++ b/include/TrustWalletCore/TWEthereumMessageSigner.h @@ -21,6 +21,23 @@ TW_EXTERN_C_BEGIN TW_EXPORT_STRUCT struct TWEthereumMessageSigner; +/// Sign a typed message EIP-712 V4. +/// +/// \param privateKey: the private key used for signing +/// \param messageJson: A custom typed data message in json +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumMessageSignerSignTypedMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull messageJson); + +/// Sign a typed message EIP-712 V4 with EIP-155 replay attack protection. +/// +/// \param privateKey: the private key used for signing +/// \param messageJson: A custom typed data message in json +/// \param chainId: chainId for eip-155 protection +/// \returns the signature, Hex-encoded. On invalid input empty string is returned or invalid chainId error message. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumMessageSignerSignTypedMessageEip155(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull messageJson, int chainId); + /// Sign a message. /// /// \param privateKey: the private key used for signing @@ -29,6 +46,23 @@ struct TWEthereumMessageSigner; TW_EXPORT_STATIC_METHOD TWString* _Nonnull TWEthereumMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message); +/// Sign a message with Immutable X msg type. +/// +/// \param privateKey: the private key used for signing +/// \param message: A custom message which is input to the signing. +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumMessageSignerSignMessageImmutableX(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message); + +/// Sign a message with Eip-155 msg type. +/// +/// \param privateKey: the private key used for signing +/// \param message: A custom message which is input to the signing. +/// \param chainId: chainId for eip-155 protection +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWEthereumMessageSignerSignMessageEip155(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message, int chainId); + /// Verify signature for a message. /// /// \param pubKey: pubKey that will verify and recover the message from the signature diff --git a/src/Ethereum/EIP191.cpp b/src/Ethereum/EIP191.cpp deleted file mode 100644 index 309c61c959c..00000000000 --- a/src/Ethereum/EIP191.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright © 2017-2022 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -#include "EIP191.h" -#include "HexCoding.h" -#include -#include - -namespace TW::Ethereum::internal { - -Data generateMessage(const std::string& message) { - std::string prefix(1, MessageSigner::EthereumPrefix); - std::stringstream ss; - ss << prefix << MessageSigner::MessagePrefix << std::to_string(message.size()) << message; - Data signableMessage = Hash::keccak256(data(ss.str())); - return signableMessage; -} - -} // namespace TW::Ethereum::internal - -namespace TW::Ethereum { - -std::string MessageSigner::signMessage(const PrivateKey& privateKey, const std::string& message) { - auto signableMessage = internal::generateMessage(message); - return hex(privateKey.sign(signableMessage, TWCurveSECP256k1)); -} - -bool MessageSigner::verifyMessage(const PublicKey& publicKey, const std::string& message, const std::string& signature) noexcept { - auto msg = internal::generateMessage(message); - auto rawSignature = parse_hex(signature); - auto recovered = publicKey.recover(rawSignature, msg); - return recovered == publicKey && publicKey.verify(rawSignature, msg); -} - -} // namespace TW::Ethereum diff --git a/src/Ethereum/MessageSigner.cpp b/src/Ethereum/MessageSigner.cpp new file mode 100644 index 00000000000..fa86a3097f2 --- /dev/null +++ b/src/Ethereum/MessageSigner.cpp @@ -0,0 +1,75 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "MessageSigner.h" +#include +#include +#include + +namespace TW::Ethereum::internal { + +Data generateMessage(const std::string& message) { + std::string prefix(1, MessageSigner::EthereumPrefix); + std::stringstream ss; + ss << prefix << MessageSigner::MessagePrefix << std::to_string(message.size()) << message; + Data signableMessage = Hash::keccak256(data(ss.str())); + return signableMessage; +} + +std::string commonSign(const PrivateKey& privateKey, const Data& signableMessage, MessageType msgType, TW::Ethereum::MessageSigner::MaybeChainId chainId) { + auto data = privateKey.sign(signableMessage, TWCurveSECP256k1); + switch (msgType) { + case MessageType::ImmutableX: + break; + case MessageType::Legacy: + data[64] += 27; + break; + case MessageType::Eip155: + auto id = chainId.value_or(0); + data[64] += 35 + id * 2; + break; + } + return hex(data); +} + +} // namespace TW::Ethereum::internal + +namespace TW::Ethereum { + +std::string MessageSigner::signMessage(const PrivateKey& privateKey, const std::string& message, MessageType msgType, MaybeChainId chainId) { + auto signableMessage = internal::generateMessage(message); + return internal::commonSign(privateKey, signableMessage, msgType, chainId); +} + +std::string MessageSigner::signTypedData(const PrivateKey& privateKey, const std::string& data, MessageType msgType, MessageSigner::MaybeChainId chainId) { + if (msgType == MessageType::Eip155 && nlohmann::json::accept(data)) { + auto json = nlohmann::json::parse(data); + if (json.contains("types") && json.at("types").contains("EIP712Domain")) { + if (json.at("domain").at("chainId").get() != *chainId) { + return "EIP712 chainId is different than the current chainID."; + } + } + } + auto signableMessage = ABI::ParamStruct::hashStructJson(data); + return internal::commonSign(privateKey, signableMessage, msgType, chainId); +} + +bool MessageSigner::verifyMessage(const PublicKey& publicKey, const std::string& message, const std::string& signature) noexcept { + Data msg = internal::generateMessage(message); + //! If it's json && EIP712Domain then we hash the struct + if (nlohmann::json::accept(message)) { + auto json = nlohmann::json::parse(message); + if (json.contains("types") && json.at("types").contains("EIP712Domain")) { + msg = ABI::ParamStruct::hashStructJson(message); + } + } + auto rawSignature = parse_hex(signature); + auto recovered = publicKey.recover(rawSignature, msg); + return recovered == publicKey && publicKey.verify(rawSignature, msg); +} + +} // namespace TW::Ethereum diff --git a/src/Ethereum/EIP191.h b/src/Ethereum/MessageSigner.h similarity index 60% rename from src/Ethereum/EIP191.h rename to src/Ethereum/MessageSigner.h index c1267ab0452..4cb3c1e9598 100644 --- a/src/Ethereum/EIP191.h +++ b/src/Ethereum/MessageSigner.h @@ -8,16 +8,35 @@ #include #include +#include namespace TW::Ethereum { +enum class MessageType { + Legacy = 1, + Eip155 = 2, + ImmutableX = 3 +}; + class MessageSigner { public: + using MaybeChainId = std::optional; /// Sign a message following EIP-191 /// \param privateKey the private key to sign with /// \param message message to sign + /// \param msgType message type to sign + /// \param chainId optional chainId if msgType is eip155 + /// \return hex signed message + static std::string signMessage(const PrivateKey& privateKey, const std::string& message, MessageType msgType, MaybeChainId chainId = std::nullopt); + + /// Sign typed data according to EIP-712 V4 + /// \param privateKey the private key to sign with + /// \param data json data + /// \param msgType message type to sign + /// \param chainId optional chainId if msgType is eip155 /// \return hex signed message - static std::string signMessage(const PrivateKey& privateKey, const std::string& message); + static std::string signTypedData(const PrivateKey& privateKey, const std::string& data, MessageType msgType, MaybeChainId chainId = std::nullopt); + /// Verify a message following EIP-191 /// \param publicKey publickey to verify the signed message /// \param message message to be verified as a string diff --git a/src/interface/TWEthereumMessageSigner.cpp b/src/interface/TWEthereumMessageSigner.cpp index 19e1d6e3705..75ce9f884e4 100644 --- a/src/interface/TWEthereumMessageSigner.cpp +++ b/src/interface/TWEthereumMessageSigner.cpp @@ -6,17 +6,50 @@ #include -#include "Ethereum/EIP191.h" +#include "Ethereum/MessageSigner.h" -TWString* _Nonnull TWEthereumMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message) { +namespace TW::internal { + +TWString* _Nonnull TWEthereumMessageSignerSignCommon(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message, Ethereum::MessageType msgType, Ethereum::MessageSigner::MaybeChainId chainId = std::nullopt) { try { - const auto signature = TW::Ethereum::MessageSigner::signMessage(privateKey->impl, TWStringUTF8Bytes(message)); + const auto signature = TW::Ethereum::MessageSigner::signMessage(privateKey->impl, TWStringUTF8Bytes(message), msgType, chainId); return TWStringCreateWithUTF8Bytes(signature.c_str()); } catch (...) { return TWStringCreateWithUTF8Bytes(""); } } +TWString* _Nonnull TWEthereumMessageSignerSignTypedCommon(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message, Ethereum::MessageType msgType, Ethereum::MessageSigner::MaybeChainId chainId = std::nullopt) { + try { + const auto signature = TW::Ethereum::MessageSigner::signTypedData(privateKey->impl, TWStringUTF8Bytes(message), msgType, chainId); + return TWStringCreateWithUTF8Bytes(signature.c_str()); + } catch (...) { + return TWStringCreateWithUTF8Bytes(""); + } +} + +} // namespace TW::internal + +TWString* _Nonnull TWEthereumMessageSignerSignTypedMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull messageJson) { + return TW::internal::TWEthereumMessageSignerSignTypedCommon(privateKey, messageJson, TW::Ethereum::MessageType::Legacy); +} + +TWString* _Nonnull TWEthereumMessageSignerSignTypedMessageEip155(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull messageJson, int chainId) { + return TW::internal::TWEthereumMessageSignerSignTypedCommon(privateKey, messageJson, TW::Ethereum::MessageType::Eip155, static_cast(chainId)); +} + +TWString* _Nonnull TWEthereumMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message) { + return TW::internal::TWEthereumMessageSignerSignCommon(privateKey, message, TW::Ethereum::MessageType::Legacy); +} + +TWString* _Nonnull TWEthereumMessageSignerSignMessageImmutableX(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message) { + return TW::internal::TWEthereumMessageSignerSignCommon(privateKey, message, TW::Ethereum::MessageType::ImmutableX); +} + +TWString* _Nonnull TWEthereumMessageSignerSignMessageEip155(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message, int chainId) { + return TW::internal::TWEthereumMessageSignerSignCommon(privateKey, message, TW::Ethereum::MessageType::Eip155, static_cast(chainId)); +} + bool TWEthereumMessageSignerVerifyMessage(const struct TWPublicKey* _Nonnull publicKey, TWString* _Nonnull message, TWString* _Nonnull signature) { return TW::Ethereum::MessageSigner::verifyMessage(publicKey->impl, TWStringUTF8Bytes(message), TWStringUTF8Bytes(signature)); } diff --git a/swift/Tests/Blockchains/EthereumTests.swift b/swift/Tests/Blockchains/EthereumTests.swift index 766e5d310ff..4a94e459445 100644 --- a/swift/Tests/Blockchains/EthereumTests.swift +++ b/swift/Tests/Blockchains/EthereumTests.swift @@ -291,12 +291,100 @@ class EthereumTests: XCTestCase { XCTAssertEqual(btcAddress, "bc1q97jc0jdgsyvvhxydxxd6np8sa920c39l3qpscf") } - func testMessageAndVerifySigner() { + func testMessageAndVerifySignerImmutableX() { let privateKey = PrivateKey(data: Data(hexString: "3b0a61f46fdae924007146eacb6db6642de7a5603ad843ec58e10331d89d4b84")!)! let msg = "Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3" - let signature = EthereumMessageSigner.signMessage(privateKey: privateKey, message: msg) + let signature = EthereumMessageSigner.signMessageImmutableX(privateKey: privateKey, message: msg) XCTAssertEqual(signature, "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01") let pubKey = privateKey.getPublicKey(coinType: .ethereum) XCTAssertTrue(EthereumMessageSigner.verifyMessage(pubKey: pubKey, message: msg, signature: signature)) } + + func testMessageAndVerifySignerLegacy() { + let privateKey = PrivateKey(data: Data(hexString: "03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d")!)! + let msg = "Foo" + let signature = EthereumMessageSigner.signMessage(privateKey: privateKey, message: msg) + XCTAssertEqual(signature, "21a779d499957e7fd39392d49a079679009e60e492d9654a148829be43d2490736ec72bc4a5644047d979c3cf4ebe2c1c514044cf436b063cb89fc6676be71101b") + let pubKey = privateKey.getPublicKey(coinType: .ethereum) + XCTAssertTrue(EthereumMessageSigner.verifyMessage(pubKey: pubKey, message: msg, signature: signature)) + } + + func testMessageAndVerifySignerEip155() { + let privateKey = PrivateKey(data: Data(hexString: "03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d")!)! + let msg = "Foo" + let signature = EthereumMessageSigner.signMessageEip155(privateKey: privateKey, message: msg, chainId: 0) + XCTAssertEqual(signature, "21a779d499957e7fd39392d49a079679009e60e492d9654a148829be43d2490736ec72bc4a5644047d979c3cf4ebe2c1c514044cf436b063cb89fc6676be711023") + let pubKey = privateKey.getPublicKey(coinType: .ethereum) + XCTAssertTrue(EthereumMessageSigner.verifyMessage(pubKey: pubKey, message: msg, signature: signature)) + } + + func testMessageAndVerifySigner712Legacy() { + let privateKey = PrivateKey(data: Data(hexString: "03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d")!)! + let msg = """ + { + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Person": [ + {"name": "name", "type": "string"}, + {"name": "wallet", "type": "address"} + ] + }, + "primaryType": "Person", + "domain": { + "name": "Ether Person", + "version": "1", + "chainId": 0, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "name": "Cow", + "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + } + } + """ + let signature = EthereumMessageSigner.signTypedMessage(privateKey: privateKey, messageJson: msg) + XCTAssertEqual(signature, "446434e4c34d6b7456e5f07a1b994b88bf85c057234c68d1e10c936b1c85706c4e19147c0ac3a983bc2d56ebfd7146f8b62bcea6114900fe8e7d7351f44bf3761c") + let pubKey = privateKey.getPublicKey(coinType: .ethereum) + XCTAssertTrue(EthereumMessageSigner.verifyMessage(pubKey: pubKey, message: msg, signature: signature)) + } + + func testMessageAndVerifySigner712Eip155() { + let privateKey = PrivateKey(data: Data(hexString: "03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d")!)! + let msg = """ + { + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Person": [ + {"name": "name", "type": "string"}, + {"name": "wallet", "type": "address"} + ] + }, + "primaryType": "Person", + "domain": { + "name": "Ether Person", + "version": "1", + "chainId": 0, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "name": "Cow", + "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + } + } + """ + let signature = EthereumMessageSigner.signTypedMessageEip155(privateKey: privateKey, messageJson: msg, chainId: 0) + XCTAssertEqual(signature, "446434e4c34d6b7456e5f07a1b994b88bf85c057234c68d1e10c936b1c85706c4e19147c0ac3a983bc2d56ebfd7146f8b62bcea6114900fe8e7d7351f44bf37624") + let pubKey = privateKey.getPublicKey(coinType: .ethereum) + XCTAssertTrue(EthereumMessageSigner.verifyMessage(pubKey: pubKey, message: msg, signature: signature)) + } } diff --git a/swift/Tests/HDWalletTests.swift b/swift/Tests/HDWalletTests.swift index 537f8b0a961..ea077ee52e0 100644 --- a/swift/Tests/HDWalletTests.swift +++ b/swift/Tests/HDWalletTests.swift @@ -27,7 +27,7 @@ class HDWalletTests: XCTestCase { // Retrieve Stark Private key part let ethMsg = "Only sign this request if you’ve initiated an action with Immutable X." - let ethSignature = EthereumMessageSigner.signMessage(privateKey: ethPrivateKey, message: ethMsg) + let ethSignature = EthereumMessageSigner.signMessageImmutableX(privateKey: ethPrivateKey, message: ethMsg) XCTAssertEqual(ethSignature, "18b1be8b78807d3326e28bc286d7ee3d068dcd90b1949ce1d25c1f99825f26e70992c5eb7f44f76b202aceded00d74f771ed751f2fe538eec01e338164914fe001") let starkPrivateKey = StarkWare.getStarkKeyFromSignature(derivationPath: derivationPath, signature: ethSignature) XCTAssertEqual(starkPrivateKey.data.hexString, "04be51a04e718c202e4dca60c2b72958252024cfc1070c090dd0f170298249de") @@ -36,7 +36,7 @@ class HDWalletTests: XCTestCase { // Account Register let ethMsgToRegister = "Only sign this key linking request from Immutable X" - let ethSignatureToRegister = EthereumMessageSigner.signMessage(privateKey: ethPrivateKey, message: ethMsgToRegister) + let ethSignatureToRegister = EthereumMessageSigner.signMessageImmutableX(privateKey: ethPrivateKey, message: ethMsgToRegister) XCTAssertEqual(ethSignatureToRegister, "646da4160f7fc9205e6f502fb7691a0bf63ecbb74bbb653465cd62388dd9f56325ab1e4a9aba99b1661e3e6251b42822855a71e60017b310b9f90e990a12e1dc01") let starkMsg = "463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf" let starkSignature = StarkExMessageSigner.signMessage(privateKey: starkPrivateKey, message: starkMsg) diff --git a/tests/chains/Ethereum/EIP1014Tests.cpp b/tests/chains/Ethereum/EIP1014Tests.cpp index 2a9e38864bd..dab96107ebc 100644 --- a/tests/chains/Ethereum/EIP1014Tests.cpp +++ b/tests/chains/Ethereum/EIP1014Tests.cpp @@ -60,19 +60,21 @@ namespace TW::Ethereum::tests { TEST(EthereumEip1014, Example2) { const std::string& from = "0xdeadbeef00000000000000000000000000000000"; const Data salt = parse_hex("0x000000000000000000000000feed000000000000000000000000000000000000"); - Data initCodeHash = Hash::keccak256(parse_hex("0x00")); - const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); - ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0xD04116cDd17beBE565EB2422F2497E06cC1C9833"); - ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0xD04116cDd17beBE565EB2422F2497E06cC1C9833"); + Data initCode = parse_hex("0x00"); + initCode.resize(32); + const auto& addressData = Ethereum::create2Address(from, salt, initCode); + ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x2DB27D1d6BE32C9abfA484BA3d591101881D4B9f"); + ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCode), "0x2DB27D1d6BE32C9abfA484BA3d591101881D4B9f"); } TEST(EthereumEip1014, Example3) { const std::string& from = "0x0000000000000000000000000000000000000000"; const Data salt = parse_hex("0x0000000000000000000000000000000000000000000000000000000000000000"); - Data initCodeHash = Hash::keccak256(parse_hex("0xdeadbeef")); - const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); - ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x70f2b2914A2a4b783FaEFb75f459A580616Fcb5e"); - ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0x70f2b2914A2a4b783FaEFb75f459A580616Fcb5e"); + Data initCode = parse_hex("0xdeadbeef"); + initCode.resize(32); + const auto& addressData = Ethereum::create2Address(from, salt, initCode); + ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x219438aC82230Cb9A9C13Cd99D324fA1d66CF018"); + ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCode), "0x219438aC82230Cb9A9C13Cd99D324fA1d66CF018"); } TEST(EthereumEip1014, Example4) { @@ -101,7 +103,7 @@ namespace TW::Ethereum::tests { ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0"); ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0"); } - + TEST(EthereumEip1014, Example7) { const std::string& from = "0x7EF2e0048f5bAeDe046f6BF797943daF4ED8CB47"; const Data salt = parse_hex("0x0000000000000000000000000000000000000000000000000000000000000000"); diff --git a/tests/chains/Ethereum/EIP191Tests.cpp b/tests/chains/Ethereum/EIP191Tests.cpp deleted file mode 100644 index 38c937479d1..00000000000 --- a/tests/chains/Ethereum/EIP191Tests.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright © 2017-2022 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -#include -#include -#include -#include -#include -#include "TestUtilities.h" - -#include - -namespace TW::Ethereum { - TEST(EthereumEip191, signMessageAndVerify) { - PrivateKey ethKey(parse_hex("3b0a61f46fdae924007146eacb6db6642de7a5603ad843ec58e10331d89d4b84")); - auto msg = "Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3"; - auto signature = Ethereum::MessageSigner::signMessage(ethKey, msg); - ASSERT_EQ(signature, "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01"); - auto pubKey = ethKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended); - ASSERT_TRUE(Ethereum::MessageSigner::verifyMessage(pubKey, msg, signature)); - } - - TEST(TWEthereumMessageSigner, SignAndVerify) { - const auto privKeyData = "3b0a61f46fdae924007146eacb6db6642de7a5603ad843ec58e10331d89d4b84"; - const auto privateKey = WRAP(TWPrivateKey, TWPrivateKeyCreateWithData(DATA(privKeyData).get())); - const auto message = STRING("Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3"); - - const auto pubKey = TWPrivateKeyGetPublicKey(privateKey.get(), TWCoinTypeEthereum); - const auto signature = WRAPS(TWEthereumMessageSignerSignMessage(privateKey.get(), message.get())); - EXPECT_EQ(std::string(TWStringUTF8Bytes(signature.get())), "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01"); - EXPECT_TRUE(TWEthereumMessageSignerVerifyMessage(pubKey, message.get(), signature.get())); - delete pubKey; - } -} diff --git a/tests/chains/Ethereum/EthereumMessageSignerTests.cpp b/tests/chains/Ethereum/EthereumMessageSignerTests.cpp new file mode 100644 index 00000000000..2c818921e86 --- /dev/null +++ b/tests/chains/Ethereum/EthereumMessageSignerTests.cpp @@ -0,0 +1,246 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "TestUtilities.h" +#include +#include +#include +#include +#include + +#include + +namespace TW::Ethereum { + TEST(EthereumEip712, SignMessageAndVerifyLegacy) { + PrivateKey ethKey(parse_hex("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d")); + auto msg = R"( + { + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Person": [ + {"name": "name", "type": "string"}, + {"name": "wallet", "type": "address"} + ] + }, + "primaryType": "Person", + "domain": { + "name": "Ether Person", + "version": "1", + "chainId": 0, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "name": "Cow", + "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + } + })"; + auto signature = Ethereum::MessageSigner::signTypedData(ethKey, msg, MessageType::Legacy); + ASSERT_EQ(signature, "446434e4c34d6b7456e5f07a1b994b88bf85c057234c68d1e10c936b1c85706c4e19147c0ac3a983bc2d56ebfd7146f8b62bcea6114900fe8e7d7351f44bf3761c"); + auto pubKey = ethKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended); + ASSERT_TRUE(Ethereum::MessageSigner::verifyMessage(pubKey, msg, signature)); + } + + TEST(EthereumEip712, SignMessageAndVerifyEip155) { + PrivateKey ethKey(parse_hex("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d")); + auto msg = R"( + { + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Person": [ + {"name": "name", "type": "string"}, + {"name": "wallet", "type": "address"} + ] + }, + "primaryType": "Person", + "domain": { + "name": "Ether Person", + "version": "1", + "chainId": 0, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "name": "Cow", + "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + } + })"; + auto signature = Ethereum::MessageSigner::signTypedData(ethKey, msg, MessageType::Eip155, 0); + ASSERT_EQ(signature, "446434e4c34d6b7456e5f07a1b994b88bf85c057234c68d1e10c936b1c85706c4e19147c0ac3a983bc2d56ebfd7146f8b62bcea6114900fe8e7d7351f44bf37624"); + auto pubKey = ethKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended); + ASSERT_TRUE(Ethereum::MessageSigner::verifyMessage(pubKey, msg, signature)); + } + + TEST(EthereumEip712, SignMessageAndVerifyInvalidEip155) { + PrivateKey ethKey(parse_hex("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d")); + auto msg = R"( + { + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Person": [ + {"name": "name", "type": "string"}, + {"name": "wallet", "type": "address"} + ] + }, + "primaryType": "Person", + "domain": { + "name": "Ether Person", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "name": "Cow", + "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + } + })"; + auto signature = Ethereum::MessageSigner::signTypedData(ethKey, msg, MessageType::Eip155, 0); + ASSERT_EQ(signature, "EIP712 chainId is different than the current chainID."); + } + + TEST(EthereumEip191, SignMessageAndVerifyLegacy) { + PrivateKey ethKey(parse_hex("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d")); + auto msg = "Foo"; + auto signature = Ethereum::MessageSigner::signMessage(ethKey, msg, MessageType::Legacy); + ASSERT_EQ(signature, "21a779d499957e7fd39392d49a079679009e60e492d9654a148829be43d2490736ec72bc4a5644047d979c3cf4ebe2c1c514044cf436b063cb89fc6676be71101b"); + auto pubKey = ethKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended); + ASSERT_TRUE(Ethereum::MessageSigner::verifyMessage(pubKey, msg, signature)); + } + + TEST(EthereumEip191, SignMessageAndVerifyEip155) { + PrivateKey ethKey(parse_hex("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d")); + auto msg = "Foo"; + auto signature = Ethereum::MessageSigner::signMessage(ethKey, msg, MessageType::Eip155, 0); + ASSERT_EQ(signature, "21a779d499957e7fd39392d49a079679009e60e492d9654a148829be43d2490736ec72bc4a5644047d979c3cf4ebe2c1c514044cf436b063cb89fc6676be711023"); + auto pubKey = ethKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended); + ASSERT_TRUE(Ethereum::MessageSigner::verifyMessage(pubKey, msg, signature)); + } + + TEST(EthereumEip191, SignMessageAndVerifyImmutableX) { + PrivateKey ethKey(parse_hex("3b0a61f46fdae924007146eacb6db6642de7a5603ad843ec58e10331d89d4b84")); + auto msg = "Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3"; + auto signature = Ethereum::MessageSigner::signMessage(ethKey, msg, MessageType::ImmutableX); + ASSERT_EQ(signature, "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01"); + auto pubKey = ethKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended); + ASSERT_TRUE(Ethereum::MessageSigner::verifyMessage(pubKey, msg, signature)); + } + + TEST(TWEthereumMessageSigner, SignAndVerifyImmutableX) { + const auto privKeyData = "3b0a61f46fdae924007146eacb6db6642de7a5603ad843ec58e10331d89d4b84"; + const auto privateKey = WRAP(TWPrivateKey, TWPrivateKeyCreateWithData(DATA(privKeyData).get())); + const auto message = STRING("Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3"); + + const auto pubKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKey(privateKey.get(), TWCoinTypeEthereum)); + const auto signature = WRAPS(TWEthereumMessageSignerSignMessageImmutableX(privateKey.get(), message.get())); + EXPECT_EQ(std::string(TWStringUTF8Bytes(signature.get())), "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01"); + EXPECT_TRUE(TWEthereumMessageSignerVerifyMessage(pubKey.get(), message.get(), signature.get())); + } + + TEST(TWEthereumMessageSigner, SignAndVerifyLegacy) { + const auto privKeyData = "03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d"; + const auto privateKey = WRAP(TWPrivateKey, TWPrivateKeyCreateWithData(DATA(privKeyData).get())); + const auto message = STRING("Foo"); + + const auto pubKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKey(privateKey.get(), TWCoinTypeEthereum)); + const auto signature = WRAPS(TWEthereumMessageSignerSignMessage(privateKey.get(), message.get())); + EXPECT_EQ(std::string(TWStringUTF8Bytes(signature.get())), "21a779d499957e7fd39392d49a079679009e60e492d9654a148829be43d2490736ec72bc4a5644047d979c3cf4ebe2c1c514044cf436b063cb89fc6676be71101b"); + EXPECT_TRUE(TWEthereumMessageSignerVerifyMessage(pubKey.get(), message.get(), signature.get())); + } + + TEST(TWEthereumMessageSigner, SignAndVerifyEip155) { + const auto privKeyData = "03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d"; + const auto privateKey = WRAP(TWPrivateKey, TWPrivateKeyCreateWithData(DATA(privKeyData).get())); + const auto message = STRING("Foo"); + + const auto pubKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKey(privateKey.get(), TWCoinTypeEthereum)); + const auto signature = WRAPS(TWEthereumMessageSignerSignMessageEip155(privateKey.get(), message.get(), 0)); + EXPECT_EQ(std::string(TWStringUTF8Bytes(signature.get())), "21a779d499957e7fd39392d49a079679009e60e492d9654a148829be43d2490736ec72bc4a5644047d979c3cf4ebe2c1c514044cf436b063cb89fc6676be711023"); + EXPECT_TRUE(TWEthereumMessageSignerVerifyMessage(pubKey.get(), message.get(), signature.get())); + } + + TEST(TWEthereumEip712, SignMessageAndVerifyLegacy) { + const auto privKeyData = "03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d"; + const auto privateKey = WRAP(TWPrivateKey, TWPrivateKeyCreateWithData(DATA(privKeyData).get())); + auto msg = STRING(R"( + { + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Person": [ + {"name": "name", "type": "string"}, + {"name": "wallet", "type": "address"} + ] + }, + "primaryType": "Person", + "domain": { + "name": "Ether Person", + "version": "1", + "chainId": 0, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "name": "Cow", + "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + } + })"); + const auto pubKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKey(privateKey.get(), TWCoinTypeEthereum)); + const auto signature = WRAPS(TWEthereumMessageSignerSignTypedMessage(privateKey.get(), msg.get())); + EXPECT_EQ(std::string(TWStringUTF8Bytes(signature.get())), "446434e4c34d6b7456e5f07a1b994b88bf85c057234c68d1e10c936b1c85706c4e19147c0ac3a983bc2d56ebfd7146f8b62bcea6114900fe8e7d7351f44bf3761c"); + EXPECT_TRUE(TWEthereumMessageSignerVerifyMessage(pubKey.get(), msg.get(), signature.get())); + } + + TEST(TWEthereumEip712, SignMessageAndVerifyEip155) { + const auto privKeyData = "03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d"; + const auto privateKey = WRAP(TWPrivateKey, TWPrivateKeyCreateWithData(DATA(privKeyData).get())); + auto msg = STRING(R"( + { + "types": { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"} + ], + "Person": [ + {"name": "name", "type": "string"}, + {"name": "wallet", "type": "address"} + ] + }, + "primaryType": "Person", + "domain": { + "name": "Ether Person", + "version": "1", + "chainId": 0, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "name": "Cow", + "wallet": "CD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + } + })"); + const auto pubKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKey(privateKey.get(), TWCoinTypeEthereum)); + const auto signature = WRAPS(TWEthereumMessageSignerSignTypedMessageEip155(privateKey.get(), msg.get(), 0)); + EXPECT_EQ(std::string(TWStringUTF8Bytes(signature.get())), "446434e4c34d6b7456e5f07a1b994b88bf85c057234c68d1e10c936b1c85706c4e19147c0ac3a983bc2d56ebfd7146f8b62bcea6114900fe8e7d7351f44bf37624"); + EXPECT_TRUE(TWEthereumMessageSignerVerifyMessage(pubKey.get(), msg.get(), signature.get())); + } +} diff --git a/tests/chains/Ethereum/SignerTests.cpp b/tests/chains/Ethereum/SignerTests.cpp index cbb9fb38e91..bb938626569 100644 --- a/tests/chains/Ethereum/SignerTests.cpp +++ b/tests/chains/Ethereum/SignerTests.cpp @@ -5,9 +5,9 @@ // file LICENSE at the root of the source code distribution tree. #include "Ethereum/Address.h" +#include "Ethereum/MessageSigner.h" #include "Ethereum/RLP.h" #include "Ethereum/Signer.h" -#include "Ethereum/EIP191.h" #include "Ethereum/Transaction.h" #include "HexCoding.h" diff --git a/tests/common/HDWallet/HDWalletTests.cpp b/tests/common/HDWallet/HDWalletTests.cpp index f783dffb7e1..c5f858bbc04 100644 --- a/tests/common/HDWallet/HDWalletTests.cpp +++ b/tests/common/HDWallet/HDWalletTests.cpp @@ -10,9 +10,9 @@ #include "Bitcoin/SegwitAddress.h" #include "Coin.h" #include "Ethereum/Address.h" -#include "Ethereum/Signer.h" -#include "Ethereum/EIP191.h" #include "Ethereum/EIP2645.h" +#include "Ethereum/MessageSigner.h" +#include "Ethereum/Signer.h" #include "HDWallet.h" #include "Hash.h" #include "Hedera/DER.h" @@ -21,8 +21,8 @@ #include "Mnemonic.h" #include "NEAR/Address.h" #include "PublicKey.h" -#include "TestUtilities.h" #include "StarkEx/MessageSigner.h" +#include "TestUtilities.h" #include @@ -544,7 +544,7 @@ TEST(HDWallet, FromMnemonicImmutableXMainnet) { ASSERT_EQ(ethAddressFromPub, ethAddress); std::string tosign = "Only sign this request if you’ve initiated an action with Immutable X.\n\nFor internal use:\nbd717ba31dca6e0f3f136f7c4197babce5f09a9f25176044c0b3112b1b6017a3"; - auto hexEthSignature = Ethereum::MessageSigner::signMessage(ethPrivKey, tosign); + auto hexEthSignature = Ethereum::MessageSigner::signMessage(ethPrivKey, tosign, Ethereum::MessageType::ImmutableX); ASSERT_EQ(hexEthSignature, "32cd5a58f3419fc5db672e3d57f76199b853eda0856d491b38f557b629b0a0814ace689412bf354a1af81126d2749207dffae8ae8845160f33948a6b787e17ee01"); } @@ -577,13 +577,13 @@ TEST(HDWallet, FromMnemonicImmutableXMainnetFromSignature) { ASSERT_EQ(hex(ethPrivKey.bytes), "03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d"); auto ethAddressFromPub = Ethereum::Address(ethPrivKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended)).string(); ASSERT_EQ(ethAddressFromPub, ethAddress); - auto signature = Ethereum::MessageSigner::signMessage(ethPrivKey, "Only sign this request if you’ve initiated an action with Immutable X."); + auto signature = Ethereum::MessageSigner::signMessage(ethPrivKey, "Only sign this request if you’ve initiated an action with Immutable X.", Ethereum::MessageType::ImmutableX); ASSERT_EQ(signature, "18b1be8b78807d3326e28bc286d7ee3d068dcd90b1949ce1d25c1f99825f26e70992c5eb7f44f76b202aceded00d74f771ed751f2fe538eec01e338164914fe001"); auto starkPrivKey = ImmutableX::getPrivateKeyFromRawSignature(parse_hex(signature), DerivationPath(derivationPath)); auto starkPubKey = starkPrivKey.getPublicKey(TWPublicKeyTypeStarkex); ASSERT_EQ(hex(starkPrivKey.bytes), "04be51a04e718c202e4dca60c2b72958252024cfc1070c090dd0f170298249de"); ASSERT_EQ(hex(starkPubKey.bytes), "00e5b9b11f8372610ef35d647a1dcaba1a4010716588d591189b27bf3c2d5095"); - auto signatureToSend = Ethereum::MessageSigner::signMessage(ethPrivKey, "Only sign this key linking request from Immutable X"); + auto signatureToSend = Ethereum::MessageSigner::signMessage(ethPrivKey, "Only sign this key linking request from Immutable X", Ethereum::MessageType::ImmutableX); ASSERT_EQ(signatureToSend, "646da4160f7fc9205e6f502fb7691a0bf63ecbb74bbb653465cd62388dd9f56325ab1e4a9aba99b1661e3e6251b42822855a71e60017b310b9f90e990a12e1dc01"); auto starkMsg = "463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf"; diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp index f97644e1ad5..a73b5f44bff 100644 --- a/tests/interface/TWHDWalletTests.cpp +++ b/tests/interface/TWHDWalletTests.cpp @@ -524,7 +524,7 @@ TEST(TWHDWallet, FromMnemonicImmutableXMainnetFromSignature) { // Retrieve Stark Private key part const auto ethMsg = STRING("Only sign this request if you’ve initiated an action with Immutable X."); - const auto ethSignature = WRAPS(TWEthereumMessageSignerSignMessage(ethPrivateKey.get(), ethMsg.get())); + const auto ethSignature = WRAPS(TWEthereumMessageSignerSignMessageImmutableX(ethPrivateKey.get(), ethMsg.get())); assertStringsEqual(ethSignature, "18b1be8b78807d3326e28bc286d7ee3d068dcd90b1949ce1d25c1f99825f26e70992c5eb7f44f76b202aceded00d74f771ed751f2fe538eec01e338164914fe001"); const auto starkPrivateKey = WRAP(TWPrivateKey, TWStarkWareGetStarkKeyFromSignature(starkDerivationPath.get(), ethSignature.get())); const auto starkPrivateKeyData = WRAPD(TWPrivateKeyData(starkPrivateKey.get())); @@ -535,7 +535,7 @@ TEST(TWHDWallet, FromMnemonicImmutableXMainnetFromSignature) { // Account register const auto ethMsgToRegister = STRING("Only sign this key linking request from Immutable X"); - const auto ethSignatureToRegister = WRAPS(TWEthereumMessageSignerSignMessage(ethPrivateKey.get(), ethMsgToRegister.get())); + const auto ethSignatureToRegister = WRAPS(TWEthereumMessageSignerSignMessageImmutableX(ethPrivateKey.get(), ethMsgToRegister.get())); assertStringsEqual(ethSignatureToRegister, "646da4160f7fc9205e6f502fb7691a0bf63ecbb74bbb653465cd62388dd9f56325ab1e4a9aba99b1661e3e6251b42822855a71e60017b310b9f90e990a12e1dc01"); const auto starkMsg = STRING("463a2240432264a3aa71a5713f2a4e4c1b9e12bbb56083cd56af6d878217cf"); const auto starkSignature = WRAPS(TWStarkExMessageSignerSignMessage(starkPrivateKey.get(), starkMsg.get())); From 1709e798b68a93fb0ed311a9fc97ef21ba7eebc4 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 25 Jan 2023 16:36:11 +0100 Subject: [PATCH 178/497] feat(aptos): aptos tx fix pancake swap (#2888) --- rust/src/move_parser/mod.rs | 11 +++++++- .../chains/Aptos/TransactionPayloadTests.cpp | 28 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/rust/src/move_parser/mod.rs b/rust/src/move_parser/mod.rs index ba788b5b042..2df6a089556 100644 --- a/rust/src/move_parser/mod.rs +++ b/rust/src/move_parser/mod.rs @@ -57,7 +57,7 @@ pub extern fn parse_function_argument_to_bcs(input: *const c_char) -> *const c_c TransactionArgument::U8(v) => hex::encode(bcs::to_bytes(&v).unwrap()), TransactionArgument::U64(v) => hex::encode(bcs::to_bytes(&v).unwrap()), TransactionArgument::U128(v) => hex::encode(bcs::to_bytes(&v).unwrap()), - TransactionArgument::Address(v) => hex::encode(bcs::to_bytes(&v).unwrap()), + TransactionArgument::Address(v) => hex::encode(bcs::to_bytes(&bcs::to_bytes(&v).unwrap()).unwrap()), TransactionArgument::U8Vector(v) => hex::encode(bcs::to_bytes(&v).unwrap()), TransactionArgument::Bool(v) => hex::encode(bcs::to_bytes(&v).unwrap()), }; @@ -84,4 +84,13 @@ mod tests { let str = unsafe { CStr::from_ptr(parse_function_argument_to_bcs("5047445908\0".as_ptr() as *const c_char)).to_str().unwrap() }; assert_eq!(str, "94e9d92c01000000"); } + + #[test] + fn tests_function_argument_to_bcs_another() { + let str = unsafe { CStr::from_ptr(parse_function_argument_to_bcs("0xc95db29a67a848940829b3df6119b5e67b788ff0248676e4484c7c6f29c0f5e6\0".as_ptr() as *const c_char)).to_str().unwrap() }; + let decoded = hex::decode(str).unwrap(); + let v = vec![decoded]; + let t = hex::encode(bcs::to_bytes(&v).unwrap()); + assert_eq!(t, "012120c95db29a67a848940829b3df6119b5e67b788ff0248676e4484c7c6f29c0f5e6"); + } } diff --git a/tests/chains/Aptos/TransactionPayloadTests.cpp b/tests/chains/Aptos/TransactionPayloadTests.cpp index ed393963a06..4e8203e07bb 100644 --- a/tests/chains/Aptos/TransactionPayloadTests.cpp +++ b/tests/chains/Aptos/TransactionPayloadTests.cpp @@ -10,6 +10,34 @@ namespace TW::Aptos::tests { +TEST(AptosTransactionPayload, PancakeSwapPayload) { + auto pancakeSwapPayload=R"( + { +"arguments": [ + "0xc95db29a67a848940829b3df6119b5e67b788ff0248676e4484c7c6f29c0f5e6" +], +"function": "0xc23c3b70956ce8d88fb18ad9ed3b463fe873cb045db3f6d2e2fb15b9aab71d50::IFO::release", +"type": "entry_function_payload", +"type_arguments": [ + "0x48e0e3958d42b8d452c9199d4a221d0d1b15d14655787453dbe77208ced90517::coins::BUSD", + "0x48e0e3958d42b8d452c9199d4a221d0d1b15d14655787453dbe77208ced90517::coins::DAI", + "0x9936836587ca33240d3d3f91844651b16cb07802faf5e34514ed6f78580deb0a::uints::U1" +] +} +)"_json; + + TransactionPayload payload = EntryFunction::from_json(pancakeSwapPayload); + BCS::Serializer serializer; + Address sender("0x2ce519d8cd60e0870e874e8000e8cbc87c8172e6acdbec83662b4c8cc3fc3de9"); + std::uint64_t sequenceNumber{75}; + std::uint64_t gasAmount{488130}; + std::uint64_t gasPrice{100}; + std::uint64_t expirationTime{199940521552}; + std::uint8_t chainId{1}; + serializer << sender << sequenceNumber << payload << gasAmount << gasPrice << expirationTime << chainId; + ASSERT_EQ(hex(serializer.bytes), "2ce519d8cd60e0870e874e8000e8cbc87c8172e6acdbec83662b4c8cc3fc3de94b0000000000000002c23c3b70956ce8d88fb18ad9ed3b463fe873cb045db3f6d2e2fb15b9aab71d500349464f0772656c65617365030748e0e3958d42b8d452c9199d4a221d0d1b15d14655787453dbe77208ced9051705636f696e730442555344000748e0e3958d42b8d452c9199d4a221d0d1b15d14655787453dbe77208ced9051705636f696e730344414900079936836587ca33240d3d3f91844651b16cb07802faf5e34514ed6f78580deb0a0575696e747302553100012120c95db29a67a848940829b3df6119b5e67b788ff0248676e4484c7c6f29c0f5e6c2720700000000006400000000000000503e628d2e00000001"); +} + TEST(AptosTransactionPayload, PayLoadBasis) { ModuleId module(Address::one(), "coin"); std::uint64_t amount{1000}; From 7772467b2f72cfe32d421c52ddd83ac853259b0f Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 27 Jan 2023 12:29:56 +0100 Subject: [PATCH 179/497] [Sui]: Add SUI Implementation (#2883) --- .../blockchains/CoinAddressDerivationTests.kt | 1 + .../app/blockchains/sui/TestSuiAddress.kt | 35 ++++++ .../core/app/blockchains/sui/TestSuiSigner.kt | 42 +++++++ docs/registry.md | 1 + include/TrustWalletCore/TWBlockchain.h | 1 + include/TrustWalletCore/TWCoinType.h | 1 + registry.json | 28 +++++ rust/Cargo.lock | 9 +- rust/Cargo.toml | 1 + rust/cbindgen.toml | 3 + rust/src/encoding/mod.rs | 115 ++++++++++++++++++ rust/src/lib.rs | 1 + src/Aptos/Address.cpp | 66 +--------- src/Aptos/Address.h | 38 ++---- src/Base64.cpp | 91 +++++--------- src/Base64.h | 2 +- src/Coin.cpp | 5 +- src/Move/Address.h | 106 ++++++++++++++++ src/Sui/Address.cpp | 24 ++++ src/Sui/Address.h | 39 ++++++ src/Sui/Entry.cpp | 26 ++++ src/Sui/Entry.h | 20 +++ src/Sui/Signer.cpp | 45 +++++++ src/Sui/Signer.h | 25 ++++ src/proto/Sui.proto | 34 ++++++ swift/Tests/Blockchains/SuiTests.swift | 40 ++++++ swift/Tests/CoinAddressDerivationTests.swift | 3 + tests/chains/Sui/AddressTests.cpp | 53 ++++++++ tests/chains/Sui/SignerTests.cpp | 65 ++++++++++ tests/chains/Sui/TWCoinTypeTests.cpp | 33 +++++ tests/common/Base64Tests.cpp | 9 ++ tests/common/CoinAddressDerivationTests.cpp | 3 + tests/common/HDWallet/HDWalletTests.cpp | 13 ++ .../common/rust/bindgen/WalletCoreRsTests.cpp | 1 - tools/install-wasm-dependencies | 2 +- walletconsole/lib/Util.cpp | 9 +- wasm/CMakeLists.txt | 2 +- wasm/tests/Blockchain/Sui.test.ts | 28 +++++ 38 files changed, 858 insertions(+), 162 deletions(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiAddress.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiSigner.kt create mode 100644 rust/cbindgen.toml create mode 100644 rust/src/encoding/mod.rs create mode 100644 src/Move/Address.h create mode 100644 src/Sui/Address.cpp create mode 100644 src/Sui/Address.h create mode 100644 src/Sui/Entry.cpp create mode 100644 src/Sui/Entry.h create mode 100644 src/Sui/Signer.cpp create mode 100644 src/Sui/Signer.h create mode 100644 src/proto/Sui.proto create mode 100644 swift/Tests/Blockchains/SuiTests.swift create mode 100644 tests/chains/Sui/AddressTests.cpp create mode 100644 tests/chains/Sui/SignerTests.cpp create mode 100644 tests/chains/Sui/TWCoinTypeTests.cpp create mode 100644 wasm/tests/Blockchain/Sui.test.ts diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index dd3b7491a5c..84ed86b221f 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -108,6 +108,7 @@ class CoinAddressDerivationTests { EVERSCALE -> assertEquals("0:0c39661089f86ec5926ea7d4ee4223d634ba4ed6dcc2e80c7b6a8e6d59f79b04", address) TON -> assertEquals("EQDgEMqToTacHic7SnvnPFmvceG5auFkCcAw0mSCvzvKUfk9", address) APTOS -> assertEquals("0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30", address) + SUI -> assertEquals("0x061ce2b2100a71bb7aa0da98998887ad82597948", address) HEDERA -> assertEquals("0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5", address) SECRET -> assertEquals("secret1f69sk5033zcdr2p2yf3xjehn7xvgdeq09d2llh", address) NATIVEINJECTIVE -> assertEquals("inj13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a", address) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiAddress.kt new file mode 100644 index 00000000000..87ae5c400e0 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiAddress.kt @@ -0,0 +1,35 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.sui + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestSuiAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val any = AnyAddress("0x061ce2b2100a71bb7aa0da98998887ad82597948", CoinType.SUI) + assertEquals(any.coin(), CoinType.SUI) + assertEquals(any.description(), "0x061ce2b2100a71bb7aa0da98998887ad82597948") + + Assert.assertFalse( + AnyAddress.isValid( + "0xMQqpqMQgCBuiPkoXfgZZsJvuzCeI1zc00z6vHJj4", + CoinType.SUI + ) + ) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiSigner.kt new file mode 100644 index 00000000000..9a5782eebd0 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/sui/TestSuiSigner.kt @@ -0,0 +1,42 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core.app.blockchains.sui + +import com.google.protobuf.ByteString +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexByteArray +import com.trustwallet.core.app.utils.toHexBytes +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.proto.Sui + +class TestSuiSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun SuiTransactionSigning() { + // Successfully broadcasted https://explorer.sui.io/transaction/rxLgxcAqgMg8gphp6eCsSGQcdZnwFYx2SRdwEhnAUC4 + val txBytes = """ + AAUCLiNiMy/EzosKCk5EZr5QQZmMVLnvAAAAAAAAACDqj/OT+1+qyLZKV4YLw8kpK3/bTZKspTUmh1pBuUfHPLb0crwkV1LQcBARaxER8XhTNJmK7wAAAAAAAAAgaQEguOdXa+m16IM536nsveakQ4u/GYJAc1fpYGGKEvgBQUP35yxF+cEL5qm153kw18dVeuYB6AMAAAAAAAAttQCskZzd41GsNuNxHYMsbbl2aS4jYjMvxM6LCgpORGa+UEGZjFS57wAAAAAAAAAg6o/zk/tfqsi2SleGC8PJKSt/202SrKU1JodaQblHxzwBAAAAAAAAAOgDAAAAAAAA + """.trimIndent() + val key = + "3823dce5288ab55dd1c00d97e91933c613417fdb282a0b8b01a7f5f5a533b266".toHexBytesInByteString() + val signDirect = Sui.SignDirect.newBuilder().setUnsignedTxMsg(txBytes).build() + val signingInput = + Sui.SigningInput.newBuilder().setSignDirectMessage(signDirect).setPrivateKey(key).build() + val result = AnySigner.sign(signingInput, CoinType.SUI, Sui.SigningOutput.parser()) + val expectedSignature = "AIYRmHDpQesfAx3iWBCMwInf3MZ56ZQGnPWNtECFjcSq0ssAgjRW6GLnFCX24tfDNjSm9gjYgoLmn1No15iFJAtqfN7sFqdcD/Z4e8I1YQlGkDMCK7EOgmydRDqfH8C9jg==" + assertEquals(result.unsignedTx, txBytes); + assertEquals(result.signature, expectedSignature) + } +} diff --git a/docs/registry.md b/docs/registry.md index 0f0784f6e60..65da87087a0 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -55,6 +55,7 @@ This list is generated from [./registry.json](../registry.json) | 607 | TON | TON | | | | 637 | Aptos | APT | | | | 714 | BNB Beacon Chain | BNB | | | +| 784 | Sui | SUI | | | | 818 | VeChain | VET | | | | 820 | Callisto | CLO | | | | 888 | NEO | NEO | | | diff --git a/include/TrustWalletCore/TWBlockchain.h b/include/TrustWalletCore/TWBlockchain.h index 4231010137d..c93bab5e2b9 100644 --- a/include/TrustWalletCore/TWBlockchain.h +++ b/include/TrustWalletCore/TWBlockchain.h @@ -57,6 +57,7 @@ enum TWBlockchain { TWBlockchainAptos = 43, // Aptos TWBlockchainHedera = 44, // Hedera TWBlockchainTheOpenNetwork = 45, + TWBlockchainSui = 46, }; TW_EXTERN_C_END diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 39b3c9bdeb0..22a3540c265 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -130,6 +130,7 @@ enum TWCoinType { TWCoinTypeNativeInjective = 10000060, TWCoinTypeAgoric = 564, TWCoinTypeTON = 607, + TWCoinTypeSui = 784, }; /// Returns the blockchain for a coin type. diff --git a/registry.json b/registry.json index 2bfa2e3ad3c..07081485815 100644 --- a/registry.json +++ b/registry.json @@ -429,6 +429,34 @@ "documentation": "https://fullnode.mainnet.aptoslabs.com/v1/spec#/" } }, + { + "id": "sui", + "name": "Sui", + "coinId": 784, + "symbol": "SUI", + "decimals": 9, + "blockchain": "Sui", + "derivation": [ + { + "path": "m/44'/784'/0'/0'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "explorer": { + "url": "https://explorer.sui.io/", + "txPath": "/transaction/", + "accountPath": "/address/", + "sampleTx": "SWRW1RoMHxnD9NeobgBoC4cXGwp2Hc511CnfWUoTBmo", + "sampleAccount": "0x62107e1afefccc7b2267ab74e332c146f5c2ca15" + }, + "info": { + "url": "https://sui.io/", + "source": "https://github.com/MystenLabs/sui", + "rpc": "https://fullnode.testnet.sui.io", + "documentation": "https://docs.sui.io/" + } + }, { "id": "cosmos", "name": "Cosmos", diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 00747873f1b..3efb0c41ea4 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -97,6 +97,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + [[package]] name = "bcs" version = "0.1.4" @@ -806,7 +812,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95540acef038bfdf3c91da323cedf0fd335f73899152cabdf407033fc7560713" dependencies = [ - "base64", + "base64 0.13.1", "ethereum-types", "hex", "serde", @@ -994,6 +1000,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" name = "wallet-core-rs" version = "0.1.0" dependencies = [ + "base64 0.21.0", "bcs", "hex", "move-core-types", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index b3a7546634b..7752a93202d 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -16,5 +16,6 @@ starknet-ff = "0.1.0" starknet-signers = "0.1.0" bcs = "0.1.4" hex = "0.4.3" +base64 = "0.21.0" [dev-dependencies] diff --git a/rust/cbindgen.toml b/rust/cbindgen.toml new file mode 100644 index 00000000000..0ccb2ad1451 --- /dev/null +++ b/rust/cbindgen.toml @@ -0,0 +1,3 @@ +# Whether to add a `#pragma once` guard +# default: doesn't emit a `#pragma once` +pragma_once = true diff --git a/rust/src/encoding/mod.rs b/rust/src/encoding/mod.rs new file mode 100644 index 00000000000..82bff00e40b --- /dev/null +++ b/rust/src/encoding/mod.rs @@ -0,0 +1,115 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +use base64::{Engine as _, engine::{general_purpose}}; +use std::ffi::{CStr, CString}; +use std::os::raw::c_char; + +#[no_mangle] +pub extern "C" fn encode_base64(data: *const u8, len: usize, is_url: bool) -> *mut c_char { + let data = unsafe { std::slice::from_raw_parts(data, len) }; + let encoded = if is_url { + general_purpose::URL_SAFE.encode(data) + } else { + general_purpose::STANDARD.encode(data) + }; + CString::new(encoded).unwrap().into_raw() +} + +#[repr(C)] +pub struct CByteArray { + data: *mut u8, + size: usize, +} + +#[no_mangle] +pub extern "C" fn decode_base64(data: *const c_char, is_url: bool) -> CByteArray { + if data.is_null() { + return CByteArray { data: std::ptr::null_mut(), size: 0 }; + } + let c_str = unsafe { CStr::from_ptr(data) }; + let str_slice = c_str.to_str().unwrap(); + let decoded = if is_url { + general_purpose::URL_SAFE + .decode(str_slice) + } else { + general_purpose::STANDARD + .decode(str_slice) + }; + let decoded = match decoded { + Ok(decoded) => decoded, + Err(_) => return CByteArray { data: std::ptr::null_mut(), size: 0 } + }; + let size = decoded.len(); + let mut decoded_vec = decoded.to_vec(); + let ptr = decoded_vec.as_mut_ptr(); + std::mem::forget(decoded_vec); + CByteArray { data: ptr, size } +} + + +#[cfg(test)] +mod tests { + use std::ffi::CString; + use crate::encoding::{decode_base64, encode_base64}; + + #[test] + fn test_encode_base64_ffi() { + let data = b"hello world"; + let encoded = unsafe { + std::ffi::CStr::from_ptr(encode_base64(data.as_ptr(), data.len(), false)) + }; + let expected = "aGVsbG8gd29ybGQ="; + assert_eq!(encoded.to_str().unwrap(), expected); + } + + #[test] + fn test_encode_base64_url_ffi() { + let data = b"+'?ab"; + let encoded = unsafe { + std::ffi::CStr::from_ptr(encode_base64(data.as_ptr(), data.len(), true)) + }; + let expected = "Kyc_YWI="; + assert_eq!(encoded.to_str().unwrap(), expected); + } + + #[test] + fn test_decode_base64_url() { + let encoded = "Kyc_YWI="; + let expected = b"+'?ab"; + + let encoded_c_str = CString::new(encoded).unwrap(); + let encoded_ptr = encoded_c_str.as_ptr(); + + let decoded_ptr = decode_base64(encoded_ptr, true); + let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; + + assert_eq!(decoded_slice, expected); + } + + #[test] + fn test_decode_base64() { + let encoded = "aGVsbG8gd29ybGQh"; + let expected = b"hello world!"; + + let encoded_c_str = CString::new(encoded).unwrap(); + let encoded_ptr = encoded_c_str.as_ptr(); + + let decoded_ptr = decode_base64(encoded_ptr, false); + let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; + + assert_eq!(decoded_slice, expected); + } + + #[test] + fn test_decode_base64_invalid() { + let invalid_encoded = "_This_is_an_invalid_base64_"; + let encoded_c_str = CString::new(invalid_encoded).unwrap(); + let encoded_ptr = encoded_c_str.as_ptr(); + let decoded_ptr = decode_base64(encoded_ptr, false); + assert_eq!(decoded_ptr.data.is_null(), true); + } +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 01bae1bc0ae..e0efd13f8a2 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -7,3 +7,4 @@ pub mod move_parser; pub mod memory; pub mod starknet; +pub mod encoding; diff --git a/src/Aptos/Address.cpp b/src/Aptos/Address.cpp index 30c1b587872..2688e58c279 100644 --- a/src/Aptos/Address.cpp +++ b/src/Aptos/Address.cpp @@ -8,76 +8,18 @@ #include "Address.h" #include "HexCoding.h" -namespace { - -std::string normalize(const std::string& string, std::size_t hexLen) { - std::string hexStr((TW::Aptos::Address::size * 2) - hexLen, '0'); - hexStr.append(string); - return hexStr; -} - -} // namespace - namespace TW::Aptos { -bool Address::isValid(const std::string& string) { - auto address = string; - if (address.starts_with("0x")) { - address = address.substr(2); - if (std::size_t hexLen = address.size(); hexLen < Address::size * 2) { - address = normalize(address, hexLen); - } - } - if (address.size() != 2 * Address::size) { - return false; - } - const auto data = parse_hex(address); - return isValid(data); +Address::Address(const std::string& string) : Address::AptosAddress(string) { } -Address::Address(const std::string& string) { - if (!isValid(string)) { - throw std::invalid_argument("Invalid address string"); - } - auto hexFunctor = [&string]() { - if (std::size_t hexLen = string.size() - 2; string.starts_with("0x") && hexLen < Address::size * 2) { - //! We have specific address like 0x1, padding it. - return parse_hex(normalize(string.substr(2), hexLen)); - } else { - return parse_hex(string); - } - }; - - const auto data = hexFunctor(); - std::copy(data.begin(), data.end(), bytes.begin()); +Address::Address(const PublicKey& publicKey): Address::AptosAddress(publicKey) { } -Address::Address(const Data& data) { - if (!isValid(data)) { - throw std::invalid_argument("Invalid address data"); - } - std::copy(data.begin(), data.end(), bytes.begin()); -} - -Address::Address(const PublicKey& publicKey) { - if (publicKey.type != TWPublicKeyTypeED25519) { - throw std::invalid_argument("Invalid public key type"); - } +Data Address::getDigest(const PublicKey& publicKey) { auto key_data = publicKey.bytes; append(key_data, 0x00); - const auto data = Hash::sha3_256(key_data); - std::copy(data.begin(), data.end(), bytes.begin()); -} - -std::string Address::string(bool withPrefix) const { - std::string output = withPrefix ? "0x" : ""; - return output + hex(bytes); -} - -std::string Address::shortString() const { - std::string s = hex(bytes); - s.erase(0, s.find_first_not_of('0')); - return s; + return key_data; } BCS::Serializer& operator<<(BCS::Serializer& stream, Address addr) noexcept { diff --git a/src/Aptos/Address.h b/src/Aptos/Address.h index 328c387edf4..0e372a88e93 100644 --- a/src/Aptos/Address.h +++ b/src/Aptos/Address.h @@ -9,53 +9,29 @@ #include "BCS.h" #include "Data.h" -#include "../PublicKey.h" +#include "Move/Address.h" +#include "PublicKey.h" #include namespace TW::Aptos { -class Address { +class Address : public Move::Address { public: - static constexpr size_t size = 32; - - std::array bytes; - - /// Determines whether a collection of bytes makes a valid address. - static bool isValid(const Data& data) { return data.size() == size; } - - /// Determines whether a string makes a valid address. - static bool isValid(const std::string& string); - - static Address zero() { - return Address("0x0"); - } - - static Address one() { - return Address("0x1"); - } - - static Address three() { - return Address("0x3"); - } + using AptosAddress = Move::Address; + using AptosAddress::size; + using AptosAddress::bytes; /// Initializes an Aptos address with a string representation. explicit Address(const std::string& string); - /// Initializes an Aptos address with a collection of bytes - explicit Address(const Data& data); - /// Initializes an Aptos address with a public key. explicit Address(const PublicKey& publicKey); /// Constructor that allow factory programming; Address() noexcept = default; - /// Returns a string representation of the address. - [[nodiscard]] std::string string(bool withPrefix = true) const; - - /// Returns a short string representation of the address. E.G 0x1; - [[nodiscard]] std::string shortString() const; + Data getDigest(const PublicKey& publicKey); }; constexpr inline bool operator==(const Address& lhs, const Address& rhs) noexcept { diff --git a/src/Base64.cpp b/src/Base64.cpp index edb5db03998..a09f399e3c7 100644 --- a/src/Base64.cpp +++ b/src/Base64.cpp @@ -1,15 +1,35 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. #include "Base64.h" +#include "rust/bindgen/WalletCoreRSBindgen.h" -#include -#include -#include -#include +namespace TW::Base64::internal { + +std::string encode(const Data& val, bool is_url) { + char* encoded = encode_base64(val.data(), val.size(), is_url); + std::string encoded_str(encoded); + free_string(encoded); + return encoded_str; +} + +Data decode(const std::string& val, bool is_url) { + if (val.empty()) { + return Data(); + } + auto decoded = decode_base64(val.c_str(), is_url); + if (decoded.data == nullptr) { + return Data(); + } + std::vector decoded_vec(&decoded.data[0], &decoded.data[decoded.size]); + std::free(decoded.data); + return decoded_vec; +} + +} namespace TW::Base64 { @@ -36,65 +56,20 @@ bool isBase64orBase64Url(const string& val) { return isBase64Any(val, base64_chars) || isBase64Any(val, base64_url_chars); } -Data decode(const string& val) { - using namespace boost::archive::iterators; - using It = transform_width, 8, 6>; - return boost::algorithm::trim_right_copy_if(Data(It(begin(val)), It(end(val))), - [](char c) { return c == '\0'; }); -} - -string encode(const Data& val) { - using namespace boost::archive::iterators; - using It = base64_from_binary>; - auto encoded = string(It(begin(val)), It(end(val))); - return encoded.append((3 - val.size() % 3) % 3, '='); -} - -/// Convert from Base64Url format to regular -void convertFromBase64Url(string& b) { - // '-' and '_' (Base64URL format) are changed to '+' and '/' - // in-place replace - size_t n = b.length(); - char* start = b.data(); - char* end = start + n; - for (auto* p = start; p < end; ++p) { - if (*p == '-') { - *p = '+'; - } else if (*p == '_') { - *p = '/'; - } - } +Data decodeBase64Url(const string& val) { + return internal::decode(val, true); } -/// Convert from regular format to Base64Url -void convertToBase64Url(string& b) { - // '+' and '/' are changed to '-' and '_' (Base64URL format) - // in-place replace - size_t n = b.length(); - char* start = b.data(); - char* end = start + n; - for (auto* p = start; p < end; ++p) { - if (*p == '+') { - *p = '-'; - } else if (*p == '/') { - *p = '_'; - } - } +string encodeBase64Url(const Data& val) { + return internal::encode(val, true); } -Data decodeBase64Url(const string& val) { - string base64Url = val; - convertFromBase64Url(base64Url); - return decode(base64Url); +std::string encode(const Data& val) { + return internal::encode(val, false); } -string encodeBase64Url(const Data& val) { - using namespace boost::archive::iterators; - using It = base64_from_binary>; - auto encoded = string(It(begin(val)), It(end(val))); - encoded.append((3 - val.size() % 3) % 3, '='); - convertToBase64Url(encoded); - return encoded; +Data decode(const string& val) { + return internal::decode(val, false); } } // namespace TW::Base64 diff --git a/src/Base64.h b/src/Base64.h index 8ea6f74356b..eacd9e147a5 100644 --- a/src/Base64.h +++ b/src/Base64.h @@ -17,7 +17,7 @@ bool isBase64orBase64Url(const std::string& val); Data decode(const std::string& val); // Encode bytes into Base64 string -std::string encode(const Data& val); +std::string encode(const TW::Data& val); // Decode a Base64Url-format or a regular Base64 string. // Base64Url format uses '-' and '_' as the two special characters, Base64 uses '+'and '/'. diff --git a/src/Coin.cpp b/src/Coin.cpp index 521db9fb0a8..167fb0026b2 100644 --- a/src/Coin.cpp +++ b/src/Coin.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2022 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -57,6 +57,7 @@ #include "Zilliqa/Entry.h" #include "Hedera/Entry.h" #include "TheOpenNetwork/Entry.h" +#include "Sui/Entry.h" // end_of_coin_includes_marker_do_not_modify using namespace TW; @@ -107,6 +108,7 @@ Nervos::Entry NervosDP; Everscale::Entry EverscaleDP; Hedera::Entry HederaDP; TheOpenNetwork::Entry tonDP; +Sui::Entry SuiDP; // end_of_coin_dipatcher_declarations_marker_do_not_modify CoinEntry* coinDispatcher(TWCoinType coinType) { @@ -159,6 +161,7 @@ CoinEntry* coinDispatcher(TWCoinType coinType) { case TWBlockchainAptos: entry = &AptosDP; break; case TWBlockchainHedera: entry = &HederaDP; break; case TWBlockchainTheOpenNetwork: entry = &tonDP; break; + case TWBlockchainSui: entry = &SuiDP; break; // end_of_coin_dipatcher_switch_marker_do_not_modify default: entry = nullptr; break; diff --git a/src/Move/Address.h b/src/Move/Address.h new file mode 100644 index 00000000000..216f1d209d6 --- /dev/null +++ b/src/Move/Address.h @@ -0,0 +1,106 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" +#include "HexCoding.h" +#include "PublicKey.h" +#include + +namespace TW::Move { +template +class Address { +private: + static std::string normalize(const std::string& string, std::size_t hexLen) { + std::string hexStr((size * 2) - hexLen, '0'); + hexStr.append(string); + return hexStr; + } + + /// Determines whether a collection of bytes makes a valid address. + static bool isValid(const Data& data) { return data.size() == size; } +public: + static constexpr int size = N; + std::array bytes; + + /// Determines whether a string makes a valid address. + static bool isValid(const std::string& string) { + auto address = string; + if (address.starts_with("0x")) { + address = address.substr(2); + if (std::size_t hexLen = address.size(); hexLen < Address::size * 2) { + address = normalize(address, hexLen); + } + } + if (address.size() != 2 * Address::size) { + return false; + } + const auto data = parse_hex(address); + return isValid(data); + }; + + Address() noexcept = default; + + Address(const std::string& string) { + if (!isValid(string)) { + throw std::invalid_argument("Invalid address string"); + } + auto hexFunctor = [&string]() { + if (std::size_t hexLen = string.size() - 2; string.starts_with("0x") && hexLen < size * 2) { + //! We have specific address like 0x1, padding it. + return parse_hex(normalize(string.substr(2), hexLen)); + } else { + return parse_hex(string); + } + }; + + const auto data = hexFunctor(); + std::copy(data.begin(), data.end(), bytes.begin()); + } + + Address(const Data& data) { + if (!isValid(data)) { + throw std::invalid_argument("Invalid address data"); + } + std::copy_n(data.begin(), size, bytes.begin()); + } + + Address(const PublicKey& publicKey) { + if (publicKey.type != TWPublicKeyTypeED25519) { + throw std::invalid_argument("Invalid public key type"); + } + auto digest = static_cast(this)->getDigest(publicKey); + const auto data = Hash::sha3_256(digest); + std::copy_n(data.begin(), Address::size, bytes.begin()); + } + + static Derived zero() { + return Derived("0x0"); + } + + static Derived one() { + return Derived("0x1"); + } + + static Derived three() { + return Derived("0x3"); + } + + /// Returns a string representation of the address. + [[nodiscard]] std::string string(bool withPrefix = true) const { + std::string output = withPrefix ? "0x" : ""; + return output + hex(bytes); + }; + + /// Returns a short string representation of the address. E.G 0x1; + [[nodiscard]] std::string shortString() const { + std::string s = hex(bytes); + s.erase(0, s.find_first_not_of('0')); + return s; + }; +}; +} // namespace TW::Move diff --git a/src/Sui/Address.cpp b/src/Sui/Address.cpp new file mode 100644 index 00000000000..63bba970c76 --- /dev/null +++ b/src/Sui/Address.cpp @@ -0,0 +1,24 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Address.h" +#include "HexCoding.h" + +namespace TW::Sui { + +Address::Address(const std::string& string) : Address::SuiAddress(string) { +} + +Address::Address(const PublicKey& publicKey): Address::SuiAddress(publicKey) { +} + +Data Address::getDigest(const PublicKey& publicKey) { + auto key_data = Data{0x00}; + append(key_data, publicKey.bytes); + return key_data; +} + +} // namespace TW::Sui diff --git a/src/Sui/Address.h b/src/Sui/Address.h new file mode 100644 index 00000000000..ccdf055a1c1 --- /dev/null +++ b/src/Sui/Address.h @@ -0,0 +1,39 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" +#include "PublicKey.h" +#include "Move/Address.h" + +#include + +namespace TW::Sui { + +class Address : public Move::Address { +public: + using SuiAddress = Move::Address; + using SuiAddress::size; + using SuiAddress::bytes; + + /// Initializes an Sui address with a string representation. + explicit Address(const std::string& string); + + /// Initializes an Sui address with a public key. + explicit Address(const PublicKey& publicKey); + + /// Constructor that allow factory programming; + Address() noexcept = default; + + Data getDigest(const PublicKey& publicKey); +}; + +constexpr inline bool operator==(const Address& lhs, const Address& rhs) noexcept { + return lhs.bytes == rhs.bytes; +} + +} // namespace TW::Sui diff --git a/src/Sui/Entry.cpp b/src/Sui/Entry.cpp new file mode 100644 index 00000000000..8df448495ca --- /dev/null +++ b/src/Sui/Entry.cpp @@ -0,0 +1,26 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Entry.h" + +#include "Address.h" +#include "Signer.h" + +namespace TW::Sui { + +bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { + return Address::isValid(address); +} + +std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, [[maybe_unused]] const PrefixVariant& addressPrefix) const { + return Address(publicKey).string(); +} + +void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { + signTemplate(dataIn, dataOut); +} + +} // namespace TW::Sui diff --git a/src/Sui/Entry.h b/src/Sui/Entry.h new file mode 100644 index 00000000000..75cfde95062 --- /dev/null +++ b/src/Sui/Entry.h @@ -0,0 +1,20 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "CoinEntry.h" + +namespace TW::Sui { + +class Entry final : public CoinEntry { +public: + bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; + std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; + void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; +}; + +} // namespace TW::Sui diff --git a/src/Sui/Signer.cpp b/src/Sui/Signer.cpp new file mode 100644 index 00000000000..49e9b247f63 --- /dev/null +++ b/src/Sui/Signer.cpp @@ -0,0 +1,45 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Signer.h" +#include "Address.h" +#include "Base64.h" +#include "PublicKey.h" + +namespace { + +enum IntentScope : int { + TransactionData = 0, +}; + +enum IntentVersion : int { + V0 = 0, +}; + +enum IntentAppId { + Sui = 0 +}; + +} // namespace + +namespace TW::Sui { + +Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { + auto protoOutput = Proto::SigningOutput(); + auto unsignedTx = input.sign_direct_message().unsigned_tx_msg(); + auto unsignedTxData = TW::Base64::decode(unsignedTx); + Data toSign{TransactionData, V0, IntentAppId::Sui}; + append(toSign, unsignedTxData); + auto privateKey = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); + Data signatureScheme{0x00}; + append(signatureScheme, privateKey.sign(toSign, TWCurveED25519)); + append(signatureScheme, privateKey.getPublicKey(TWPublicKeyTypeED25519).bytes); + protoOutput.set_unsigned_tx(unsignedTx); + protoOutput.set_signature(TW::Base64::encode(signatureScheme)); + return protoOutput; +} + +} // namespace TW::Sui diff --git a/src/Sui/Signer.h b/src/Sui/Signer.h new file mode 100644 index 00000000000..2b158464c88 --- /dev/null +++ b/src/Sui/Signer.h @@ -0,0 +1,25 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" +#include "PrivateKey.h" +#include "proto/Sui.pb.h" + +namespace TW::Sui { + +/// Helper class that performs Sui transaction signing. +class Signer { +public: + /// Hide default constructor + Signer() = delete; + + /// Signs a Proto::SigningInput transaction + static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept; +}; + +} // namespace TW::Sui diff --git a/src/proto/Sui.proto b/src/proto/Sui.proto new file mode 100644 index 00000000000..ae68ccf2367 --- /dev/null +++ b/src/proto/Sui.proto @@ -0,0 +1,34 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +syntax = "proto3"; + +package TW.Sui.Proto; +option java_package = "wallet.core.jni.proto"; + +// Base64 encoded msg to sign (string) +message SignDirect { + // Obtain by calling any write RpcJson on SUI + string unsigned_tx_msg = 1; +} + +// Input data necessary to create a signed transaction. +message SigningInput { + // Private key to sign the transaction (bytes) + bytes private_key = 1; + + oneof transaction_payload { + SignDirect sign_direct_message = 2; + } +} + +// Transaction signing output. +message SigningOutput { + /// The raw transaction without indent in base64 + string unsigned_tx = 1; + /// The signature encoded in base64 + string signature = 2; +} diff --git a/swift/Tests/Blockchains/SuiTests.swift b/swift/Tests/Blockchains/SuiTests.swift new file mode 100644 index 00000000000..a8a64e8892c --- /dev/null +++ b/swift/Tests/Blockchains/SuiTests.swift @@ -0,0 +1,40 @@ +// Copyright © 2017-2022 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import WalletCore +import XCTest + +class SuiTests: XCTestCase { + func testAddress() { + let anyAddress = AnyAddress(string: "0x061ce2b2100a71bb7aa0da98998887ad82597948", coin: .sui) + + XCTAssertEqual(anyAddress?.description, "0x061ce2b2100a71bb7aa0da98998887ad82597948") + XCTAssertEqual(anyAddress?.coin, .sui) + + let invalid = "MQqpqMQgCBuiPkoXfgZZsJvuzCeI1zc00z6vHJj4" + XCTAssertNil(Data(hexString: invalid)) + XCTAssertNil(AnyAddress(string: invalid, coin: .sui)) + XCTAssertFalse(AnyAddress.isValid(string: invalid, coin: .sui)) + } + + func testSign() { + // Successfully broadcasted https://explorer.sui.io/transaction/rxLgxcAqgMg8gphp6eCsSGQcdZnwFYx2SRdwEhnAUC4 + let privateKeyData = Data(hexString: "3823dce5288ab55dd1c00d97e91933c613417fdb282a0b8b01a7f5f5a533b266")! + let txBytes = """ +AAUCLiNiMy/EzosKCk5EZr5QQZmMVLnvAAAAAAAAACDqj/OT+1+qyLZKV4YLw8kpK3/bTZKspTUmh1pBuUfHPLb0crwkV1LQcBARaxER8XhTNJmK7wAAAAAAAAAgaQEguOdXa+m16IM536nsveakQ4u/GYJAc1fpYGGKEvgBQUP35yxF+cEL5qm153kw18dVeuYB6AMAAAAAAAAttQCskZzd41GsNuNxHYMsbbl2aS4jYjMvxM6LCgpORGa+UEGZjFS57wAAAAAAAAAg6o/zk/tfqsi2SleGC8PJKSt/202SrKU1JodaQblHxzwBAAAAAAAAAOgDAAAAAAAA +""" + let input = SuiSigningInput.with { + $0.signDirectMessage = SuiSignDirect.with { + $0.unsignedTxMsg = txBytes + } + $0.privateKey = privateKeyData + } + let output: SuiSigningOutput = AnySigner.sign(input: input, coin: .sui) + XCTAssertEqual(output.unsignedTx, txBytes) + let expectedSignature = "AIYRmHDpQesfAx3iWBCMwInf3MZ56ZQGnPWNtECFjcSq0ssAgjRW6GLnFCX24tfDNjSm9gjYgoLmn1No15iFJAtqfN7sFqdcD/Z4e8I1YQlGkDMCK7EOgmydRDqfH8C9jg==" + XCTAssertEqual(output.signature, expectedSignature) + } +} diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 1863b13d3b5..eced318a140 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -259,6 +259,9 @@ class CoinAddressDerivationTests: XCTestCase { case .aptos: let expectedResult = "0x07968dab936c1bad187c60ce4082f307d030d780e91e694ae03aef16aba73f30"; assertCoinDerivation(coin, expectedResult, derivedAddress, address) + case .sui: + let expectedResult = "0x061ce2b2100a71bb7aa0da98998887ad82597948"; + assertCoinDerivation(coin, expectedResult, derivedAddress, address) case .hedera: let expectedResult = "0.0.302a300506032b657003210049eba62f64d0d941045595d9433e65d84ecc46bcdb1421de55e05fcf2d8357d5"; assertCoinDerivation(coin, expectedResult, derivedAddress, address) diff --git a/tests/chains/Sui/AddressTests.cpp b/tests/chains/Sui/AddressTests.cpp new file mode 100644 index 00000000000..c28c9c4253e --- /dev/null +++ b/tests/chains/Sui/AddressTests.cpp @@ -0,0 +1,53 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "HexCoding.h" +#include "Sui/Address.h" +#include "PublicKey.h" +#include "PrivateKey.h" +#include +#include + +namespace TW::Sui::tests { + +TEST(SuiAddress, Valid) { + ASSERT_TRUE(Address::isValid("0x1")); + // Address 20 are valid in SUI + ASSERT_TRUE(Address::isValid("0xb1dc06bd64d4e179a482b97bb68243f6c02c1b92")); + ASSERT_TRUE(Address::isValid("b1dc06bd64d4e179a482b97bb68243f6c02c1b92")); +} + +TEST(SuiAddress, Invalid) { + // Address 32 are invalid in SUI + ASSERT_FALSE(Address::isValid("0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b")); + ASSERT_FALSE(Address::isValid("eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b")); + ASSERT_FALSE(Address::isValid("19aadeca9388e009d136245b9a67423f3eee242b03142849eb4f81a4a409e59c")); + // Too long + ASSERT_FALSE(Address::isValid("b1dc06bd64d4e179a482b97bb68243f6c02c1b921")); + // Too short + ASSERT_FALSE(Address::isValid("b1dc06bd64d4e179a482b97bb68243f6c02c1b9")); + // Invalid Hex + ASSERT_FALSE(Address::isValid("0xS1dc06bd64d4e179a482b97bb68243f6c02c1b92")); +} + +TEST(SuiAddress, FromString) { + auto address = Address("b1dc06bd64d4e179a482b97bb68243f6c02c1b92"); + ASSERT_EQ(address.string(), "0xb1dc06bd64d4e179a482b97bb68243f6c02c1b92"); +} + +TEST(SuiAddress, FromPrivateKey) { + auto privateKey = PrivateKey(parse_hex("088baa019f081d6eab8dff5c447f9ce2f83c1babf3d03686299eaf6a1e89156e")); + auto address = Address(privateKey.getPublicKey(TWPublicKeyTypeED25519)); + ASSERT_EQ(address.string(), "0xb638d15fa81d301a9756259d0c7b2ca27a00a531"); +} + +TEST(SuiAddress, FromPublicKey) { + auto publicKey = PublicKey(parse_hex("ad0e293a56c9fc648d1872a00521d97e6b65724519a2676c2c47cb95d131cf5a"), TWPublicKeyTypeED25519); + auto address = Address(publicKey); + ASSERT_EQ(address.string(), "0xb638d15fa81d301a9756259d0c7b2ca27a00a531"); +} + +} // namespace TW::Sui::tests diff --git a/tests/chains/Sui/SignerTests.cpp b/tests/chains/Sui/SignerTests.cpp new file mode 100644 index 00000000000..29c640dfbff --- /dev/null +++ b/tests/chains/Sui/SignerTests.cpp @@ -0,0 +1,65 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Sui/Signer.h" +#include "Sui/Address.h" +#include "HexCoding.h" +#include "PrivateKey.h" +#include "PublicKey.h" + +#include + +namespace TW::Sui::tests { + +TEST(SuiSigner, Transfer) { + // Successfully broadcasted https://explorer.sui.io/transaction/rxLgxcAqgMg8gphp6eCsSGQcdZnwFYx2SRdwEhnAUC4 + Proto::SigningInput input; + auto txMsg = "AAUCLiNiMy/EzosKCk5EZr5QQZmMVLnvAAAAAAAAACDqj/OT+1+qyLZKV4YLw8kpK3/bTZKspTUmh1pBuUfHPLb0crwkV1LQcBARaxER8XhTNJmK7wAAAAAAAAAgaQEguOdXa+m16IM536nsveakQ4u/GYJAc1fpYGGKEvgBQUP35yxF+cEL5qm153kw18dVeuYB6AMAAAAAAAAttQCskZzd41GsNuNxHYMsbbl2aS4jYjMvxM6LCgpORGa+UEGZjFS57wAAAAAAAAAg6o/zk/tfqsi2SleGC8PJKSt/202SrKU1JodaQblHxzwBAAAAAAAAAOgDAAAAAAAA"; + input.mutable_sign_direct_message()->set_unsigned_tx_msg(txMsg); + auto privateKey = PrivateKey(parse_hex("3823dce5288ab55dd1c00d97e91933c613417fdb282a0b8b01a7f5f5a533b266")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(result.unsigned_tx(), "AAUCLiNiMy/EzosKCk5EZr5QQZmMVLnvAAAAAAAAACDqj/OT+1+qyLZKV4YLw8kpK3/bTZKspTUmh1pBuUfHPLb0crwkV1LQcBARaxER8XhTNJmK7wAAAAAAAAAgaQEguOdXa+m16IM536nsveakQ4u/GYJAc1fpYGGKEvgBQUP35yxF+cEL5qm153kw18dVeuYB6AMAAAAAAAAttQCskZzd41GsNuNxHYMsbbl2aS4jYjMvxM6LCgpORGa+UEGZjFS57wAAAAAAAAAg6o/zk/tfqsi2SleGC8PJKSt/202SrKU1JodaQblHxzwBAAAAAAAAAOgDAAAAAAAA"); + ASSERT_EQ(result.signature(), "AIYRmHDpQesfAx3iWBCMwInf3MZ56ZQGnPWNtECFjcSq0ssAgjRW6GLnFCX24tfDNjSm9gjYgoLmn1No15iFJAtqfN7sFqdcD/Z4e8I1YQlGkDMCK7EOgmydRDqfH8C9jg=="); +} + +TEST(SuiSigner, TransferNFT) { + // Successfully broadcasted https://explorer.sui.io/transaction/EmnhP9swuoijxYwHMywnXDGCXfFs1QxErsYoyWy9Y15J + Proto::SigningInput input; + std::string unsigned_tx = R"(AAAv0f6HrJCZ/1cuDVuxh1BL12XMeHxkKeZ7Js9grhcB0u8xtTvoOepOHAAAAAAAAAAgJvcpOSvKhM+tHPgGAnp5Pmc8l3wjZhVxK4/BrLu4YAgttQCskZzd41GsNuNxHYMsbbl2aSEnoKw8oAGf/LobCM7RxGurtPZtHAAAAAAAAAAgwk74iUAH9S+cGVXQxAydItvltZ3UK2L0vg1TYgDMPfABAAAAAAAAAOgDAAAAAAAA)"; + input.mutable_sign_direct_message()->set_unsigned_tx_msg(unsigned_tx); + auto privateKey = PrivateKey(parse_hex("3823dce5288ab55dd1c00d97e91933c613417fdb282a0b8b01a7f5f5a533b266")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(result.unsigned_tx(), unsigned_tx); + ASSERT_EQ(result.signature(), "AIjbyuyg9YX0f8/DXB5XZBnUCOqhUrPDbU9/E/FlzwGtDS57cOL/gZwN3vTV1KiOuN0cr0kxypgJpVLKlhd8hgdqfN7sFqdcD/Z4e8I1YQlGkDMCK7EOgmydRDqfH8C9jg=="); +} + +TEST(SuiSigner, MoveCall) { + // Successfully broadcasted on: https://explorer.sui.io/transaction/3Gg8AcEfokDnA8m7W58ANmeCr8vkSaPWjXMp9sLMScTj + Proto::SigningInput input; + std::string unsigned_tx = R"(AAIAAAAAAAAAAAAAAAAAAAAAAAAAAgEAAAAAAAAAINaXMihjlCd4CQVFRPjcNb7QfYP4wGgQyl1xbplvEKUCA3N1aQh0cmFuc2ZlcgACAQCdB6Mav5rHiXD0rAWTCxS+ENwxMBsAAAAAAAAAINqDfrJUZebPjUi7xcyR3QcQSA9tOLwxThgYaZ1vMfgfABQU2gJ3ToaOYd1F/R6mXryOZdvpRi21AKyRnN3jUaw243EdgyxtuXZppM+mSjYYEQWDcV/7hFRrAE0VtRwbAAAAAAAAACC5nJxYaYJfa9rfbxSikaEFVmHGuXyCIZoZbMpxMwLebAEAAAAAAAAA0AcAAAAAAAA=)"; + input.mutable_sign_direct_message()->set_unsigned_tx_msg(unsigned_tx); + auto privateKey = PrivateKey(parse_hex("3823dce5288ab55dd1c00d97e91933c613417fdb282a0b8b01a7f5f5a533b266")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(result.unsigned_tx(), unsigned_tx); + ASSERT_EQ(result.signature(), "AE8394w/+KOodhLjnKgu21iW0xZur6MA4ajPh31f2xaOI7vs6JHLAHLk5ED3bfJfc5ZehmC6D4DMyrH4F0dA3A1qfN7sFqdcD/Z4e8I1YQlGkDMCK7EOgmydRDqfH8C9jg=="); +} + +TEST(SuiSigner, AddDelegation) { + // Successfully broadcasted on: https://explorer.sui.io/transaction/3Gg8AcEfokDnA8m7W58ANmeCr8vkSaPWjXMp9sLMScTj + Proto::SigningInput input; + std::string unsigned_tx = R"(AAIAAAAAAAAAAAAAAAAAAAAAAAAAAgEAAAAAAAAAIEt/p6rXSTjdKP6wJOXyx0c2xsgJ4MJtfxe7qHC34u4UCnN1aV9zeXN0ZW0fcmVxdWVzdF9hZGRfZGVsZWdhdGlvbl9tdWxfY29pbgAEAQEAAAAAAAAAAAAAAAAAAAAAAAAABQEAAAAAAAAAAgIAGSkMV9AFc419O9dL1kez9tzVIOiXzAEAAAAAACAfIePlHHP/+iv++FWQW9ofkVm4S2sFwupGikSq8bNjYwAH1A26NKDn7pJfn9zWaDi1nbntMJfMAQAAAAAAIKfMZAZktdmw36jwg/jcK1TDmrHmSZ/fdkeInO3BSjfWAAkB0AcAAAAAAAAAFAej1I8mhjmcpQTQtiX2J2HZ7y2xLbUArJGc3eNRrDbjcR2DLG25dmlY2RBfTU/P+GL1qpxE8NQrwiLw/JfMAQAAAAAAICs2NJlowCmCnpJ+hja2VwZE5K6yGM/qw0MSRnn9tW2cbgAAAAAAAACghgEAAAAAAA==)"; + input.mutable_sign_direct_message()->set_unsigned_tx_msg(unsigned_tx); + auto privateKey = PrivateKey(parse_hex("3823dce5288ab55dd1c00d97e91933c613417fdb282a0b8b01a7f5f5a533b266")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + auto result = Signer::sign(input); + ASSERT_EQ(result.unsigned_tx(), unsigned_tx); + ASSERT_EQ(result.signature(), "AKSbUoc+F4JGG9i+A8yVYyzcD8BXNV88iSaWpoS5KXUG7ao2pxjyvfUJEYyhWXTxgQazNDnIM1xGhD7zu1GU1wRqfN7sFqdcD/Z4e8I1YQlGkDMCK7EOgmydRDqfH8C9jg=="); +} + +} // namespace TW::Sui::tests diff --git a/tests/chains/Sui/TWCoinTypeTests.cpp b/tests/chains/Sui/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..9489907728d --- /dev/null +++ b/tests/chains/Sui/TWCoinTypeTests.cpp @@ -0,0 +1,33 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "TestUtilities.h" +#include +#include + + +TEST(TWSuiCoinType, TWCoinType) { + const auto coin = TWCoinTypeSui; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("SWRW1RoMHxnD9NeobgBoC4cXGwp2Hc511CnfWUoTBmo")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0x62107e1afefccc7b2267ab74e332c146f5c2ca15")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "sui"); + assertStringsEqual(name, "Sui"); + assertStringsEqual(symbol, "SUI"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 9); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainSui); + assertStringsEqual(txUrl, "https://explorer.sui.io//transaction/SWRW1RoMHxnD9NeobgBoC4cXGwp2Hc511CnfWUoTBmo"); + assertStringsEqual(accUrl, "https://explorer.sui.io//address/0x62107e1afefccc7b2267ab74e332c146f5c2ca15"); +} diff --git a/tests/common/Base64Tests.cpp b/tests/common/Base64Tests.cpp index 1d61102f7ff..339c4859175 100644 --- a/tests/common/Base64Tests.cpp +++ b/tests/common/Base64Tests.cpp @@ -46,6 +46,15 @@ TEST(Base64, decode) { EXPECT_EQ("11ff8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d291b", hex(decoded)); } + + +TEST(Base64, EncodeDecodeSui) { + auto v = "AAIAAAAAAAAAAAAAAAAAAAAAAAAAAgEAAAAAAAAAINaXMihjlCd4CQVFRPjcNb7QfYP4wGgQyl1xbplvEKUCA3N1aQh0cmFuc2ZlcgACAQCDlY9/fBVEt0yclyDF8RrjSRBfRRsAAAAAAAAAIJttZrU/26Bim7ku4dwY8d3fdabngn0B6dY/hLKgb6+xABQv0f6HrJCZ/1cuDVuxh1BL12XMeC21AKyRnN3jUaw243EdgyxtuXZpG62iKzFvYdk6RMGXxnoWd8RcfwkUAQAAAAAAACDi9GYNIZ0FXpPPi+zdDUuzHfs6MDoxzPuXGPZJq8ZfOAEAAAAAAAAA0AcAAAAAAAA="; + auto decoded = decode(v); + auto encoded = encode(decoded); + ASSERT_EQ(encoded, v); +} + TEST(Base64, UrlFormat) { const std::string const1 = "11003faa8556289975ec991ac9994dfb613abec4ea000d5094e6379080f594e559b330b8"; diff --git a/tests/common/CoinAddressDerivationTests.cpp b/tests/common/CoinAddressDerivationTests.cpp index 34b27fce10e..7f54228c9a1 100644 --- a/tests/common/CoinAddressDerivationTests.cpp +++ b/tests/common/CoinAddressDerivationTests.cpp @@ -256,6 +256,9 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeAptos: EXPECT_EQ(address, "0xce2fd04ac9efa74f17595e5785e847a2399d7e637f5e8179244f76191f653276"); break; + case TWCoinTypeSui: + EXPECT_EQ(address, "0xfc93395679dec6ca84d9766be2014b6bc1473f2e"); + break; case TWCoinTypeHedera: EXPECT_EQ(address, "0.0.302a300506032b6570032100ee93a4f66f8d16b819bb9beb9ffccdfcdc1412e87fee6a324c2a99a1e0e67148"); break; diff --git a/tests/common/HDWallet/HDWalletTests.cpp b/tests/common/HDWallet/HDWalletTests.cpp index c5f858bbc04..44441d5b113 100644 --- a/tests/common/HDWallet/HDWalletTests.cpp +++ b/tests/common/HDWallet/HDWalletTests.cpp @@ -8,6 +8,7 @@ #include "Bitcoin/Address.h" #include "Bitcoin/CashAddress.h" #include "Bitcoin/SegwitAddress.h" +#include "Sui/Address.h" #include "Coin.h" #include "Ethereum/Address.h" #include "Ethereum/EIP2645.h" @@ -440,6 +441,18 @@ TEST(HDWallet, AptosKey) { } } +TEST(HDWallet, SuiKey) { + const auto derivPath = "m/44'/784'/0'/0'/0'"; + HDWallet wallet = HDWallet("cost add execute system fault long raccoon stone paddle column ketchup smile debate wood marble please jar can goddess magnet axis celery rough gold", ""); + { + const auto privateKey = wallet.getKey(TWCoinTypeSui, DerivationPath(derivPath)); + EXPECT_EQ(hex(privateKey.bytes), "3823dce5288ab55dd1c00d97e91933c613417fdb282a0b8b01a7f5f5a533b266"); + auto pubkey = privateKey.getPublicKey(TWPublicKeyTypeED25519); + EXPECT_EQ(hex(pubkey.bytes), "6a7cdeec16a75c0ff6787bc2356109469033022bb10e826c9d443a9f1fc0bd8e"); + EXPECT_EQ(TW::Sui::Address(pubkey).string(), "0x2db500ac919cdde351ac36e3711d832c6db97669"); + } +} + TEST(HDWallet, HederaKey) { // https://github.com/hashgraph/hedera-sdk-js/blob/e0cd39c84ab189d59a6bcedcf16e4102d7bb8beb/packages/cryptography/test/unit/Mnemonic.js#L47 { diff --git a/tests/common/rust/bindgen/WalletCoreRsTests.cpp b/tests/common/rust/bindgen/WalletCoreRsTests.cpp index ce99263e0c1..4293863ec56 100644 --- a/tests/common/rust/bindgen/WalletCoreRsTests.cpp +++ b/tests/common/rust/bindgen/WalletCoreRsTests.cpp @@ -5,7 +5,6 @@ // file LICENSE at the root of the source code distribution tree. #include "rust/bindgen/WalletCoreRSBindgen.h" - #include "gtest/gtest.h" TEST(RustBindgen, MoveParseFunctionArgument) { diff --git a/tools/install-wasm-dependencies b/tools/install-wasm-dependencies index dcf17caa686..31fc852b850 100755 --- a/tools/install-wasm-dependencies +++ b/tools/install-wasm-dependencies @@ -2,7 +2,7 @@ set -e -emsdk_version=3.1.22 +emsdk_version=3.1.30 git clone https://github.com/emscripten-core/emsdk.git diff --git a/walletconsole/lib/Util.cpp b/walletconsole/lib/Util.cpp index 86dd938dc84..a0312d05261 100644 --- a/walletconsole/lib/Util.cpp +++ b/walletconsole/lib/Util.cpp @@ -38,14 +38,13 @@ bool Util::base64Encode(const string& p, string& res) { } bool Util::base64Decode(const string& p, string& res) { - try { - auto dec = Base64::decode(p); - res = TW::hex(dec); - return true; - } catch (exception& ex) { + auto dec = Base64::decode(p); + if (dec.empty()) { _out << "Error while Base64 decode" << endl; return false; } + res = TW::hex(dec); + return true; } bool Util::fileW(const string& fileName, const string& data, [[maybe_unused]] string& res) { diff --git a/wasm/CMakeLists.txt b/wasm/CMakeLists.txt index e7ea9f4ca0e..592e636d94c 100644 --- a/wasm/CMakeLists.txt +++ b/wasm/CMakeLists.txt @@ -40,5 +40,5 @@ set_target_properties(${TARGET_NAME} set_target_properties(${TARGET_NAME} PROPERTIES COMPILE_FLAGS "-O2 -sSTRICT -sUSE_BOOST_HEADERS=1" - LINK_FLAGS "--bind --no-entry --closure 1 -O2 -sSTRICT -sASSERTIONS -sMODULARIZE=1 -sALLOW_MEMORY_GROWTH=1 -sDYNAMIC_EXECUTION=0" + LINK_FLAGS "--bind --no-entry --closure 1 -O2 -sSTRICT -sASSERTIONS -sMODULARIZE=1 -sALLOW_MEMORY_GROWTH=1 -sDYNAMIC_EXECUTION=0 -s EXPORTED_FUNCTIONS=['_setThrew']" ) diff --git a/wasm/tests/Blockchain/Sui.test.ts b/wasm/tests/Blockchain/Sui.test.ts new file mode 100644 index 00000000000..49baaea6c84 --- /dev/null +++ b/wasm/tests/Blockchain/Sui.test.ts @@ -0,0 +1,28 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import "mocha"; +import { assert } from "chai"; +import { Buffer } from "buffer"; +import { TW } from "../../dist"; + +describe("Sui", () => { + it("test sign Sui", () => { + const { PrivateKey, HexCoding, AnySigner, AnyAddress, CoinType } = globalThis.core; + const txDataInput = TW.Sui.Proto.SigningInput.create({ + signDirectMessage: TW.Sui.Proto.SignDirect.create({ + unsignedTxMsg: "AAUCLiNiMy/EzosKCk5EZr5QQZmMVLnvAAAAAAAAACDqj/OT+1+qyLZKV4YLw8kpK3/bTZKspTUmh1pBuUfHPLb0crwkV1LQcBARaxER8XhTNJmK7wAAAAAAAAAgaQEguOdXa+m16IM536nsveakQ4u/GYJAc1fpYGGKEvgBQUP35yxF+cEL5qm153kw18dVeuYB6AMAAAAAAAAttQCskZzd41GsNuNxHYMsbbl2aS4jYjMvxM6LCgpORGa+UEGZjFS57wAAAAAAAAAg6o/zk/tfqsi2SleGC8PJKSt/202SrKU1JodaQblHxzwBAAAAAAAAAOgDAAAAAAAA" + }), + privateKey: HexCoding.decode( + "0x3823dce5288ab55dd1c00d97e91933c613417fdb282a0b8b01a7f5f5a533b266", + ) + }); + const input = TW.Sui.Proto.SigningInput.encode(txDataInput).finish(); + const outputData = AnySigner.sign(input, CoinType.sui); + const output = TW.Sui.Proto.SigningOutput.decode(outputData); + assert.equal(output.signature, "AIYRmHDpQesfAx3iWBCMwInf3MZ56ZQGnPWNtECFjcSq0ssAgjRW6GLnFCX24tfDNjSm9gjYgoLmn1No15iFJAtqfN7sFqdcD/Z4e8I1YQlGkDMCK7EOgmydRDqfH8C9jg==") + }); +}); From 588bd84642428db5fd417f41e1bac99e76128492 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 1 Feb 2023 10:52:01 +0100 Subject: [PATCH 180/497] fix(thorchain): fix overflow for big amount (#2901) --- src/THORChain/Swap.cpp | 14 +++++++------- src/THORChain/Swap.h | 9 +++++---- tests/chains/THORChain/SwapTests.cpp | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/THORChain/Swap.cpp b/src/THORChain/Swap.cpp index cb42e556b81..52eb156d7be 100644 --- a/src/THORChain/Swap.cpp +++ b/src/THORChain/Swap.cpp @@ -109,7 +109,7 @@ SwapBundled SwapBuilder::build(bool shortened) { return {.status_code = static_cast(Proto::ErrorCode::Error_Invalid_to_address), .error = "Invalid to address"}; } - uint64_t fromAmountNum = std::stoull(mFromAmount); + uint256_t fromAmountNum = uint256_t(mFromAmount); const auto memo = this->buildMemo(shortened); switch (fromChain) { @@ -164,7 +164,7 @@ std::string SwapBuilder::buildMemo(bool shortened) noexcept { return memo.str(); } -SwapBundled SwapBuilder::buildBitcoin(uint64_t amount, const std::string& memo, Chain fromChain) { +SwapBundled SwapBuilder::buildBitcoin(uint256_t amount, const std::string& memo, Chain fromChain) { auto input = Bitcoin::Proto::SigningInput(); Data out; // Following fields must be set afterwards, before signing ... @@ -187,7 +187,7 @@ SwapBundled SwapBuilder::buildBitcoin(uint64_t amount, const std::string& memo, out.insert(out.end(), serialized.begin(), serialized.end()); return {.out = std::move(out)}; } -SwapBundled SwapBuilder::buildBinance(Proto::Asset fromAsset, uint64_t amount, const std::string& memo) { +SwapBundled SwapBuilder::buildBinance(Proto::Asset fromAsset, uint256_t amount, const std::string& memo) { auto input = Binance::Proto::SigningInput(); Data out; @@ -205,7 +205,7 @@ SwapBundled SwapBuilder::buildBinance(Proto::Asset fromAsset, uint64_t amount, c auto token = Binance::Proto::SendOrder::Token(); token.set_denom(fromAsset.token_id().empty() ? "BNB" : fromAsset.token_id()); - token.set_amount(amount); + token.set_amount(static_cast(amount)); { Binance::Address fromAddressBin; Binance::Address::decode(mFromAddress, fromAddressBin); @@ -226,7 +226,7 @@ SwapBundled SwapBuilder::buildBinance(Proto::Asset fromAsset, uint64_t amount, c return {.out = std::move(out)}; } -SwapBundled SwapBuilder::buildEth(uint64_t amount, const std::string& memo) { +SwapBundled SwapBuilder::buildEth(uint256_t amount, const std::string& memo) { Data out; auto input = Ethereum::Proto::SigningInput(); // EIP-1559 @@ -280,7 +280,7 @@ SwapBundled SwapBuilder::buildEth(uint64_t amount, const std::string& memo) { return {.out = std::move(out)}; } -SwapBundled SwapBuilder::buildAtom(uint64_t amount, const std::string& memo) { +SwapBundled SwapBuilder::buildAtom(uint256_t amount, const std::string& memo) { if (!Cosmos::Address::isValid(mVaultAddress, "cosmos")) { return {.status_code = static_cast(Proto::ErrorCode::Error_Invalid_vault_address), .error = "Invalid vault address: " + mVaultAddress}; } @@ -299,7 +299,7 @@ SwapBundled SwapBuilder::buildAtom(uint64_t amount, const std::string& memo) { auto amountOfTx = message.add_amounts(); amountOfTx->set_denom("uatom"); - amountOfTx->set_amount(std::to_string(amount)); + amountOfTx->set_amount(amount.str()); auto serialized = input.SerializeAsString(); out.insert(out.end(), serialized.begin(), serialized.end()); diff --git a/src/THORChain/Swap.h b/src/THORChain/Swap.h index b8bedea7a76..926ef3535b1 100644 --- a/src/THORChain/Swap.h +++ b/src/THORChain/Swap.h @@ -8,6 +8,7 @@ #include "Data.h" #include "proto/THORChainSwap.pb.h" +#include "uint256.h" #include #include @@ -49,10 +50,10 @@ class SwapBuilder { std::optional mAffFeeRate{std::nullopt}; std::optional mExtraMemo{std::nullopt}; - SwapBundled buildBitcoin(uint64_t amount, const std::string& memo, Chain fromChain); - SwapBundled buildBinance(Proto::Asset fromAsset, uint64_t amount, const std::string& memo); - SwapBundled buildEth(uint64_t amount, const std::string& memo); - SwapBundled buildAtom(uint64_t amount, const std::string& memo); + SwapBundled buildBitcoin(uint256_t amount, const std::string& memo, Chain fromChain); + SwapBundled buildBinance(Proto::Asset fromAsset, uint256_t amount, const std::string& memo); + SwapBundled buildEth(uint256_t amount, const std::string& memo); + SwapBundled buildAtom(uint256_t amount, const std::string& memo); public: SwapBuilder() noexcept = default; diff --git a/tests/chains/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp index f47bc022a34..372bfd70d9e 100644 --- a/tests/chains/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -42,6 +42,25 @@ const auto VaultEth = "0x1091c4De6a3cF09CdA00AbDAeD42c7c3B69C83EC"; const auto VaultBnb = "bnb1n9esxuw8ca7ts8l6w66kdh800s09msvul6vlse"; const auto RouterEth = "0x42A5Ed456650a09Dc10EBc6361A7480fDd61f27B"; +TEST(THORChainSwap, OverflowFixEth) { + Proto::Asset fromAsset; + fromAsset.set_chain(static_cast(Chain::ETH)); + fromAsset.set_symbol("ETH"); + Proto::Asset toAsset; + toAsset.set_chain(static_cast(Chain::BTC)); + toAsset.set_symbol("BTC"); + auto&& [out, errorCode, error] = SwapBuilder::builder() + .from(fromAsset) + .to(toAsset) + .fromAddress(Address1Eth) + .toAddress(Address1Btc) + .vault(VaultEth) + .fromAmount("1234000000000000000000") + .toAmountLimit("5285656144") + .build(); + ASSERT_EQ(errorCode, 0); +} + TEST(THORChainSwap, SwapBtcEth) { Proto::Asset fromAsset; fromAsset.set_chain(static_cast(Chain::BTC)); From 940ae76fc79fce8e424339ff6579f12f741aaeda Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 2 Feb 2023 14:26:14 +0100 Subject: [PATCH 181/497] Update CODEOWNERS (#2903) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 61760e1454c..79869e12cc8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,4 +3,4 @@ # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @hewigovens @catenocrypt @milerius +* @hewigovens @rsrbk @milerius From ab369a94deb3ff191dbd7b5373e63d467ce96ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Fri, 3 Feb 2023 11:54:46 +0200 Subject: [PATCH 182/497] Code-wise rebranding of Elrond to MultiversX (#2895) --- .../blockchains/CoinAddressDerivationTests.kt | 2 +- .../TestMultiversXAddress.kt} | 10 ++-- .../TestMultiversXSigner.kt} | 54 +++++++++---------- include/TrustWalletCore/TWBlockchain.h | 2 +- include/TrustWalletCore/TWCoinType.h | 2 +- registry.json | 5 +- src/Coin.cpp | 6 +-- src/{Elrond => MultiversX}/Address.cpp | 4 +- src/{Elrond => MultiversX}/Address.h | 17 +++--- src/{Elrond => MultiversX}/Codec.cpp | 6 +-- src/{Elrond => MultiversX}/Codec.h | 6 +-- src/{Elrond => MultiversX}/Entry.cpp | 6 +-- src/{Elrond => MultiversX}/Entry.h | 6 +-- src/{Elrond => MultiversX}/GasEstimator.cpp | 4 +- src/{Elrond => MultiversX}/GasEstimator.h | 2 +- src/{Elrond => MultiversX}/NetworkConfig.cpp | 4 +- src/{Elrond => MultiversX}/NetworkConfig.h | 17 +++--- src/{Elrond => MultiversX}/Serialization.cpp | 6 +-- src/{Elrond => MultiversX}/Serialization.h | 4 +- src/{Elrond => MultiversX}/Signer.cpp | 4 +- src/{Elrond => MultiversX}/Signer.h | 8 +-- src/{Elrond => MultiversX}/Transaction.cpp | 4 +- src/{Elrond => MultiversX}/Transaction.h | 4 +- .../TransactionFactory.cpp | 4 +- .../TransactionFactory.h | 12 +++-- src/proto/{Elrond.proto => MultiversX.proto} | 5 +- ...lrondTests.swift => MultiversXTests.swift} | 54 +++++++++---------- swift/Tests/CoinAddressDerivationTests.swift | 2 +- .../{Elrond => MultiversX}/AddressTests.cpp | 18 +++---- .../SerializationTests.cpp | 12 ++--- .../{Elrond => MultiversX}/SignerTests.cpp | 43 ++++++++------- .../TWAnySignerTests.cpp | 16 +++--- .../TWCoinTypeTests.cpp | 20 +++---- .../{Elrond => MultiversX}/TestAccounts.h | 2 +- .../TransactionFactoryTests.cpp | 18 +++---- tests/common/CoinAddressDerivationTests.cpp | 2 +- tests/common/CoinAddressValidationTests.cpp | 6 +-- tests/interface/TWAnyAddressTests.cpp | 4 +- tests/interface/TWCoinTypeTests.cpp | 4 +- tests/interface/TWHDWalletTests.cpp | 6 +-- tests/interface/TWHRPTests.cpp | 6 +-- 41 files changed, 210 insertions(+), 207 deletions(-) rename android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/{elrond/TestElrondAddress.kt => multiversx/TestMultiversXAddress.kt} (83%) rename android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/{elrond/TestElrondSigner.kt => multiversx/TestMultiversXSigner.kt} (81%) rename src/{Elrond => MultiversX}/Address.cpp (89%) rename src/{Elrond => MultiversX}/Address.h (76%) rename src/{Elrond => MultiversX}/Codec.cpp (90%) rename src/{Elrond => MultiversX}/Codec.h (89%) rename src/{Elrond => MultiversX}/Entry.cpp (92%) rename src/{Elrond => MultiversX}/Entry.h (90%) rename src/{Elrond => MultiversX}/GasEstimator.cpp (96%) rename src/{Elrond => MultiversX}/GasEstimator.h (95%) rename src/{Elrond => MultiversX}/NetworkConfig.cpp (97%) rename src/{Elrond => MultiversX}/NetworkConfig.h (90%) rename src/{Elrond => MultiversX}/Serialization.cpp (88%) rename src/{Elrond => MultiversX}/Serialization.h (90%) rename src/{Elrond => MultiversX}/Signer.cpp (96%) rename src/{Elrond => MultiversX}/Signer.h (81%) rename src/{Elrond => MultiversX}/Transaction.cpp (89%) rename src/{Elrond => MultiversX}/Transaction.h (91%) rename src/{Elrond => MultiversX}/TransactionFactory.cpp (99%) rename src/{Elrond => MultiversX}/TransactionFactory.h (94%) rename src/proto/{Elrond.proto => MultiversX.proto} (93%) rename swift/Tests/Blockchains/{ElrondTests.swift => MultiversXTests.swift} (82%) rename tests/chains/{Elrond => MultiversX}/AddressTests.cpp (86%) rename tests/chains/{Elrond => MultiversX}/SerializationTests.cpp (87%) rename tests/chains/{Elrond => MultiversX}/SignerTests.cpp (95%) rename tests/chains/{Elrond => MultiversX}/TWAnySignerTests.cpp (89%) rename tests/chains/{Elrond => MultiversX}/TWCoinTypeTests.cpp (69%) rename tests/chains/{Elrond => MultiversX}/TestAccounts.h (90%) rename tests/chains/{Elrond => MultiversX}/TransactionFactoryTests.cpp (94%) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 84ed86b221f..a5958c59d15 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -94,7 +94,7 @@ class CoinAddressDerivationTests { CARDANO -> assertEquals("addr1qyr8jjfnypp95eq74aqzn7ss687ehxclgj7mu6gratmg3mul2040vt35dypp042awzsjk5xm3zr3zm5qh7454uwdv08s84ray2", address) NEO -> assertEquals("AT6w7PJvwPcSqHvtbNBY2aHPDv12eW5Uuf", address) FILECOIN -> assertEquals("f1zzykebxldfcakj5wdb5n3n7priul522fnmjzori", address) - ELROND -> assertEquals("erd1jfcy8aeru6vlx4fe6h3pc3vlpe2cnnur5zetxdhp879yagq7vqvs8na4f8", address) + MULTIVERSX -> assertEquals("erd1jfcy8aeru6vlx4fe6h3pc3vlpe2cnnur5zetxdhp879yagq7vqvs8na4f8", address) BANDCHAIN -> assertEquals("band1624hqgend0s3d94z68fyka2y5jak6vd7u0l50r", address) SMARTCHAINLEGACY -> assertEquals("0x49784f90176D8D9d4A3feCDE7C1373dAAb5b13b8", address) OASIS -> assertEquals("oasis1qzcpavvmuw280dk0kd4lxjhtpf0u3ll27yf7sqps", address) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/multiversx/TestMultiversXAddress.kt similarity index 83% rename from android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt rename to android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/multiversx/TestMultiversXAddress.kt index e8304e3deeb..6cb38fef175 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/multiversx/TestMultiversXAddress.kt @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -package com.trustwallet.core.app.blockchains.elrond +package com.trustwallet.core.app.blockchains.multiversx import com.trustwallet.core.app.utils.toHex import com.trustwallet.core.app.utils.toHexByteArray @@ -12,7 +12,7 @@ import org.junit.Assert.assertEquals import org.junit.Test import wallet.core.jni.* -class TestElrondAddress { +class TestMultiversXAddress { init { System.loadLibrary("TrustWalletCore") @@ -26,7 +26,7 @@ class TestElrondAddress { fun testAddressFromPrivateKey() { val key = PrivateKey(aliceSeedHex.toHexByteArray()) val pubKey = key.publicKeyEd25519 - val address = AnyAddress(pubKey, CoinType.ELROND) + val address = AnyAddress(pubKey, CoinType.MULTIVERSX) assertEquals(alicePubKeyHex, pubKey.data().toHex()) assertEquals(aliceBech32, address.description()) @@ -35,14 +35,14 @@ class TestElrondAddress { @Test fun testAddressFromPublicKey() { val pubKey = PublicKey(alicePubKeyHex.toHexByteArray(), PublicKeyType.ED25519) - val address = AnyAddress(pubKey, CoinType.ELROND) + val address = AnyAddress(pubKey, CoinType.MULTIVERSX) assertEquals(aliceBech32, address.description()) } @Test fun testAddressFromString() { - val address = AnyAddress(aliceBech32, CoinType.ELROND) + val address = AnyAddress(aliceBech32, CoinType.MULTIVERSX) assertEquals(aliceBech32, address.description()) } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/multiversx/TestMultiversXSigner.kt similarity index 81% rename from android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt rename to android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/multiversx/TestMultiversXSigner.kt index a3597e4deb0..72dec595a74 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/multiversx/TestMultiversXSigner.kt @@ -4,7 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -package com.trustwallet.core.app.blockchains.elrond +package com.trustwallet.core.app.blockchains.multiversx import com.google.protobuf.ByteString import com.trustwallet.core.app.utils.toHexByteArray @@ -13,9 +13,9 @@ import org.junit.Test import wallet.core.java.AnySigner import wallet.core.jni.CoinType import wallet.core.jni.PrivateKey -import wallet.core.jni.proto.Elrond +import wallet.core.jni.proto.MultiversX -class TestElrondSigner { +class TestMultiversXSigner { init { System.loadLibrary("TrustWalletCore") @@ -29,20 +29,20 @@ class TestElrondSigner { fun signGenericAction() { val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) - val accounts = Elrond.Accounts.newBuilder() + val accounts = MultiversX.Accounts.newBuilder() .setSenderNonce(7) .setSender(aliceBech32) .setReceiver(bobBech32) .build() - val genericAction = Elrond.GenericAction.newBuilder() + val genericAction = MultiversX.GenericAction.newBuilder() .setAccounts(accounts) .setValue("0") .setData("foo") .setVersion(1) .build() - val signingInput = Elrond.SigningInput.newBuilder() + val signingInput = MultiversX.SigningInput.newBuilder() .setGenericAction(genericAction) .setGasPrice(1000000000) .setGasLimit(50000) @@ -50,7 +50,7 @@ class TestElrondSigner { .setPrivateKey(privateKey) .build() - val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) val expectedSignature = "e8647dae8b16e034d518a1a860c6a6c38d16192d0f1362833e62424f424e5da660770dff45f4b951d9cc58bfb9d14559c977d443449bfc4b8783ff9c84065700" assertEquals(expectedSignature, output.signature) @@ -62,20 +62,20 @@ class TestElrondSigner { // Successfully broadcasted https://explorer.multiversx.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) - val accounts = Elrond.Accounts.newBuilder() + val accounts = MultiversX.Accounts.newBuilder() .setSenderNonce(6) .setSender("erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa") .setReceiver("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r") .build() - val genericAction = Elrond.GenericAction.newBuilder() + val genericAction = MultiversX.GenericAction.newBuilder() .setAccounts(accounts) .setValue("0") .setData("unDelegate@0de0b6b3a7640000") .setVersion(1) .build() - val signingInput = Elrond.SigningInput.newBuilder() + val signingInput = MultiversX.SigningInput.newBuilder() .setGenericAction(genericAction) .setGasPrice(1000000000) .setGasLimit(12000000) @@ -83,7 +83,7 @@ class TestElrondSigner { .setPrivateKey(privateKey) .build() - val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) val expectedSignature = "89f9683af92f7b835bff4e1d0dbfcff5245b3367df4d23538eb799e0ad0a90be29ac3bd3598ce55b35b35ebef68bfa5738eed39fd01adc33476f65bd1b966e0b" assertEquals(expectedSignature, output.signature) @@ -95,20 +95,20 @@ class TestElrondSigner { // Successfully broadcasted https://explorer.multiversx.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) - val accounts = Elrond.Accounts.newBuilder() + val accounts = MultiversX.Accounts.newBuilder() .setSenderNonce(1) .setSender("erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa") .setReceiver("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r") .build() - val genericAction = Elrond.GenericAction.newBuilder() + val genericAction = MultiversX.GenericAction.newBuilder() .setAccounts(accounts) .setValue("1") .setData("delegate") .setVersion(1) .build() - val signingInput = Elrond.SigningInput.newBuilder() + val signingInput = MultiversX.SigningInput.newBuilder() .setGenericAction(genericAction) .setGasPrice(1000000000) .setGasLimit(12000000) @@ -116,7 +116,7 @@ class TestElrondSigner { .setPrivateKey(privateKey) .build() - val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) val expectedSignature = "3b9164d47a4e3c0330ae387cd29ba6391f9295acf5e43a16a4a2611645e66e5fa46bf22294ca68fe1948adf45cec8cb47b8792afcdb248bd9adec7c6e6c27108" assertEquals(expectedSignature, output.signature) @@ -127,24 +127,24 @@ class TestElrondSigner { fun signEGLDTransfer() { val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) - val accounts = Elrond.Accounts.newBuilder() + val accounts = MultiversX.Accounts.newBuilder() .setSenderNonce(7) .setSender(aliceBech32) .setReceiver(bobBech32) .build() - val transfer = Elrond.EGLDTransfer.newBuilder() + val transfer = MultiversX.EGLDTransfer.newBuilder() .setAccounts(accounts) .setAmount("1000000000000000000") .build() - val signingInput = Elrond.SigningInput.newBuilder() + val signingInput = MultiversX.SigningInput.newBuilder() .setEgldTransfer(transfer) .setChainId("1") .setPrivateKey(privateKey) .build() - val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) val expectedSignature = "7e1c4c63b88ea72dcf7855a54463b1a424eb357ac3feb4345221e512ce07c7a50afb6d7aec6f480b554e32cf2037082f3bc17263d1394af1f3ef240be53c930b" assertEquals(expectedSignature, output.signature) @@ -155,25 +155,25 @@ class TestElrondSigner { fun signESDTTransfer() { val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) - val accounts = Elrond.Accounts.newBuilder() + val accounts = MultiversX.Accounts.newBuilder() .setSenderNonce(7) .setSender(aliceBech32) .setReceiver(bobBech32) .build() - val transfer = Elrond.ESDTTransfer.newBuilder() + val transfer = MultiversX.ESDTTransfer.newBuilder() .setAccounts(accounts) .setTokenIdentifier("MYTOKEN-1234") .setAmount("10000000000000") .build() - val signingInput = Elrond.SigningInput.newBuilder() + val signingInput = MultiversX.SigningInput.newBuilder() .setEsdtTransfer(transfer) .setChainId("1") .setPrivateKey(privateKey) .build() - val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) val expectedSignature = "9add6d9ac3f1a1fddb07b934e8a73cad3b8c232bdf29d723c1b38ad619905f03e864299d06eb3fe3bbb48a9f1d9b7f14e21dc5eaffe0c87f5718ad0c4198bb0c" val expectedData = "RVNEVFRyYW5zZmVyQDRkNTk1NDRmNGI0NTRlMmQzMTMyMzMzNEAwOTE4NGU3MmEwMDA=" @@ -185,26 +185,26 @@ class TestElrondSigner { fun signESDTNFTTransfer() { val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data()) - val accounts = Elrond.Accounts.newBuilder() + val accounts = MultiversX.Accounts.newBuilder() .setSenderNonce(7) .setSender(aliceBech32) .setReceiver(bobBech32) .build() - val transfer = Elrond.ESDTNFTTransfer.newBuilder() + val transfer = MultiversX.ESDTNFTTransfer.newBuilder() .setAccounts(accounts) .setTokenCollection("LKMEX-aab910") .setTokenNonce(4) .setAmount("184300000000000000") .build() - val signingInput = Elrond.SigningInput.newBuilder() + val signingInput = MultiversX.SigningInput.newBuilder() .setEsdtnftTransfer(transfer) .setChainId("1") .setPrivateKey(privateKey) .build() - val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser()) + val output = AnySigner.sign(signingInput, CoinType.MULTIVERSX, MultiversX.SigningOutput.parser()) val expectedSignature = "cc935685d5b31525e059a16a832cba98dee751983a5a93de4198f6553a2c55f5f1e0b4300fe9077376fa754546da0b0f6697e66462101a209aafd0fc775ab60a" val expectedData = "RVNEVE5GVFRyYW5zZmVyQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAwNEAwMjhlYzNkZmEwMWFjMDAwQDgwNDlkNjM5ZTVhNjk4MGQxY2QyMzkyYWJjY2U0MTAyOWNkYTc0YTE1NjM1MjNhMjAyZjA5NjQxY2MyNjE4Zjg=" diff --git a/include/TrustWalletCore/TWBlockchain.h b/include/TrustWalletCore/TWBlockchain.h index c93bab5e2b9..36daed2499f 100644 --- a/include/TrustWalletCore/TWBlockchain.h +++ b/include/TrustWalletCore/TWBlockchain.h @@ -44,7 +44,7 @@ enum TWBlockchain { TWBlockchainCardano = 30, TWBlockchainNEO = 31, TWBlockchainFilecoin = 32, - TWBlockchainElrondNetwork = 33, + TWBlockchainMultiversX = 33, TWBlockchainOasisNetwork = 34, TWBlockchainDecred = 35, // Bitcoin TWBlockchainZcash = 36, // Bitcoin diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 22a3540c265..0337ee4c6b0 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -88,7 +88,7 @@ enum TWCoinType { TWCoinTypeKusama = 434, TWCoinTypePolkadot = 354, TWCoinTypeFilecoin = 461, - TWCoinTypeElrond = 508, + TWCoinTypeMultiversX = 508, TWCoinTypeBandChain = 494, TWCoinTypeSmartChainLegacy = 10000714, TWCoinTypeSmartChain = 20000714, diff --git a/registry.json b/registry.json index 07081485815..869c99c92bc 100644 --- a/registry.json +++ b/registry.json @@ -1405,12 +1405,11 @@ }, { "id": "elrond", - "name": "Elrond", - "displayName": "MultiversX", + "name": "MultiversX", "coinId": 508, "symbol": "eGLD", "decimals": 18, - "blockchain": "ElrondNetwork", + "blockchain": "MultiversX", "derivation": [ { "path": "m/44'/508'/0'/0'/0'" diff --git a/src/Coin.cpp b/src/Coin.cpp index 167fb0026b2..22930188aaa 100644 --- a/src/Coin.cpp +++ b/src/Coin.cpp @@ -23,7 +23,7 @@ #include "Cosmos/Entry.h" #include "Decred/Entry.h" #include "EOS/Entry.h" -#include "Elrond/Entry.h" +#include "MultiversX/Entry.h" #include "Ethereum/Entry.h" #include "Everscale/Entry.h" #include "FIO/Entry.h" @@ -72,7 +72,7 @@ Binance::Entry binanceDP; Bitcoin::Entry bitcoinDP; Cardano::Entry cardanoDP; Cosmos::Entry cosmosDP; -Elrond::Entry elrondDP; +MultiversX::Entry multiversxDP; EOS::Entry eosDP; Ethereum::Entry ethereumDP; Decred::Entry decredDP; @@ -148,7 +148,7 @@ CoinEntry* coinDispatcher(TWCoinType coinType) { case TWBlockchainCardano: entry = &cardanoDP; break; case TWBlockchainNEO: entry = &neoDP; break; case TWBlockchainFilecoin: entry = &filecoinDP; break; - case TWBlockchainElrondNetwork: entry = &elrondDP; break; + case TWBlockchainMultiversX: entry = &multiversxDP; break; case TWBlockchainOasisNetwork: entry = &oasisDP; break; case TWBlockchainDecred: entry = &decredDP; break; case TWBlockchainGroestlcoin: entry = &groestlcoinDP; break; diff --git a/src/Elrond/Address.cpp b/src/MultiversX/Address.cpp similarity index 89% rename from src/Elrond/Address.cpp rename to src/MultiversX/Address.cpp index 581f95b1e9e..eb6b8a574b1 100644 --- a/src/Elrond/Address.cpp +++ b/src/MultiversX/Address.cpp @@ -8,7 +8,7 @@ #include "Address.h" -namespace TW::Elrond { +namespace TW::MultiversX { const std::string Address::hrp = HRP_ELROND; @@ -16,4 +16,4 @@ bool Address::isValid(const std::string& string) { return Bech32Address::isValid(string, hrp); } -} // namespace TW::Elrond +} // namespace TW::MultiversX diff --git a/src/Elrond/Address.h b/src/MultiversX/Address.h similarity index 76% rename from src/Elrond/Address.h rename to src/MultiversX/Address.h index a638b4af8bd..7827cf1244b 100644 --- a/src/Elrond/Address.h +++ b/src/MultiversX/Address.h @@ -7,32 +7,35 @@ #pragma once #include "Data.h" -#include "../PublicKey.h" #include "../Bech32Address.h" +#include "../PublicKey.h" #include -namespace TW::Elrond { +namespace TW::MultiversX { class Address : public Bech32Address { - public: +public: /// The human-readable part of the address, as defined in "registry.json" static const std::string hrp; // HRP_ELROND /// Determines whether a string makes a valid address. static bool isValid(const std::string& string); - Address() : Bech32Address(hrp) {} + Address() + : Bech32Address(hrp) {} /// Initializes an address with a key hash. - Address(Data keyHash) : Bech32Address(hrp, keyHash) {} + Address(Data keyHash) + : Bech32Address(hrp, keyHash) {} /// Initializes an address with a public key. - Address(const PublicKey& publicKey) : Bech32Address(hrp, publicKey.bytes) {} + Address(const PublicKey& publicKey) + : Bech32Address(hrp, publicKey.bytes) {} static bool decode(const std::string& addr, Address& obj_out) { return Bech32Address::decode(addr, obj_out, hrp); } }; -} // namespace TW::Elrond +} // namespace TW::MultiversX diff --git a/src/Elrond/Codec.cpp b/src/MultiversX/Codec.cpp similarity index 90% rename from src/Elrond/Codec.cpp rename to src/MultiversX/Codec.cpp index a76328f8b39..d66fa38e706 100644 --- a/src/Elrond/Codec.cpp +++ b/src/MultiversX/Codec.cpp @@ -9,7 +9,7 @@ #include "HexCoding.h" #include "uint256.h" -namespace TW::Elrond { +namespace TW::MultiversX { std::string Codec::encodeString(const std::string& value) { std::string encoded = hex(TW::data(value)); @@ -25,7 +25,7 @@ std::string Codec::encodeBigInt(const std::string& value) { return encodeBigInt(uint256_t(value)); } -// For reference, see https://docs.multiversx.com/developers/developer-reference/elrond-serialization-format/#arbitrary-width-big-numbers. +// For reference, see https://docs.multiversx.com/developers/developer-reference/serialization-format#arbitrary-width-big-numbers. std::string Codec::encodeBigInt(uint256_t value) { std::string encoded = hex(store(value)); return encoded; @@ -42,4 +42,4 @@ std::string Codec::encodeAddress(const Address& address) { return encoded; } -} // namespace TW::Elrond +} // namespace TW::MultiversX diff --git a/src/Elrond/Codec.h b/src/MultiversX/Codec.h similarity index 89% rename from src/Elrond/Codec.h rename to src/MultiversX/Codec.h index 18d71f3f223..587f3c70a17 100644 --- a/src/Elrond/Codec.h +++ b/src/MultiversX/Codec.h @@ -9,9 +9,9 @@ #include "Address.h" #include "uint256.h" -namespace TW::Elrond { +namespace TW::MultiversX { -/// A stripped-down variant of the Elrond codec. +/// A stripped-down variant of the MultiversX codec. /// For reference, see: /// - https://docs.multiversx.com/developers/developer-reference/overview /// - https://github.com/multiversx/mx-sdk-erdjs/tree/main/src/smartcontracts/codec @@ -26,4 +26,4 @@ class Codec { static std::string encodeAddress(const Address& address); }; -} // namespace +} // namespace TW::MultiversX diff --git a/src/Elrond/Entry.cpp b/src/MultiversX/Entry.cpp similarity index 92% rename from src/Elrond/Entry.cpp rename to src/MultiversX/Entry.cpp index 6cd504b6008..fef968916f8 100644 --- a/src/Elrond/Entry.cpp +++ b/src/MultiversX/Entry.cpp @@ -12,7 +12,7 @@ using namespace TW; using namespace std; -namespace TW::Elrond { +namespace TW::MultiversX { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { @@ -25,7 +25,7 @@ std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicK Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { Address addr; - if (!Elrond::Address::decode(address, addr)) { + if (!MultiversX::Address::decode(address, addr)) { return Data(); } return addr.getKeyHash(); @@ -39,4 +39,4 @@ string Entry::signJSON([[maybe_unused]] TWCoinType coin, const std::string& json return Signer::signJSON(json, key); } -} // namespace TW::Elrond +} // namespace TW::MultiversX diff --git a/src/Elrond/Entry.h b/src/MultiversX/Entry.h similarity index 90% rename from src/Elrond/Entry.h rename to src/MultiversX/Entry.h index df2a0967e7f..bd5ff2a1409 100644 --- a/src/Elrond/Entry.h +++ b/src/MultiversX/Entry.h @@ -8,9 +8,9 @@ #include "../CoinEntry.h" -namespace TW::Elrond { +namespace TW::MultiversX { -/// Entry point for implementation of Elrond coin. +/// Entry point for implementation of MultiversX coin. /// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file class Entry final : public CoinEntry { public: @@ -22,4 +22,4 @@ class Entry final : public CoinEntry { std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const; }; -} // namespace TW::Elrond +} // namespace TW::MultiversX diff --git a/src/Elrond/GasEstimator.cpp b/src/MultiversX/GasEstimator.cpp similarity index 96% rename from src/Elrond/GasEstimator.cpp rename to src/MultiversX/GasEstimator.cpp index 6db7cbc9580..d57853686ff 100644 --- a/src/Elrond/GasEstimator.cpp +++ b/src/MultiversX/GasEstimator.cpp @@ -6,7 +6,7 @@ #include "GasEstimator.h" -namespace TW::Elrond { +namespace TW::MultiversX { // Additional gas to account for eventual increases in gas requirements (thus avoid breaking changes in clients of TW-core). const uint64_t ADDITIONAL_GAS_FOR_ESDT_TRANSFER = 100000; @@ -47,4 +47,4 @@ uint64_t GasEstimator::forESDTNFTTransfer(size_t dataLength) const { return gasLimit; } -} // namespace TW::Elrond +} // namespace TW::MultiversX diff --git a/src/Elrond/GasEstimator.h b/src/MultiversX/GasEstimator.h similarity index 95% rename from src/Elrond/GasEstimator.h rename to src/MultiversX/GasEstimator.h index 4c14ed434d6..77f848bd9db 100644 --- a/src/Elrond/GasEstimator.h +++ b/src/MultiversX/GasEstimator.h @@ -9,7 +9,7 @@ #include #include "NetworkConfig.h" -namespace TW::Elrond { +namespace TW::MultiversX { class GasEstimator { NetworkConfig networkConfig; diff --git a/src/Elrond/NetworkConfig.cpp b/src/MultiversX/NetworkConfig.cpp similarity index 97% rename from src/Elrond/NetworkConfig.cpp rename to src/MultiversX/NetworkConfig.cpp index ba514e9183f..8b71350b48f 100644 --- a/src/Elrond/NetworkConfig.cpp +++ b/src/MultiversX/NetworkConfig.cpp @@ -8,7 +8,7 @@ #include -namespace TW::Elrond { +namespace TW::MultiversX { NetworkConfig::NetworkConfig() : chainId("1") /* Mainnet */ { @@ -82,4 +82,4 @@ NetworkConfig NetworkConfig::GetByTimestamp(uint64_t timestamp) { return networkConfig; } -} // namespace TW::Elrond +} // namespace TW::MultiversX diff --git a/src/Elrond/NetworkConfig.h b/src/MultiversX/NetworkConfig.h similarity index 90% rename from src/Elrond/NetworkConfig.h rename to src/MultiversX/NetworkConfig.h index 719335b17ed..5df96a75a1a 100644 --- a/src/Elrond/NetworkConfig.h +++ b/src/MultiversX/NetworkConfig.h @@ -8,7 +8,7 @@ #include -namespace TW::Elrond { +namespace TW::MultiversX { /// A "NetworkConfig" object holds the network parameters relevant to creating transactions (e.g. minimum gas limit, minimum gas price). class NetworkConfig { @@ -19,26 +19,27 @@ class NetworkConfig { uint32_t minGasLimit; uint64_t minGasPrice; - /// GasSchedule entries of interest (only one at this moment), according to: https://github.com/ElrondNetwork/elrond-config-mainnet/blob/master/gasSchedules. - /// Here, for the sake of simplicity, we define the gas costs of interest directly in the class "NetworkConfig" + /// GasSchedule entries of interest (only one at this moment), according to: https://github.com/multiversx/mx-chain-mainnet-config/blob/master/gasSchedules. + /// Here, for the sake of simplicity, we define the gas costs of interest directly in the class "NetworkConfig" /// (that is, without defining extra nested structures such as "GasSchedule" and "BuiltInCosts"). uint32_t gasCostESDTTransfer; uint32_t gasCostESDTNFTTransfer; + public: NetworkConfig(); const std::string& getChainId() const; void setChainId(const std::string& value); - + uint32_t getGasPerDataByte() const; void setGasPerDataByte(uint32_t value); - + uint32_t getMinGasLimit() const; void setMinGasLimit(uint32_t value); - + uint64_t getMinGasPrice() const; void setMinGasPrice(uint64_t value); - + uint32_t getGasCostESDTTransfer() const; void setGasCostESDTTransfer(uint32_t value); @@ -51,4 +52,4 @@ class NetworkConfig { static NetworkConfig GetByTimestamp(uint64_t timestamp); }; -} // namespace +} // namespace TW::MultiversX diff --git a/src/Elrond/Serialization.cpp b/src/MultiversX/Serialization.cpp similarity index 88% rename from src/Elrond/Serialization.cpp rename to src/MultiversX/Serialization.cpp index ffe2241bd08..08566e01e21 100644 --- a/src/Elrond/Serialization.cpp +++ b/src/MultiversX/Serialization.cpp @@ -36,7 +36,7 @@ template using sorted_map = std::map; using sorted_json = nlohmann::basic_json; -sorted_json preparePayload(const Elrond::Transaction& transaction) { +sorted_json preparePayload(const MultiversX::Transaction& transaction) { using namespace nlohmann; sorted_json payload{ {"nonce", json(transaction.nonce)}, @@ -69,12 +69,12 @@ sorted_json preparePayload(const Elrond::Transaction& transaction) { return payload; } -std::string Elrond::serializeTransaction(const Elrond::Transaction& transaction) { +std::string MultiversX::serializeTransaction(const MultiversX::Transaction& transaction) { sorted_json payload = preparePayload(transaction); return payload.dump(); } -std::string Elrond::serializeSignedTransaction(const Elrond::Transaction& transaction, std::string signature) { +std::string MultiversX::serializeSignedTransaction(const MultiversX::Transaction& transaction, std::string signature) { sorted_json payload = preparePayload(transaction); payload["signature"] = nlohmann::json(signature); return payload.dump(); diff --git a/src/Elrond/Serialization.h b/src/MultiversX/Serialization.h similarity index 90% rename from src/Elrond/Serialization.h rename to src/MultiversX/Serialization.h index 64023d47213..0058df7d38a 100644 --- a/src/Elrond/Serialization.h +++ b/src/MultiversX/Serialization.h @@ -10,7 +10,7 @@ #include "Transaction.h" #include -namespace TW::Elrond { +namespace TW::MultiversX { using string = std::string; using json = nlohmann::json; @@ -18,4 +18,4 @@ using json = nlohmann::json; string serializeTransaction(const Transaction& transaction); string serializeSignedTransaction(const Transaction& transaction, string encodedSignature); -} // namespace TW::Elrond +} // namespace TW::MultiversX diff --git a/src/Elrond/Signer.cpp b/src/MultiversX/Signer.cpp similarity index 96% rename from src/Elrond/Signer.cpp rename to src/MultiversX/Signer.cpp index f26e6c0460c..a8ec5f20183 100644 --- a/src/Elrond/Signer.cpp +++ b/src/MultiversX/Signer.cpp @@ -12,7 +12,7 @@ #include -namespace TW::Elrond { +namespace TW::MultiversX { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { TransactionFactory factory; @@ -39,4 +39,4 @@ std::string Signer::signJSON(const std::string& json, const Data& key) { return output.encoded(); } -} // namespace TW::Elrond +} // namespace TW::MultiversX diff --git a/src/Elrond/Signer.h b/src/MultiversX/Signer.h similarity index 81% rename from src/Elrond/Signer.h rename to src/MultiversX/Signer.h index df43bf1295d..57260a34ac6 100644 --- a/src/Elrond/Signer.h +++ b/src/MultiversX/Signer.h @@ -8,11 +8,11 @@ #include "Data.h" #include "../PrivateKey.h" -#include "../proto/Elrond.pb.h" +#include "../proto/MultiversX.pb.h" -namespace TW::Elrond { +namespace TW::MultiversX { -/// Helper class that performs Elrond transaction signing. +/// Helper class that performs MultiversX transaction signing. class Signer { public: /// Hide default constructor @@ -25,4 +25,4 @@ class Signer { static std::string signJSON(const std::string& json, const Data& key); }; -} // namespace TW::Elrond +} // namespace TW::MultiversX diff --git a/src/Elrond/Transaction.cpp b/src/MultiversX/Transaction.cpp similarity index 89% rename from src/Elrond/Transaction.cpp rename to src/MultiversX/Transaction.cpp index 24c8373e9c5..92f6db9b403 100644 --- a/src/Elrond/Transaction.cpp +++ b/src/MultiversX/Transaction.cpp @@ -6,11 +6,11 @@ #include "Transaction.h" -namespace TW::Elrond { +namespace TW::MultiversX { Transaction::Transaction() : nonce(0), sender(""), senderUsername(""), receiver(""), receiverUsername(""), value("0"), data(""), gasPrice(0), gasLimit(0), chainID(""), version(0), options(0) { } -} // namespace TW::Elrond +} // namespace TW::MultiversX diff --git a/src/Elrond/Transaction.h b/src/MultiversX/Transaction.h similarity index 91% rename from src/Elrond/Transaction.h rename to src/MultiversX/Transaction.h index a98e7435360..e40885b78bc 100644 --- a/src/Elrond/Transaction.h +++ b/src/MultiversX/Transaction.h @@ -8,7 +8,7 @@ #include -namespace TW::Elrond { +namespace TW::MultiversX { class Transaction { public: @@ -28,4 +28,4 @@ class Transaction { Transaction(); }; -} // namespace +} // namespace TW::MultiversX diff --git a/src/Elrond/TransactionFactory.cpp b/src/MultiversX/TransactionFactory.cpp similarity index 99% rename from src/Elrond/TransactionFactory.cpp rename to src/MultiversX/TransactionFactory.cpp index 4e3a271165e..58822f03944 100644 --- a/src/Elrond/TransactionFactory.cpp +++ b/src/MultiversX/TransactionFactory.cpp @@ -8,7 +8,7 @@ #include "Codec.h" -namespace TW::Elrond { +namespace TW::MultiversX { const int TX_VERSION = 1; @@ -148,4 +148,4 @@ std::string TransactionFactory::prepareFunctionCall(const std::string& function, return result; } -} // namespace TW::Elrond +} // namespace TW::MultiversX diff --git a/src/Elrond/TransactionFactory.h b/src/MultiversX/TransactionFactory.h similarity index 94% rename from src/Elrond/TransactionFactory.h rename to src/MultiversX/TransactionFactory.h index db7ec70e19c..5b66df1ecfd 100644 --- a/src/Elrond/TransactionFactory.h +++ b/src/MultiversX/TransactionFactory.h @@ -6,26 +6,27 @@ #pragma once -#include "../proto/Elrond.pb.h" #include "Address.h" -#include "NetworkConfig.h" #include "GasEstimator.h" +#include "NetworkConfig.h" #include "Transaction.h" #include "uint256.h" +#include "../proto/MultiversX.pb.h" -namespace TW::Elrond { +namespace TW::MultiversX { /// Creates specific transaction objects, wrt. the provided "NetworkConfig". class TransactionFactory { private: NetworkConfig networkConfig; GasEstimator gasEstimator; + public: TransactionFactory(); TransactionFactory(const NetworkConfig& networkConfig); /// Creates the appropriate transaction object, with respect to the "oneof" field (substructure) of Proto::SigningInput. - Transaction create(const Proto::SigningInput &input); + Transaction create(const Proto::SigningInput& input); Transaction fromGenericAction(const Proto::SigningInput& input); @@ -47,6 +48,7 @@ class TransactionFactory { /// /// The fields "token_collection" and "token_nonce" are found as well in the HTTP response of the API call (as "collection" and "nonce", respectively). Transaction fromESDTNFTTransfer(const Proto::SigningInput& input); + private: uint64_t coalesceGasLimit(uint64_t providedGasLimit, uint64_t estimatedGasLimit); uint64_t coalesceGasPrice(uint64_t gasPrice); @@ -54,4 +56,4 @@ class TransactionFactory { std::string prepareFunctionCall(const std::string& function, std::initializer_list arguments); }; -} // namespace +} // namespace TW::MultiversX diff --git a/src/proto/Elrond.proto b/src/proto/MultiversX.proto similarity index 93% rename from src/proto/Elrond.proto rename to src/proto/MultiversX.proto index 9951055fde1..42dfcd26752 100644 --- a/src/proto/Elrond.proto +++ b/src/proto/MultiversX.proto @@ -6,7 +6,7 @@ syntax = "proto3"; -package TW.Elrond.Proto; +package TW.MultiversX.Proto; option java_package = "wallet.core.jni.proto"; // Generic action. Using one of the more specific actions (e.g. transfers, see below) is recommended. @@ -24,8 +24,7 @@ message GenericAction { uint32 version = 4; // Currently, the "options" field should be ignored (not set) by applications using TW Core. - // In the future, TW Core will handle specific transaction options - // (such as the "SignedWithHash" flag, as seen in https://github.com/ElrondNetwork/elrond-go-core/blob/main/core/versioning/txVersionChecker.go) + // In the future, TW Core will handle specific transaction options // when building and signing transactions. uint32 options = 5; } diff --git a/swift/Tests/Blockchains/ElrondTests.swift b/swift/Tests/Blockchains/MultiversXTests.swift similarity index 82% rename from swift/Tests/Blockchains/ElrondTests.swift rename to swift/Tests/Blockchains/MultiversXTests.swift index fa6a64ee3ca..327e3ab6b80 100644 --- a/swift/Tests/Blockchains/ElrondTests.swift +++ b/swift/Tests/Blockchains/MultiversXTests.swift @@ -7,7 +7,7 @@ import WalletCore import XCTest -class ElrondTests: XCTestCase { +class MultiversXTests: XCTestCase { let aliceBech32 = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" let alicePubKeyHex = "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1" @@ -17,8 +17,8 @@ class ElrondTests: XCTestCase { func testAddress() { let key = PrivateKey(data: Data(hexString: aliceSeedHex)!)! let pubkey = key.getPublicKeyEd25519() - let address = AnyAddress(publicKey: pubkey, coin: .elrond) - let addressFromString = AnyAddress(string: aliceBech32, coin: .elrond)! + let address = AnyAddress(publicKey: pubkey, coin: .multiversX) + let addressFromString = AnyAddress(string: aliceBech32, coin: .multiversX)! XCTAssertEqual(pubkey.data.hexString, alicePubKeyHex) XCTAssertEqual(address.description, addressFromString.description) @@ -27,9 +27,9 @@ class ElrondTests: XCTestCase { func testSignGenericAction() { let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)! - let input = ElrondSigningInput.with { - $0.genericAction = ElrondGenericAction.with { - $0.accounts = ElrondAccounts.with { + let input = MultiversXSigningInput.with { + $0.genericAction = MultiversXGenericAction.with { + $0.accounts = MultiversXAccounts.with { $0.senderNonce = 7 $0.sender = aliceBech32 $0.receiver = bobBech32 @@ -44,7 +44,7 @@ class ElrondTests: XCTestCase { $0.privateKey = privateKey.data } - let output: ElrondSigningOutput = AnySigner.sign(input: input, coin: .elrond) + let output: MultiversXSigningOutput = AnySigner.sign(input: input, coin: .multiversX) let expectedSignature = "e8647dae8b16e034d518a1a860c6a6c38d16192d0f1362833e62424f424e5da660770dff45f4b951d9cc58bfb9d14559c977d443449bfc4b8783ff9c84065700" let expectedEncoded = #"{"nonce":7,"value":"0","receiver":"\#(bobBech32)","sender":"\#(aliceBech32)","gasPrice":1000000000,"gasLimit":50000,"data":"Zm9v","chainID":"1","version":1,"signature":"\#(expectedSignature)"}"# @@ -56,9 +56,9 @@ class ElrondTests: XCTestCase { // Successfully broadcasted https://explorer.multiversx.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)! - let input = ElrondSigningInput.with { - $0.genericAction = ElrondGenericAction.with { - $0.accounts = ElrondAccounts.with { + let input = MultiversXSigningInput.with { + $0.genericAction = MultiversXGenericAction.with { + $0.accounts = MultiversXAccounts.with { $0.senderNonce = 6 $0.sender = "erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa" $0.receiver = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r" @@ -73,7 +73,7 @@ class ElrondTests: XCTestCase { $0.privateKey = privateKey.data } - let output: ElrondSigningOutput = AnySigner.sign(input: input, coin: .elrond) + let output: MultiversXSigningOutput = AnySigner.sign(input: input, coin: .multiversX) let expectedSignature = "89f9683af92f7b835bff4e1d0dbfcff5245b3367df4d23538eb799e0ad0a90be29ac3bd3598ce55b35b35ebef68bfa5738eed39fd01adc33476f65bd1b966e0b" let expectedEncoded = #"{"nonce":6,"value":"0","receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r","sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa","gasPrice":1000000000,"gasLimit":12000000,"data":"dW5EZWxlZ2F0ZUAwZGUwYjZiM2E3NjQwMDAw","chainID":"1","version":1,"signature":"\#(expectedSignature)"}"# @@ -85,9 +85,9 @@ class ElrondTests: XCTestCase { // Successfully broadcasted https://explorer.multiversx.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)! - let input = ElrondSigningInput.with { - $0.genericAction = ElrondGenericAction.with { - $0.accounts = ElrondAccounts.with { + let input = MultiversXSigningInput.with { + $0.genericAction = MultiversXGenericAction.with { + $0.accounts = MultiversXAccounts.with { $0.senderNonce = 1 $0.sender = "erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa" $0.receiver = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r" @@ -102,7 +102,7 @@ class ElrondTests: XCTestCase { $0.privateKey = privateKey.data } - let output: ElrondSigningOutput = AnySigner.sign(input: input, coin: .elrond) + let output: MultiversXSigningOutput = AnySigner.sign(input: input, coin: .multiversX) let expectedSignature = "3b9164d47a4e3c0330ae387cd29ba6391f9295acf5e43a16a4a2611645e66e5fa46bf22294ca68fe1948adf45cec8cb47b8792afcdb248bd9adec7c6e6c27108" let expectedEncoded = #"{"nonce":1,"value":"1","receiver":"erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r","sender":"erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa","gasPrice":1000000000,"gasLimit":12000000,"data":"ZGVsZWdhdGU=","chainID":"1","version":1,"signature":"\#(expectedSignature)"}"# @@ -113,9 +113,9 @@ class ElrondTests: XCTestCase { func testSignEGLDTransfer() { let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)! - let input = ElrondSigningInput.with { - $0.egldTransfer = ElrondEGLDTransfer.with { - $0.accounts = ElrondAccounts.with { + let input = MultiversXSigningInput.with { + $0.egldTransfer = MultiversXEGLDTransfer.with { + $0.accounts = MultiversXAccounts.with { $0.senderNonce = 7 $0.sender = aliceBech32 $0.receiver = bobBech32 @@ -126,7 +126,7 @@ class ElrondTests: XCTestCase { $0.privateKey = privateKey.data } - let output: ElrondSigningOutput = AnySigner.sign(input: input, coin: .elrond) + let output: MultiversXSigningOutput = AnySigner.sign(input: input, coin: .multiversX) let expectedSignature = "7e1c4c63b88ea72dcf7855a54463b1a424eb357ac3feb4345221e512ce07c7a50afb6d7aec6f480b554e32cf2037082f3bc17263d1394af1f3ef240be53c930b" let expectedEncoded = #"{"nonce":7,"value":"1000000000000000000","receiver":"\#(bobBech32)","sender":"\#(aliceBech32)","gasPrice":1000000000,"gasLimit":50000,"chainID":"1","version":1,"signature":"\#(expectedSignature)"}"# @@ -137,9 +137,9 @@ class ElrondTests: XCTestCase { func testSignESDTTransfer() { let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)! - let input = ElrondSigningInput.with { - $0.esdtTransfer = ElrondESDTTransfer.with { - $0.accounts = ElrondAccounts.with { + let input = MultiversXSigningInput.with { + $0.esdtTransfer = MultiversXESDTTransfer.with { + $0.accounts = MultiversXAccounts.with { $0.senderNonce = 7 $0.sender = aliceBech32 $0.receiver = bobBech32 @@ -151,7 +151,7 @@ class ElrondTests: XCTestCase { $0.privateKey = privateKey.data } - let output: ElrondSigningOutput = AnySigner.sign(input: input, coin: .elrond) + let output: MultiversXSigningOutput = AnySigner.sign(input: input, coin: .multiversX) let expectedSignature = "9add6d9ac3f1a1fddb07b934e8a73cad3b8c232bdf29d723c1b38ad619905f03e864299d06eb3fe3bbb48a9f1d9b7f14e21dc5eaffe0c87f5718ad0c4198bb0c" let expectedData = "RVNEVFRyYW5zZmVyQDRkNTk1NDRmNGI0NTRlMmQzMTMyMzMzNEAwOTE4NGU3MmEwMDA=" let expectedEncoded = #"{"nonce":7,"value":"0","receiver":"\#(bobBech32)","sender":"\#(aliceBech32)","gasPrice":1000000000,"gasLimit":425000,"data":"\#(expectedData)","chainID":"1","version":1,"signature":"\#(expectedSignature)"}"# @@ -163,9 +163,9 @@ class ElrondTests: XCTestCase { func testSignESDTNFTTransfer() { let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)! - let input = ElrondSigningInput.with { - $0.esdtnftTransfer = ElrondESDTNFTTransfer.with { - $0.accounts = ElrondAccounts.with { + let input = MultiversXSigningInput.with { + $0.esdtnftTransfer = MultiversXESDTNFTTransfer.with { + $0.accounts = MultiversXAccounts.with { $0.senderNonce = 7 $0.sender = aliceBech32 $0.receiver = bobBech32 @@ -178,7 +178,7 @@ class ElrondTests: XCTestCase { $0.privateKey = privateKey.data } - let output: ElrondSigningOutput = AnySigner.sign(input: input, coin: .elrond) + let output: MultiversXSigningOutput = AnySigner.sign(input: input, coin: .multiversX) let expectedSignature = "cc935685d5b31525e059a16a832cba98dee751983a5a93de4198f6553a2c55f5f1e0b4300fe9077376fa754546da0b0f6697e66462101a209aafd0fc775ab60a" let expectedData = "RVNEVE5GVFRyYW5zZmVyQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAwNEAwMjhlYzNkZmEwMWFjMDAwQDgwNDlkNjM5ZTVhNjk4MGQxY2QyMzkyYWJjY2U0MTAyOWNkYTc0YTE1NjM1MjNhMjAyZjA5NjQxY2MyNjE4Zjg=" let expectedEncoded = #"{"nonce":7,"value":"0","receiver":"\#(aliceBech32)","sender":"\#(aliceBech32)","gasPrice":1000000000,"gasLimit":937500,"data":"\#(expectedData)","chainID":"1","version":1,"signature":"\#(expectedSignature)"}"# diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index eced318a140..d641e7150d6 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -64,7 +64,7 @@ class CoinAddressDerivationTests: XCTestCase { case .dogecoin: let expectedResult = "DJRFZNg8jkUtjcpo2zJd92FUAzwRjitw6f" assertCoinDerivation(coin, expectedResult, derivedAddress, address) - case .elrond: + case .multiversX: let expectedResult = "erd1jfcy8aeru6vlx4fe6h3pc3vlpe2cnnur5zetxdhp879yagq7vqvs8na4f8" assertCoinDerivation(coin, expectedResult, derivedAddress, address) case .eos, .wax: diff --git a/tests/chains/Elrond/AddressTests.cpp b/tests/chains/MultiversX/AddressTests.cpp similarity index 86% rename from tests/chains/Elrond/AddressTests.cpp rename to tests/chains/MultiversX/AddressTests.cpp index a96a0f53c1a..01d820489d1 100644 --- a/tests/chains/Elrond/AddressTests.cpp +++ b/tests/chains/MultiversX/AddressTests.cpp @@ -7,7 +7,7 @@ #include #include -#include "Elrond/Address.h" +#include "MultiversX/Address.h" #include "HexCoding.h" #include "PrivateKey.h" #include "PublicKey.h" @@ -15,14 +15,14 @@ using namespace TW; -namespace TW::Elrond::tests { +namespace TW::MultiversX::tests { -TEST(ElrondAddress, Valid) { +TEST(MultiversXAddress, Valid) { ASSERT_TRUE(Address::isValid(ALICE_BECH32)); ASSERT_TRUE(Address::isValid(BOB_BECH32)); } -TEST(ElrondAddress, Invalid) { +TEST(MultiversXAddress, Invalid) { ASSERT_FALSE(Address::isValid("")); ASSERT_FALSE(Address::isValid("foo")); ASSERT_FALSE(Address::isValid("10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr")); @@ -31,7 +31,7 @@ TEST(ElrondAddress, Invalid) { ASSERT_FALSE(Address::isValid(ALICE_PUBKEY_HEX)); } -TEST(ElrondAddress, FromString) { +TEST(MultiversXAddress, FromString) { Address alice, bob, carol; ASSERT_TRUE(Address::decode(ALICE_BECH32, alice)); ASSERT_TRUE(Address::decode(BOB_BECH32, bob)); @@ -40,7 +40,7 @@ TEST(ElrondAddress, FromString) { ASSERT_EQ(BOB_PUBKEY_HEX, hex(bob.getKeyHash())); } -TEST(ElrondAddress, FromData) { +TEST(MultiversXAddress, FromData) { const auto alice = Address(parse_hex(ALICE_PUBKEY_HEX)); const auto bob = Address(parse_hex(BOB_PUBKEY_HEX)); @@ -48,7 +48,7 @@ TEST(ElrondAddress, FromData) { ASSERT_EQ(BOB_BECH32, bob.string()); } -TEST(ElrondAddress, FromPrivateKey) { +TEST(MultiversXAddress, FromPrivateKey) { auto aliceKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); auto alice = Address(aliceKey.getPublicKey(TWPublicKeyTypeED25519)); ASSERT_EQ(ALICE_BECH32, alice.string()); @@ -58,7 +58,7 @@ TEST(ElrondAddress, FromPrivateKey) { ASSERT_EQ(BOB_BECH32, bob.string()); } -TEST(ElrondAddress, FromPublicKey) { +TEST(MultiversXAddress, FromPublicKey) { auto alice = PublicKey(parse_hex(ALICE_PUBKEY_HEX), TWPublicKeyTypeED25519); ASSERT_EQ(ALICE_BECH32, Address(alice).string()); @@ -66,4 +66,4 @@ TEST(ElrondAddress, FromPublicKey) { ASSERT_EQ(BOB_BECH32, Address(bob).string()); } -} // namespace TW::Elrond::tests +} // namespace TW::MultiversX::tests diff --git a/tests/chains/Elrond/SerializationTests.cpp b/tests/chains/MultiversX/SerializationTests.cpp similarity index 87% rename from tests/chains/Elrond/SerializationTests.cpp rename to tests/chains/MultiversX/SerializationTests.cpp index c1a730de8c7..e1fe9e875e4 100644 --- a/tests/chains/Elrond/SerializationTests.cpp +++ b/tests/chains/MultiversX/SerializationTests.cpp @@ -8,15 +8,15 @@ #include #include -#include "Elrond/Serialization.h" +#include "MultiversX/Serialization.h" #include "HexCoding.h" #include "TestAccounts.h" using namespace TW; -namespace TW::Elrond::tests { +namespace TW::MultiversX::tests { -TEST(ElrondSerialization, SignableString) { +TEST(MultiversXSerialization, SignableString) { Transaction transaction; transaction.nonce = 42; transaction.value = "43"; @@ -30,7 +30,7 @@ TEST(ElrondSerialization, SignableString) { ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"bob","sender":"alice","gasPrice":0,"gasLimit":0,"data":"Zm9v","chainID":"1","version":1})", jsonString); } -TEST(ElrondSerialization, SignableStringWithRealData) { +TEST(MultiversXSerialization, SignableStringWithRealData) { Transaction transaction; transaction.nonce = 15; transaction.value = "100"; @@ -47,7 +47,7 @@ TEST(ElrondSerialization, SignableStringWithRealData) { ASSERT_EQ(expected, actual); } -TEST(ElrondSerialization, SignableStringWithoutData) { +TEST(MultiversXSerialization, SignableStringWithoutData) { Transaction transaction; transaction.nonce = 42; transaction.value = "43"; @@ -60,4 +60,4 @@ TEST(ElrondSerialization, SignableStringWithoutData) { ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"abba","sender":"feed","gasPrice":0,"gasLimit":0,"chainID":"1","version":1})", jsonString); } -} // namespace TW::Elrond::tests +} // namespace TW::MultiversX::tests diff --git a/tests/chains/Elrond/SignerTests.cpp b/tests/chains/MultiversX/SignerTests.cpp similarity index 95% rename from tests/chains/Elrond/SignerTests.cpp rename to tests/chains/MultiversX/SignerTests.cpp index 12172fa73d8..a9da1cd485a 100644 --- a/tests/chains/Elrond/SignerTests.cpp +++ b/tests/chains/MultiversX/SignerTests.cpp @@ -8,9 +8,9 @@ #include #include -#include "Elrond/Address.h" -#include "Elrond/Signer.h" -#include "Elrond/Codec.h" +#include "MultiversX/Address.h" +#include "MultiversX/Codec.h" +#include "MultiversX/Signer.h" #include "HexCoding.h" #include "PrivateKey.h" #include "PublicKey.h" @@ -19,9 +19,9 @@ using namespace TW; -namespace TW::Elrond::tests { +namespace TW::MultiversX::tests { -TEST(ElrondSigner, SignGenericAction) { +TEST(MultiversXSigner, SignGenericAction) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); @@ -46,7 +46,7 @@ TEST(ElrondSigner, SignGenericAction) { ASSERT_EQ(expectedSignature, signature); } -TEST(ElrondSigner, SignGenericActionUnDelegate) { +TEST(MultiversXSigner, SignGenericActionUnDelegate) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); @@ -55,7 +55,7 @@ TEST(ElrondSigner, SignGenericActionUnDelegate) { input.mutable_generic_action()->mutable_accounts()->set_sender("erd1aajqh5xjka5fk0c235dwy7qd6lkz2e29tlhy8gncuq0mcr68q34qgswnqa"); input.mutable_generic_action()->mutable_accounts()->set_receiver("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfhllllscrt56r"); input.mutable_generic_action()->set_value("0"); - input.mutable_generic_action()->set_data("unDelegate@" + TW::Elrond::Codec::encodeBigInt("1000000000000000000")); + input.mutable_generic_action()->set_data("unDelegate@" + TW::MultiversX::Codec::encodeBigInt("1000000000000000000")); input.mutable_generic_action()->set_version(1); input.set_gas_price(1000000000); input.set_gas_limit(12000000); @@ -83,7 +83,7 @@ TEST(ElrondSigner, SignGenericActionUnDelegate) { // Successfully broadcasted https://explorer.multiversx.com/transactions/3301ae5a6a77f0ab9ceb5125258f12539a113b0c6787de76a5c5867f2c515d65 } -TEST(ElrondSigner, SignGenericActionRedelegateRewards) { +TEST(MultiversXSigner, SignGenericActionRedelegateRewards) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); @@ -119,7 +119,7 @@ TEST(ElrondSigner, SignGenericActionRedelegateRewards) { ASSERT_EQ(expectedSignature, signature); } -TEST(ElrondSigner, SignGenericActionClaimRewards) { +TEST(MultiversXSigner, SignGenericActionClaimRewards) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); @@ -155,7 +155,7 @@ TEST(ElrondSigner, SignGenericActionClaimRewards) { ASSERT_EQ(expectedSignature, signature); } -TEST(ElrondSigner, SignGenericActionWithdrawStake) { +TEST(MultiversXSigner, SignGenericActionWithdrawStake) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); @@ -192,7 +192,7 @@ TEST(ElrondSigner, SignGenericActionWithdrawStake) { // Need to wait 9 days for broadcasting } -TEST(ElrondSigner, SignGenericActionDelegate) { +TEST(MultiversXSigner, SignGenericActionDelegate) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); @@ -229,7 +229,7 @@ TEST(ElrondSigner, SignGenericActionDelegate) { // Successfully broadcasted https://explorer.multiversx.com/transactions/e5007662780f8ed677b37b156007c24bf60b7366000f66ec3525cfa16a4564e7 } -TEST(ElrondSigner, SignGenericActionJSON) { +TEST(MultiversXSigner, SignGenericActionJSON) { // Shuffle some fields, assume arbitrary order in the input auto input = (boost::format(R"({"genericAction" : {"accounts": {"senderNonce": 7, "receiver": "%1%", "sender": "%2%"}, "data": "foo", "value": "0", "version": 1}, "gasPrice": 1000000000, "gasLimit": 50000, "chainId": "1"})") % BOB_BECH32 % ALICE_BECH32).str(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); @@ -241,7 +241,7 @@ TEST(ElrondSigner, SignGenericActionJSON) { ASSERT_EQ(expectedEncoded, encoded); } -TEST(ElrondSigner, SignWithoutData) { +TEST(MultiversXSigner, SignWithoutData) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); @@ -266,7 +266,7 @@ TEST(ElrondSigner, SignWithoutData) { ASSERT_EQ(expectedEncoded, encoded); } -TEST(ElrondSigner, SignJSONWithoutData) { +TEST(MultiversXSigner, SignJSONWithoutData) { // Shuffle some fields, assume arbitrary order in the input auto input = (boost::format(R"({"genericAction" : {"accounts": {"senderNonce": 0, "receiver": "%1%", "sender": "%2%"}, "value": "0", "version": 1}, "gasPrice": 1000000000, "gasLimit": 50000, "chainId": "1"})") % BOB_BECH32 % ALICE_BECH32).str(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); @@ -278,8 +278,8 @@ TEST(ElrondSigner, SignJSONWithoutData) { ASSERT_EQ(expectedEncoded, encoded); } -TEST(ElrondSigner, SignWithUsernames) { - // https://github.com/ElrondNetwork/elrond-go/blob/master/examples/construction_test.go, scenario "TestConstructTransaction_Usernames". +TEST(MultiversXSigner, SignWithUsernames) { + // https://github.com/multiversx/mx-chain-go/blob/master/examples/construction_test.go, scenario "TestConstructTransaction_Usernames". auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); @@ -313,7 +313,7 @@ TEST(ElrondSigner, SignWithUsernames) { ASSERT_EQ(expectedEncoded, encoded); } -TEST(ElrondSigner, SignWithOptions) { +TEST(MultiversXSigner, SignWithOptions) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); @@ -327,7 +327,6 @@ TEST(ElrondSigner, SignWithOptions) { // We'll set a dummy value on the "options" field (merely an example). // Currently, the "options" field should be ignored (not set) by applications using TW Core. // In the future, TW Core will handle specific transaction options - // (such as the "SignedWithHash" flag, as seen in https://github.com/ElrondNetwork/elrond-go-core/blob/main/core/versioning/txVersionChecker.go) // when building and signing transactions. input.mutable_generic_action()->set_options(42); input.set_gas_price(1000000000); @@ -345,7 +344,7 @@ TEST(ElrondSigner, SignWithOptions) { ASSERT_EQ(expectedSignature, signature); } -TEST(ElrondSigner, SignEGLDTransfer) { +TEST(MultiversXSigner, SignEGLDTransfer) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); @@ -366,7 +365,7 @@ TEST(ElrondSigner, SignEGLDTransfer) { ASSERT_EQ(expectedEncoded, encoded); } -TEST(ElrondSigner, SignESDTTransfer) { +TEST(MultiversXSigner, SignESDTTransfer) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); @@ -391,7 +390,7 @@ TEST(ElrondSigner, SignESDTTransfer) { ASSERT_EQ(expectedEncoded, encoded); } -TEST(ElrondSigner, SignESDTNFTTransfer) { +TEST(MultiversXSigner, SignESDTNFTTransfer) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); @@ -417,4 +416,4 @@ TEST(ElrondSigner, SignESDTNFTTransfer) { ASSERT_EQ(expectedEncoded, encoded); } -} // namespace TW::Elrond::tests +} // namespace TW::MultiversX::tests diff --git a/tests/chains/Elrond/TWAnySignerTests.cpp b/tests/chains/MultiversX/TWAnySignerTests.cpp similarity index 89% rename from tests/chains/Elrond/TWAnySignerTests.cpp rename to tests/chains/MultiversX/TWAnySignerTests.cpp index 09785661191..91a6315b550 100644 --- a/tests/chains/Elrond/TWAnySignerTests.cpp +++ b/tests/chains/MultiversX/TWAnySignerTests.cpp @@ -7,7 +7,7 @@ #include "boost/format.hpp" #include -#include "Elrond/Signer.h" +#include "MultiversX/Signer.h" #include "HexCoding.h" #include "TestAccounts.h" #include "TestUtilities.h" @@ -15,9 +15,9 @@ using namespace TW; -namespace TW::Elrond::tests { +namespace TW::MultiversX::tests { -TEST(TWAnySignerElrond, Sign) { +TEST(TWAnySignerMultiversX, Sign) { auto input = Proto::SigningInput(); auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX)); input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); @@ -33,7 +33,7 @@ TEST(TWAnySignerElrond, Sign) { input.set_chain_id("1"); Proto::SigningOutput output; - ANY_SIGN(input, TWCoinTypeElrond); + ANY_SIGN(input, TWCoinTypeMultiversX); auto signature = output.signature(); auto encoded = output.encoded(); @@ -44,16 +44,16 @@ TEST(TWAnySignerElrond, Sign) { ASSERT_EQ(expectedEncoded, encoded); } -TEST(TWAnySignerElrond, SignJSON) { +TEST(TWAnySignerMultiversX, SignJSON) { // Shuffle some fields, assume arbitrary order in the input auto input = STRING((boost::format(R"({"genericAction" : {"accounts": {"senderNonce": 7, "receiver": "%1%", "sender": "%2%"}, "data": "foo", "value": "0", "version": 1}, "gasPrice": 1000000000, "gasLimit": 50000, "chainId": "1"})") % BOB_BECH32 % ALICE_BECH32).str().c_str()); auto privateKey = DATA(ALICE_SEED_HEX); - auto encoded = WRAPS(TWAnySignerSignJSON(input.get(), privateKey.get(), TWCoinTypeElrond)); + auto encoded = WRAPS(TWAnySignerSignJSON(input.get(), privateKey.get(), TWCoinTypeMultiversX)); auto expectedSignature = "e8647dae8b16e034d518a1a860c6a6c38d16192d0f1362833e62424f424e5da660770dff45f4b951d9cc58bfb9d14559c977d443449bfc4b8783ff9c84065700"; auto expectedEncoded = (boost::format(R"({"nonce":7,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":1000000000,"gasLimit":50000,"data":"Zm9v","chainID":"1","version":1,"signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str(); - ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeElrond)); + ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeMultiversX)); assertStringsEqual(encoded, expectedEncoded.c_str()); } -} // namespace TW::Elrond::tests +} // namespace TW::MultiversX::tests diff --git a/tests/chains/Elrond/TWCoinTypeTests.cpp b/tests/chains/MultiversX/TWCoinTypeTests.cpp similarity index 69% rename from tests/chains/Elrond/TWCoinTypeTests.cpp rename to tests/chains/MultiversX/TWCoinTypeTests.cpp index 5502507c216..2a08eeb0574 100644 --- a/tests/chains/Elrond/TWCoinTypeTests.cpp +++ b/tests/chains/MultiversX/TWCoinTypeTests.cpp @@ -13,19 +13,19 @@ #include -TEST(TWElrondCoinType, TWCoinType) { - auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeElrond)); +TEST(TWMultiversXCoinType, TWCoinType) { + auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeMultiversX)); auto txId = WRAPS(TWStringCreateWithUTF8Bytes("163b46551a74626415074b626d2f37d3c78aef0f6ccb628db434ee65a35ea127")); - auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeElrond, txId.get())); + auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeMultiversX, txId.get())); auto accId = WRAPS(TWStringCreateWithUTF8Bytes("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")); - auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeElrond, accId.get())); - auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeElrond)); - auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeElrond)); + auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeMultiversX, accId.get())); + auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeMultiversX)); + auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeMultiversX)); - ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeElrond), 18); - ASSERT_EQ(TWBlockchainElrondNetwork, TWCoinTypeBlockchain(TWCoinTypeElrond)); - ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeElrond)); - ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeElrond)); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeMultiversX), 18); + ASSERT_EQ(TWBlockchainMultiversX, TWCoinTypeBlockchain(TWCoinTypeMultiversX)); + ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeMultiversX)); + ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeMultiversX)); assertStringsEqual(symbol, "eGLD"); assertStringsEqual(txUrl, "https://explorer.multiversx.com/transactions/163b46551a74626415074b626d2f37d3c78aef0f6ccb628db434ee65a35ea127"); assertStringsEqual(accUrl, "https://explorer.multiversx.com/accounts/erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); diff --git a/tests/chains/Elrond/TestAccounts.h b/tests/chains/MultiversX/TestAccounts.h similarity index 90% rename from tests/chains/Elrond/TestAccounts.h rename to tests/chains/MultiversX/TestAccounts.h index 80e45e638c3..07bfa1aaa95 100644 --- a/tests/chains/Elrond/TestAccounts.h +++ b/tests/chains/MultiversX/TestAccounts.h @@ -7,7 +7,7 @@ #pragma once // Well-known accounts on Testnet & Devnet, -// https://github.com/ElrondNetwork/elrond-sdk-erdpy/tree/main/erdpy/testnet/wallets/users: +// https://github.com/multiversx/mx-sdk-testwallets: const auto ALICE_BECH32 = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"; const auto ALICE_PUBKEY_HEX = "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1"; const auto ALICE_SEED_HEX = "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9"; diff --git a/tests/chains/Elrond/TransactionFactoryTests.cpp b/tests/chains/MultiversX/TransactionFactoryTests.cpp similarity index 94% rename from tests/chains/Elrond/TransactionFactoryTests.cpp rename to tests/chains/MultiversX/TransactionFactoryTests.cpp index 8837d2cab6b..cb8418f5624 100644 --- a/tests/chains/Elrond/TransactionFactoryTests.cpp +++ b/tests/chains/MultiversX/TransactionFactoryTests.cpp @@ -7,12 +7,12 @@ #include #include -#include "Elrond/TransactionFactory.h" +#include "MultiversX/TransactionFactory.h" #include "TestAccounts.h" -namespace TW::Elrond::tests { +namespace TW::MultiversX::tests { -TEST(ElrondTransactionFactory, fromEGLDTransfer) { +TEST(MultiversXTransactionFactory, fromEGLDTransfer) { auto input = Proto::SigningInput(); input.mutable_egld_transfer()->mutable_accounts()->set_sender(ALICE_BECH32); input.mutable_egld_transfer()->mutable_accounts()->set_receiver(BOB_BECH32); @@ -31,7 +31,7 @@ TEST(ElrondTransactionFactory, fromEGLDTransfer) { ASSERT_EQ(1ul, transaction.version); } -TEST(ElrondTransactionFactory, fromESDTTransfer) { +TEST(MultiversXTransactionFactory, fromESDTTransfer) { auto input = Proto::SigningInput(); input.mutable_esdt_transfer()->mutable_accounts()->set_sender_nonce(7); input.mutable_esdt_transfer()->mutable_accounts()->set_sender(ALICE_BECH32); @@ -52,7 +52,7 @@ TEST(ElrondTransactionFactory, fromESDTTransfer) { ASSERT_EQ(1ul, transaction.version); } -TEST(ElrondTransactionFactory, fromESDTNFTTransfer) { +TEST(MultiversXTransactionFactory, fromESDTNFTTransfer) { auto input = Proto::SigningInput(); input.mutable_esdtnft_transfer()->mutable_accounts()->set_sender_nonce(7); input.mutable_esdtnft_transfer()->mutable_accounts()->set_sender(ALICE_BECH32); @@ -74,7 +74,7 @@ TEST(ElrondTransactionFactory, fromESDTNFTTransfer) { ASSERT_EQ(1ul, transaction.version); } -TEST(ElrondTransactionFactory, createTransfersWithProvidedNetworkConfig) { +TEST(MultiversXTransactionFactory, createTransfersWithProvidedNetworkConfig) { NetworkConfig networkConfig; // Set dummy values: @@ -121,7 +121,7 @@ TEST(ElrondTransactionFactory, createTransfersWithProvidedNetworkConfig) { ASSERT_EQ("T", tx3.chainID); } -TEST(ElrondTransactionFactory, createTransfersWithOverriddenNetworkParameters) { +TEST(MultiversXTransactionFactory, createTransfersWithOverriddenNetworkParameters) { Proto::SigningInput signingInputWithEGLDTransfer; signingInputWithEGLDTransfer.set_gas_limit(50500); signingInputWithEGLDTransfer.set_gas_price(1000000001); @@ -155,7 +155,7 @@ TEST(ElrondTransactionFactory, createTransfersWithOverriddenNetworkParameters) { ASSERT_EQ("C", tx3.chainID); } -TEST(ElrondTransactionFactory, create) { +TEST(MultiversXTransactionFactory, create) { Proto::SigningInput signingInputWithGenericAction; signingInputWithGenericAction.mutable_generic_action()->set_data("hello"); @@ -189,4 +189,4 @@ TEST(ElrondTransactionFactory, create) { ASSERT_EQ("ESDTNFTTransfer@4c4b4d45582d616162393130@04@028ec3dfa01ac000@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8", tx4.data); } -} // namespace TW::Elrond::tests +} // namespace TW::MultiversX::tests diff --git a/tests/common/CoinAddressDerivationTests.cpp b/tests/common/CoinAddressDerivationTests.cpp index 7f54228c9a1..3a506f452fd 100644 --- a/tests/common/CoinAddressDerivationTests.cpp +++ b/tests/common/CoinAddressDerivationTests.cpp @@ -148,7 +148,7 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeWAX: EXPECT_EQ(address, "EOS5TrYnZP1RkDSUMzBY4GanCy6AP68kCMdkAb5EACkAwkdgRLShz"); break; - case TWCoinTypeElrond: + case TWCoinTypeMultiversX: EXPECT_EQ(address, "erd1a6f6fan035ttsxdmn04ellxdlnwpgyhg0lhx5vjv92v6rc8xw9yq83344f"); break; case TWCoinTypeEverscale: diff --git a/tests/common/CoinAddressValidationTests.cpp b/tests/common/CoinAddressValidationTests.cpp index 5f899c5c9f5..24912e02e3e 100644 --- a/tests/common/CoinAddressValidationTests.cpp +++ b/tests/common/CoinAddressValidationTests.cpp @@ -374,9 +374,9 @@ TEST(Coin, ValidateAddressVeChain) { EXPECT_EQ(normalizeAddress(TWCoinTypeVeChain, "0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f"), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F"); } -TEST(Coin, ValidateAddressElrond) { - EXPECT_TRUE(validateAddress(TWCoinTypeElrond, "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")); - EXPECT_FALSE(validateAddress(TWCoinTypeElrond, "xerd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")); +TEST(Coin, ValidateAddressMultiversX) { + EXPECT_TRUE(validateAddress(TWCoinTypeMultiversX, "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")); + EXPECT_FALSE(validateAddress(TWCoinTypeMultiversX, "xerd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz")); } TEST(Coin, ValidateAddressOasis) { diff --git a/tests/interface/TWAnyAddressTests.cpp b/tests/interface/TWAnyAddressTests.cpp index f0384bd4c09..8096cd87182 100644 --- a/tests/interface/TWAnyAddressTests.cpp +++ b/tests/interface/TWAnyAddressTests.cpp @@ -141,10 +141,10 @@ TEST(TWAnyAddress, Data) { auto keyHash = WRAPD(TWAnyAddressData(addr.get())); assertHexEqual(keyHash, "172bdf43265c0adfe105a1a8c45b3f406a38362f24"); } - // elrond + // multiversx { auto string = STRING("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"); - auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithString(string.get(), TWCoinTypeElrond)); + auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithString(string.get(), TWCoinTypeMultiversX)); auto pubkey = WRAPD(TWAnyAddressData(addr.get())); assertHexEqual(pubkey, "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293"); } diff --git a/tests/interface/TWCoinTypeTests.cpp b/tests/interface/TWCoinTypeTests.cpp index 5fd55733ef8..cb3ac95c1c9 100644 --- a/tests/interface/TWCoinTypeTests.cpp +++ b/tests/interface/TWCoinTypeTests.cpp @@ -28,7 +28,7 @@ TEST(TWCoinType, TWPurpose) { ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeBandChain)); ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeBluzelle)); ASSERT_EQ(TWPurposeBIP1852, TWCoinTypePurpose(TWCoinTypeCardano)); - ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeElrond)); + ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeMultiversX)); ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeOasis)); ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeTHORChain)); ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeCryptoOrg)); @@ -100,7 +100,7 @@ TEST(TWCoinType, TWPublicKeyType) { ASSERT_EQ(TWPublicKeyTypeSECP256k1, TWCoinTypePublicKeyType(TWCoinTypeBandChain)); ASSERT_EQ(TWPublicKeyTypeSECP256k1, TWCoinTypePublicKeyType(TWCoinTypeBluzelle)); ASSERT_EQ(TWPublicKeyTypeED25519Cardano, TWCoinTypePublicKeyType(TWCoinTypeCardano)); - ASSERT_EQ(TWPublicKeyTypeED25519, TWCoinTypePublicKeyType(TWCoinTypeElrond)); + ASSERT_EQ(TWPublicKeyTypeED25519, TWCoinTypePublicKeyType(TWCoinTypeMultiversX)); ASSERT_EQ(TWPublicKeyTypeED25519, TWCoinTypePublicKeyType(TWCoinTypeOasis)); ASSERT_EQ(TWPublicKeyTypeSECP256k1, TWCoinTypePublicKeyType(TWCoinTypeTHORChain)); ASSERT_EQ(TWPublicKeyTypeSECP256k1, TWCoinTypePublicKeyType(TWCoinTypeCryptoOrg)); diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp index a73b5f44bff..147ecad674e 100644 --- a/tests/interface/TWHDWalletTests.cpp +++ b/tests/interface/TWHDWalletTests.cpp @@ -286,11 +286,11 @@ TEST(HDWallet, DeriveAlgorand) { assertHexEqual(privateKeyData, "ce0b7ac644e2b7d9d14d3928b11643f43e48c33d3e328d059fef8add7f070e82"); } -TEST(HDWallet, DeriveElrond) { +TEST(HDWallet, DeriveMultiversX) { auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(gWords.get(), gPassphrase.get())); - auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeElrond)); + auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeMultiversX)); auto privateKeyData = WRAPD(TWPrivateKeyData(privateKey.get())); - auto address = WRAPS(TWCoinTypeDeriveAddress(TWCoinTypeElrond, privateKey.get())); + auto address = WRAPS(TWCoinTypeDeriveAddress(TWCoinTypeMultiversX, privateKey.get())); assertHexEqual(privateKeyData, "0eb593141de897d60a0883320793eb49e63d556ccdf783a87ec014f150d50453"); assertStringsEqual(address, "erd1a6l7q9cfvrgr80xuzm37tapdr4zm3mwrtl6vt8f45df45x7eadfs8ds5vv"); diff --git a/tests/interface/TWHRPTests.cpp b/tests/interface/TWHRPTests.cpp index 22195dcd3e0..7946c79c9e5 100644 --- a/tests/interface/TWHRPTests.cpp +++ b/tests/interface/TWHRPTests.cpp @@ -30,7 +30,7 @@ TEST(TWHRP, StringForHRP) { ASSERT_STREQ(stringForHRP(TWHRPBandChain), "band"); ASSERT_STREQ(stringForHRP(TWHRPBluzelle), "bluzelle"); ASSERT_STREQ(stringForHRP(TWHRPCardano), "addr"); - ASSERT_STREQ(stringForHRP(TWHRPElrond), "erd"); + ASSERT_STREQ(stringForHRP(TWHRPMultiversX), "erd"); ASSERT_STREQ(stringForHRP(TWHRPOasis), "oasis"); ASSERT_STREQ(stringForHRP(TWHRPTHORChain), "thor"); ASSERT_STREQ(stringForHRP(TWHRPCryptoOrg), "cro"); @@ -56,7 +56,7 @@ TEST(TWHRP, HRPForString) { ASSERT_EQ(hrpForString("kava"), TWHRPKava); ASSERT_EQ(hrpForString("band"), TWHRPBandChain); ASSERT_EQ(hrpForString("addr"), TWHRPCardano); - ASSERT_EQ(hrpForString("erd"), TWHRPElrond); + ASSERT_EQ(hrpForString("erd"), TWHRPMultiversX); ASSERT_EQ(hrpForString("oasis"), TWHRPOasis); ASSERT_EQ(hrpForString("thor"), TWHRPTHORChain); ASSERT_EQ(hrpForString("bluzelle"), TWHRPBluzelle); @@ -84,7 +84,7 @@ TEST(TWHPR, HPRByCoinType) { ASSERT_EQ(TWHRPBandChain, TWCoinTypeHRP(TWCoinTypeBandChain)); ASSERT_EQ(TWHRPBluzelle, TWCoinTypeHRP(TWCoinTypeBluzelle)); ASSERT_EQ(TWHRPCardano, TWCoinTypeHRP(TWCoinTypeCardano)); - ASSERT_EQ(TWHRPElrond, TWCoinTypeHRP(TWCoinTypeElrond)); + ASSERT_EQ(TWHRPMultiversX, TWCoinTypeHRP(TWCoinTypeMultiversX)); ASSERT_EQ(TWHRPOasis, TWCoinTypeHRP(TWCoinTypeOasis)); ASSERT_EQ(TWHRPTHORChain, TWCoinTypeHRP(TWCoinTypeTHORChain)); ASSERT_EQ(TWHRPCryptoOrg, TWCoinTypeHRP(TWCoinTypeCryptoOrg)); From df8d72046a989f3b2f1c25013d94262e1737a936 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 3 Feb 2023 11:58:04 +0100 Subject: [PATCH 183/497] feat(codegen): mark java class as final to avoid kt doc confusion (#2881) --- codegen/lib/templates/java/class.erb | 4 ++-- codegen/lib/templates/java/struct.erb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/codegen/lib/templates/java/class.erb b/codegen/lib/templates/java/class.erb index 69cd027f403..fa491ff2560 100644 --- a/codegen/lib/templates/java/class.erb +++ b/codegen/lib/templates/java/class.erb @@ -5,9 +5,9 @@ import java.util.HashSet; <% equal = entity.static_methods.detect{ |i| i.name == 'Equal' } -%> <%= entity.comment %> <% if !less.nil? && !equal.nil? -%> -public class <%= entity.name %> implements Comparable<<%= entity.name %>> { +public final class <%= entity.name %> implements Comparable<<%= entity.name %>> { <% else -%> -public class <%= entity.name %> { +public final class <%= entity.name %> { <% end -%> private long nativeHandle; diff --git a/codegen/lib/templates/java/struct.erb b/codegen/lib/templates/java/struct.erb index bb57cf25017..6f09dda87d2 100644 --- a/codegen/lib/templates/java/struct.erb +++ b/codegen/lib/templates/java/struct.erb @@ -4,9 +4,9 @@ import java.security.InvalidParameterException; <% equal = entity.static_methods.detect{ |i| i.name == 'Equal' } -%> <%= entity.comment %> <% if !less.nil? && !equal.nil? -%> -public class <%= entity.name %> implements Comparable<<%= entity.name %>> { +public final class <%= entity.name %> implements Comparable<<%= entity.name %>> { <% else -%> -public class <%= entity.name %> { +public final class <%= entity.name %> { <% end -%> private byte[] bytes; From c2dae8abc67d7385a595d484b39193b7805242e1 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 3 Feb 2023 19:59:52 +0900 Subject: [PATCH 184/497] Fix empty lock script data for Flux (zelcash) (#2905) --- .github/workflows/linux-ci-sonarcloud.yml | 4 ++-- src/Bitcoin/Script.cpp | 1 + swift/Tests/Blockchains/ZcashTests.swift | 8 ++++++++ tools/install-rust-dependencies | 6 +++--- tools/ios-build | 4 ++-- tools/rust-bindgen | 4 +++- 6 files changed, 19 insertions(+), 8 deletions(-) diff --git a/.github/workflows/linux-ci-sonarcloud.yml b/.github/workflows/linux-ci-sonarcloud.yml index 662c53dde90..8941656e9b5 100644 --- a/.github/workflows/linux-ci-sonarcloud.yml +++ b/.github/workflows/linux-ci-sonarcloud.yml @@ -14,8 +14,8 @@ jobs: - uses: actions/checkout@v2 - name: Install system dependencies run: | - # build-essential clang-14 libc++-dev libc++abi-dev ruby-full cmake - sudo apt-get update && sudo apt-get install ninja-build lcov llvm-14 clang-tidy-14 libboost-all-dev --fix-missing + tools/install-sys-dependencies-linux + tools/install-rust-dependencies - name: Cache internal dependencies id: internal_cache uses: actions/cache@v1.1.2 diff --git a/src/Bitcoin/Script.cpp b/src/Bitcoin/Script.cpp index 407a8e5152e..08bbaa042f3 100644 --- a/src/Bitcoin/Script.cpp +++ b/src/Bitcoin/Script.cpp @@ -376,6 +376,7 @@ Script Script::lockScriptForAddress(const std::string& string, enum TWCoinType c return {}; case TWCoinTypeZcash: + case TWCoinTypeZelcash: if (Zcash::TAddress::isValid(string)) { auto address = Zcash::TAddress(string); auto data = Data(); diff --git a/swift/Tests/Blockchains/ZcashTests.swift b/swift/Tests/Blockchains/ZcashTests.swift index bd7a861a0f4..92229c34186 100644 --- a/swift/Tests/Blockchains/ZcashTests.swift +++ b/swift/Tests/Blockchains/ZcashTests.swift @@ -74,4 +74,12 @@ class ZcashTests: XCTestCase { XCTAssertEqual(output.error, TW_Common_Proto_SigningError.ok) XCTAssertEqual(output.encoded.hexString, "0400008085202f890153685b8809efc50dd7d5cb0906b307a1b8aa5157baa5fc1bd6fe2d0344dd193a000000006b483045022100ca0be9f37a4975432a52bb65b25e483f6f93d577955290bb7fb0060a93bfc92002203e0627dff004d3c72a957dc9f8e4e0e696e69d125e4d8e275d119001924d3b48012103b243171fae5516d1dc15f9178cfcc5fdc67b0a883055c117b01ba8af29b953f6ffffffff0140720700000000001976a91449964a736f3713d64283fd0018626ba50091c7e988ac00000000000000000000000000000000000000") } + + func testLockScript() { + let script = BitcoinScript.lockScriptForAddress(address: "t1NsqaL1G2XD6xWfVmeAi9gLUVFct59zJu4", coin: .zcash) + XCTAssertTrue(!script.data.isEmpty) + + let script2 = BitcoinScript.lockScriptForAddress(address: "t1XeXHdaaXbdEaBCz1cMib5rvg34RjTWR6N", coin: .zelcash) + XCTAssertTrue(!script2.data.isEmpty) + } } diff --git a/tools/install-rust-dependencies b/tools/install-rust-dependencies index b2356e561d6..911065f4ce2 100755 --- a/tools/install-rust-dependencies +++ b/tools/install-rust-dependencies @@ -6,8 +6,8 @@ if [[ `uname` == "Darwin" ]]; then rustup update rustup toolchain install nightly rustup default nightly - rustup toolchain install nightly-x86_64-apple-darwin - rustup toolchain install nightly-aarch64-apple-darwin + rustup toolchain install nightly-x86_64-apple-darwin --force-non-host + rustup toolchain install nightly-aarch64-apple-darwin --force-non-host rustup component add rust-src --toolchain nightly-aarch64-apple-darwin rustup component add rust-src --toolchain nightly-x86_64-apple-darwin fi @@ -17,7 +17,7 @@ rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-and # iOS rustup target add aarch64-apple-darwin x86_64-apple-darwin # macOS -rustup target add x86_64-apple-ios aarch64-apple-ios-sim aarch64-apple-ios +rustup target add x86_64-apple-ios aarch64-apple-ios-sim aarch64-apple-ios # Wasm rustup target add wasm32-unknown-emscripten diff --git a/tools/ios-build b/tools/ios-build index 8e12031289e..ace228be684 100755 --- a/tools/ios-build +++ b/tools/ios-build @@ -47,13 +47,13 @@ create_xc_framework() { xcodebuild -create-xcframework -output $BUILD_FOLDER/$FRAMEWORK.xcframework \ -framework $BUILD_FOLDER/ios-arm64.xcarchive/Products/Library/Frameworks/$FRAMEWORK.framework \ -framework $BUILD_FOLDER/ios-arm64_x86_64-simulator.xcarchive/Products/Library/Frameworks/$FRAMEWORK.framework \ - -framework $BUILD_FOLDER/ios-x86_64_arm64-maccatalyst.xcarchive/Products/Library/Frameworks/$FRAMEWORK.framework \ -framework $BUILD_FOLDER/macos-arm64_x86_64.xcarchive/Products/Library/Frameworks/$FRAMEWORK.framework } main() { init - build_mac_x64_arm64 && build_ios_mac_catalyst + build_mac_x64_arm64 + #build_ios_mac_catalyst build_ios_arm64 && build_ios_simulator create_xc_framework } diff --git a/tools/rust-bindgen b/tools/rust-bindgen index ab885868d1c..c866a43b2ee 100755 --- a/tools/rust-bindgen +++ b/tools/rust-bindgen @@ -1,5 +1,7 @@ #!/bin/bash +set -e + TARGET_NAME="libwallet_core_rs.a" TARGET_XCFRAMEWORK_NAME=../swift/WalletCoreRs.xcframework BUILD_FOLDER=../build/local @@ -8,7 +10,7 @@ HEADER_NAME="WalletCoreRSBindgen.h" create_xc_framework() { rm -rf $TARGET_XCFRAMEWORK_NAME - xcodebuild -create-xcframework -library $BUILD_FOLDER/$TARGET_NAME -library $BUILD_FOLDER/darwin_universal/$TARGET_NAME -library $BUILD_FOLDER/aarch64-apple-ios/release/$TARGET_NAME -library $BUILD_FOLDER/catalyst/$TARGET_NAME -output $TARGET_XCFRAMEWORK_NAME + xcodebuild -create-xcframework -library $BUILD_FOLDER/$TARGET_NAME -library $BUILD_FOLDER/darwin_universal/$TARGET_NAME -library $BUILD_FOLDER/aarch64-apple-ios/release/$TARGET_NAME -output $TARGET_XCFRAMEWORK_NAME } cd rust From a068cc9d45a3beaee9fdecb57261b22c87018796 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 3 Feb 2023 16:37:31 +0100 Subject: [PATCH 185/497] feat(ios-build): remove catalyst for fastlane (#2906) --- swift/common-xcframework.yml | 2 +- swift/project.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/common-xcframework.yml b/swift/common-xcframework.yml index dae0d4b55c7..d556db5dcdc 100644 --- a/swift/common-xcframework.yml +++ b/swift/common-xcframework.yml @@ -45,7 +45,7 @@ targets: - framework: WalletCoreRs.xcframework settings: SKIP_INSTALL: false - SUPPORTS_MACCATALYST: true + SUPPORTS_MACCATALYST: false INFOPLIST_FILE: 'Info.plist' CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION: YES_ERROR CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER: $(inherited) false diff --git a/swift/project.yml b/swift/project.yml index df46f6a29e5..69afe8dff90 100644 --- a/swift/project.yml +++ b/swift/project.yml @@ -45,7 +45,7 @@ targets: gatherCoverageData: true settings: SKIP_INSTALL: false - SUPPORTS_MACCATALYST: true + SUPPORTS_MACCATALYST: false DEBUG_INFORMATION_FORMAT: dwarf-with-dsym BUILD_LIBRARY_FOR_DISTRIBUTION: true INFOPLIST_FILE: 'Info.plist' From 9dd8f12a5b0f47a1afc726d621c8907ec357c02b Mon Sep 17 00:00:00 2001 From: Ruslan Serebriakov Date: Mon, 6 Feb 2023 04:26:20 +0000 Subject: [PATCH 186/497] [ERC4337] Transactions support (#2891) --- .../ethereum/TestEthereumTransactionSigner.kt | 231 +++++++++++++ src/Ethereum/EIP4337.cpp | 39 ++- src/Ethereum/EIP4337.h | 4 + src/Ethereum/MessageSigner.cpp | 20 +- src/Ethereum/MessageSigner.h | 1 + src/Ethereum/Signer.cpp | 137 ++++++++ src/Ethereum/Signer.h | 4 + src/Ethereum/Transaction.cpp | 192 ++++++++++- src/Ethereum/Transaction.h | 63 ++++ src/proto/Ethereum.proto | 35 +- swift/Tests/Blockchains/EthereumTests.swift | 261 ++++++++++++++- tests/chains/Ethereum/EIP4337Tests.cpp | 20 ++ tests/chains/Ethereum/SignerTests.cpp | 227 +++++++++++++ tests/chains/Ethereum/TWAnySignerTests.cpp | 315 ++++++++++++++++++ 14 files changed, 1509 insertions(+), 40 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumTransactionSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumTransactionSigner.kt index 61a6b9a42df..ed4c5a3d88f 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumTransactionSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumTransactionSigner.kt @@ -229,4 +229,235 @@ class TestEthereumTransactionSigner { assertEquals("f86a8084d693a400825208947d8bf18c7ce84b3e175b339c4ca93aed1dd166f1870348bca5a160008025a0fe5802b49e04c6b1705088310e133605ed8b549811a18968ad409ea02ad79f21a05bf845646fb1e1b9365f63a7fd5eb5e984094e3ed35c3bed7361aebbcbf41f10", result) } + + // EIP4337 + @Test + fun testEIP4337TransactionSigningAccountNotDeployed() { + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + privateKey = ByteString.copyFrom(PrivateKey("0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8".toHexByteArray()).data()) + chainId = ByteString.copyFrom("0x5".toHexByteArray()) + nonce = ByteString.copyFrom("0x0".toHexByteArray()) + toAddress = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a" + txMode = TransactionMode.UserOp + + gasLimit = ByteString.copyFrom("0x5580".toHexByteArray()) + maxFeePerGas = ByteString.copyFrom("0x01952f1f85".toHexByteArray()) + maxInclusionFeePerGas = ByteString.copyFrom("0x0f".toHexByteArray()) + + userOperation = Ethereum.UserOperation.newBuilder().apply { + entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53" + accountFactory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92" + accountLogic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620" + owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238" + isAccountDeployed = false + + preVerificationGas = ByteString.copyFrom("0xbc18".toHexByteArray()) + verificationGasLimit = ByteString.copyFrom("0x073272".toHexByteArray()) + }.build() + + transaction = Ethereum.Transaction.newBuilder().apply { + transfer = Ethereum.Transaction.Transfer.newBuilder().apply { + amount = ByteString.copyFrom("0x2386f26fc10000".toHexByteArray()) + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + assertEquals(output.encoded.toStringUtf8(), "{\"callData\":\"0xb61d27f6000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"21888\",\"initCode\":\"0x5a87209b755781cf65feeedd3855ade0317f4a925fbfb9cf00000000000000000000000078d9c32b96bb872d66d51818227563f44e67e2380000000000000000000000000000000000000000000000000000000000000000\",\"maxFeePerGas\":\"6797860741\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"0\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"48152\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0x1560b19d17613ec8580cb0feaf7ac2953771404c5bd7830f585e5062e6ddd4b82ae3bb8dbddb659c0300e8009857b5c77501e1cfd5bbab48d03de0ea7207d07c1b\",\"verificationGasLimit\":\"471666\"}"); + } + + @Test + fun testEIP4337TransactionSigningAccountDeployed() { + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + privateKey = ByteString.copyFrom(PrivateKey("0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8".toHexByteArray()).data()) + chainId = ByteString.copyFrom("0x5".toHexByteArray()) + nonce = ByteString.copyFrom("0x1".toHexByteArray()) + + toAddress = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a" + txMode = TransactionMode.UserOp + + gasLimit = ByteString.copyFrom("0x9d55".toHexByteArray()) + maxFeePerGas = ByteString.copyFrom("0x1a339c9e9".toHexByteArray()) + maxInclusionFeePerGas = ByteString.copyFrom("0x0f".toHexByteArray()) + + userOperation = Ethereum.UserOperation.newBuilder().apply { + entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53" + accountFactory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92" + accountLogic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620" + owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238" + isAccountDeployed = true + + preVerificationGas = ByteString.copyFrom("0xb708".toHexByteArray()) + verificationGasLimit = ByteString.copyFrom("0x186a0".toHexByteArray()) + }.build() + + transaction = Ethereum.Transaction.newBuilder().apply { + transfer = Ethereum.Transaction.Transfer.newBuilder().apply { + amount = ByteString.copyFrom("0x2386f26fc10000".toHexByteArray()) + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + assertEquals(output.encoded.toStringUtf8(), "{\"callData\":\"0xb61d27f6000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"40277\",\"initCode\":\"0x\",\"maxFeePerGas\":\"7033440745\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"1\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"46856\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0xaed2011e5cf267de495b38ecf86ad6f1d4c05217a99e59f47e8d52ba3d41c10144785893fa3e7c116a054999e3902fc2771064d0545148bc49f6d7c827fc7a9a1c\",\"verificationGasLimit\":\"100000\"}"); + } + + @Test + fun testEIP4337ERC20TransferAccountDeployed() { + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + privateKey = ByteString.copyFrom(PrivateKey("0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8".toHexByteArray()).data()) + chainId = ByteString.copyFrom("0x5".toHexByteArray()) + nonce = ByteString.copyFrom("0x6".toHexByteArray()) + toAddress = "0x98339d8c260052b7ad81c28c16c0b98420f2b46a" + txMode = TransactionMode.UserOp + + gasLimit = ByteString.copyFrom("0xf78e".toHexByteArray()) + maxFeePerGas = ByteString.copyFrom("0x168ad5950f".toHexByteArray()) + maxInclusionFeePerGas = ByteString.copyFrom("0x0f".toHexByteArray()) + + userOperation = Ethereum.UserOperation.newBuilder().apply { + entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53" + accountFactory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92" + accountLogic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620" + owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238" + isAccountDeployed = true + + preVerificationGas = ByteString.copyFrom("0xbb10".toHexByteArray()) + verificationGasLimit = ByteString.copyFrom("0x186a0".toHexByteArray()) + }.build() + + transaction = Ethereum.Transaction.newBuilder().apply { + erc20Transfer = Ethereum.Transaction.ERC20Transfer.newBuilder().apply { + amount = ByteString.copyFrom("0x186a0".toHexByteArray()) + to = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a" + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + assertEquals(output.encoded.toStringUtf8(), "{\"callData\":\"0xb61d27f600000000000000000000000098339d8c260052b7ad81c28c16c0b98420f2b46a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a00000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"63374\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"6\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"47888\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0xd006c93d6a8753b5e7c1e6349de0dea34eab2e7a533106e0f2e1a3a3b013c8e97b007546dab9d7b8fc471ad14ff2e8aa351dc4f1ecb63bf20f33858dc7366cbe1c\",\"verificationGasLimit\":\"100000\"}"); + } + + @Test + fun testEIP4337ERC20ApproveAccountDeployed() { + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + privateKey = ByteString.copyFrom(PrivateKey("0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8".toHexByteArray()).data()) + chainId = ByteString.copyFrom("0x5".toHexByteArray()) + nonce = ByteString.copyFrom("0x9".toHexByteArray()) + + toAddress = "0x98339d8c260052b7ad81c28c16c0b98420f2b46a" + txMode = TransactionMode.UserOp + + gasLimit = ByteString.copyFrom("0xf78e".toHexByteArray()) + maxFeePerGas = ByteString.copyFrom("0x168ad5950f".toHexByteArray()) + maxInclusionFeePerGas = ByteString.copyFrom("0x0f".toHexByteArray()) + + userOperation = Ethereum.UserOperation.newBuilder().apply { + entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53" + accountFactory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92" + accountLogic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620" + owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238" + isAccountDeployed = true + + preVerificationGas = ByteString.copyFrom("0xbb10".toHexByteArray()) + verificationGasLimit = ByteString.copyFrom("0x186a0".toHexByteArray()) + }.build() + + transaction = Ethereum.Transaction.newBuilder().apply { + erc20Approve = Ethereum.Transaction.ERC20Approve.newBuilder().apply { + amount = ByteString.copyFrom("0x186a0".toHexByteArray()) + spender = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a" + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + assertEquals(output.encoded.toStringUtf8(), "{\"callData\":\"0xb61d27f600000000000000000000000098339d8c260052b7ad81c28c16c0b98420f2b46a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a00000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"63374\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"9\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"47888\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0x262a67dd8cf3d16a72b7809b3b5ed55e9f4c2b93eedd5a3c6be035fbbd7111164464ec933d0fdfa359e266e318f3ac22702ae428ce14fc142e4475603e6ec15e1c\",\"verificationGasLimit\":\"100000\"}"); + } + + @Test + fun testEIP4337ERC721TransferAccountDeployed() { + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + privateKey = ByteString.copyFrom(PrivateKey("0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8".toHexByteArray()).data()) + chainId = ByteString.copyFrom("0x5".toHexByteArray()) + nonce = ByteString.copyFrom("0xc".toHexByteArray()) + toAddress = "0xf5de760f2e916647fd766b4ad9e85ff943ce3a2b" + txMode = TransactionMode.UserOp + + gasLimit = ByteString.copyFrom("0x60B378".toHexByteArray()) + maxFeePerGas = ByteString.copyFrom("0x168ad5950f".toHexByteArray()) + maxInclusionFeePerGas = ByteString.copyFrom("0x0f".toHexByteArray()) + + userOperation = Ethereum.UserOperation.newBuilder().apply { + entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53" + accountFactory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92" + accountLogic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620" + owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238" + isAccountDeployed = true + + preVerificationGas = ByteString.copyFrom("0xC34F".toHexByteArray()) + verificationGasLimit = ByteString.copyFrom("0x16E360".toHexByteArray()) + }.build() + + transaction = Ethereum.Transaction.newBuilder().apply { + erc721Transfer = Ethereum.Transaction.ERC721Transfer.newBuilder().apply { + tokenId = ByteString.copyFrom("0x2A8E57".toHexByteArray()) + from = "0x8cE23B8769ac01d0df0d5f47Be1A38FeA97F3879" + to = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a" + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + assertEquals(output.encoded.toStringUtf8(), "{\"callData\":\"0xb61d27f6000000000000000000000000f5de760f2e916647fd766b4ad9e85ff943ce3a2b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000006423b872dd0000000000000000000000008ce23b8769ac01d0df0d5f47be1a38fea97f3879000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a00000000000000000000000000000000000000000000000000000000002a8e5700000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"6337400\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"12\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"49999\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0x5951cc161a4d60d6b59503efb93e446f5d1a2e3a41d4503ba6393bcf2a2637340d0a865ed5d4d7650a68cbb95915eaa7ed54fd2c42b4bf7c83376f5c5d70691d1b\",\"verificationGasLimit\":\"1500000\"}"); + } + + @Test + fun testEIP4337ERC1155TransferAccountDeployed() { + val signingInput = Ethereum.SigningInput.newBuilder() + signingInput.apply { + privateKey = ByteString.copyFrom(PrivateKey("0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8".toHexByteArray()).data()) + chainId = ByteString.copyFrom("0x5".toHexByteArray()) + nonce = ByteString.copyFrom("0x0".toHexByteArray()) + toAddress = "0x428ce4b916332e1afccfddce08baecc97cb40b12" + txMode = TransactionMode.UserOp + + gasLimit = ByteString.copyFrom("0x60B378".toHexByteArray()) + maxFeePerGas = ByteString.copyFrom("0x168ad5950f".toHexByteArray()) + maxInclusionFeePerGas = ByteString.copyFrom("0x0f".toHexByteArray()) + + userOperation = Ethereum.UserOperation.newBuilder().apply { + entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53" + accountFactory = "0x76627b8D1E01fAF0C73B69625BC1fCb8FA19a2AD" + accountLogic = "0x510ab68bd111ce7115df797118b0334d727d564b" + owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238" + isAccountDeployed = true + + preVerificationGas = ByteString.copyFrom("0xC738".toHexByteArray()) + verificationGasLimit = ByteString.copyFrom("0x16E360".toHexByteArray()) + }.build() + + transaction = Ethereum.Transaction.newBuilder().apply { + erc1155Transfer = Ethereum.Transaction.ERC1155Transfer.newBuilder().apply { + tokenId = ByteString.copyFrom("0x01".toHexByteArray()) + from = "0x8c560E00680b973645900528EDe71a99b8d4dca8" + to = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a" + }.build() + }.build() + } + + val output = AnySigner.sign(signingInput.build(), ETHEREUM, SigningOutput.parser()) + + assertEquals(output.encoded.toStringUtf8(), "{\"callData\":\"0xb61d27f6000000000000000000000000428ce4b916332e1afccfddce08baecc97cb40b120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c4f242432a0000000000000000000000008c560e00680b973645900528ede71a99b8d4dca8000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"6337400\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"0\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"51000\",\"sender\":\"0x8c560e00680b973645900528ede71a99b8d4dca8\",\"signature\":\"0xaae38bcf9f946921541b44c2a66596968beecb9420471e2c9c531f758a2d652930ffdeeab95742e57e8520fb5c8ca4fee6a8e47e37336d4201fe104103f85e111c\",\"verificationGasLimit\":\"1500000\"}"); + } } diff --git a/src/Ethereum/EIP4337.cpp b/src/Ethereum/EIP4337.cpp index dd770fc16e5..e377f996c24 100644 --- a/src/Ethereum/EIP4337.cpp +++ b/src/Ethereum/EIP4337.cpp @@ -4,25 +4,54 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include "ABI.h" +#include "AddressChecksum.h" #include "EIP1014.h" #include "EIP1967.h" -#include "AddressChecksum.h" #include "Hash.h" #include "HexCoding.h" #include -#include "ABI.h" namespace TW::Ethereum { +using ParamBasePtr = std::shared_ptr; +using ParamCollection = std::vector; + +// https://github.com/thomas-waite/bundler/blob/b083680059a52d3121c5e33cea67c86652370562/packages/sdk/src/SimpleAccountAPI.ts#L63-L75 +Data getEIP4337AccountInitializeBytecode(const std::string& ownerAddress, const std::string& factoryAddress) { + auto createAccountFunc = ABI::Function("createAccount", ParamCollection{ + std::make_shared(parse_hex(ownerAddress)), + std::make_shared(0)}); + Data createAccountFuncEncoded; + createAccountFunc.encode(createAccountFuncEncoded); + + Data envelope; + append(envelope, parse_hex(factoryAddress)); + append(envelope, createAccountFuncEncoded); + return envelope; +} + +// https://github.com/eth-infinitism/account-abstraction/blob/5a1ad4072438d9e9f7c934b66464dc05a4b37d02/contracts/samples/SimpleAccountFactory.sol#L48 Data getEIP4337LogicInitializeBytecode(const std::string& ownerAddress) { - auto initializeFunc = ABI::Function("initialize", std::vector>{ - std::make_shared(parse_hex(ownerAddress)) - }); + auto initializeFunc = ABI::Function("initialize", ParamCollection{ + std::make_shared(parse_hex(ownerAddress))}); Data initializeFuncEncoded; initializeFunc.encode(initializeFuncEncoded); return initializeFuncEncoded; } +// https://github.com/thomas-waite/bundler/blob/b083680059a52d3121c5e33cea67c86652370562/packages/sdk/src/SimpleAccountAPI.ts#L91-L100 +Data getEIP4337ExecuteBytecode(const Data& toAddress, const uint256_t& value, const Data& data) { + auto executeFunc = ABI::Function("execute", ParamCollection{ + std::make_shared(toAddress), + std::make_shared(value), + std::make_shared(data)}); + Data executeFuncEncoded; + executeFunc.encode(executeFuncEncoded); + return executeFuncEncoded; +} + +// https://github.com/eth-infinitism/account-abstraction/blob/5a1ad4072438d9e9f7c934b66464dc05a4b37d02/contracts/samples/SimpleAccountFactory.sol#L43-L51 std::string getEIP4337DeploymentAddress(const std::string& factoryAddress, const std::string& logicAddress, const std::string& ownerAddress) { const Data logicInitializeBytecode = getEIP4337LogicInitializeBytecode(ownerAddress); const Data proxyInitCode = getEIP1967ProxyInitCode(logicAddress, logicInitializeBytecode); diff --git a/src/Ethereum/EIP4337.h b/src/Ethereum/EIP4337.h index 540bd2dd6e4..a72ca4eec55 100644 --- a/src/Ethereum/EIP4337.h +++ b/src/Ethereum/EIP4337.h @@ -7,10 +7,14 @@ #pragma once #include "Data.h" +#include "uint256.h" namespace TW::Ethereum { std::string getEIP4337DeploymentAddress(const std::string& factoryAddress, const std::string& logicAddress, const std::string& ownerAddress); + +Data getEIP4337AccountInitializeBytecode(const std::string& ownerAddress, const std::string& factoryAddress); Data getEIP4337LogicInitializeBytecode(const std::string& ownerAddress); +Data getEIP4337ExecuteBytecode(const Data& toAddress, const uint256_t& value, const Data& data); } diff --git a/src/Ethereum/MessageSigner.cpp b/src/Ethereum/MessageSigner.cpp index fa86a3097f2..1988cb55b5e 100644 --- a/src/Ethereum/MessageSigner.cpp +++ b/src/Ethereum/MessageSigner.cpp @@ -12,14 +12,6 @@ namespace TW::Ethereum::internal { -Data generateMessage(const std::string& message) { - std::string prefix(1, MessageSigner::EthereumPrefix); - std::stringstream ss; - ss << prefix << MessageSigner::MessagePrefix << std::to_string(message.size()) << message; - Data signableMessage = Hash::keccak256(data(ss.str())); - return signableMessage; -} - std::string commonSign(const PrivateKey& privateKey, const Data& signableMessage, MessageType msgType, TW::Ethereum::MessageSigner::MaybeChainId chainId) { auto data = privateKey.sign(signableMessage, TWCurveSECP256k1); switch (msgType) { @@ -40,8 +32,16 @@ std::string commonSign(const PrivateKey& privateKey, const Data& signableMessage namespace TW::Ethereum { +Data MessageSigner::generateMessage(const std::string& message) { + std::string prefix(1, MessageSigner::EthereumPrefix); + std::stringstream ss; + ss << prefix << MessageSigner::MessagePrefix << std::to_string(message.size()) << message; + Data signableMessage = Hash::keccak256(data(ss.str())); + return signableMessage; +} + std::string MessageSigner::signMessage(const PrivateKey& privateKey, const std::string& message, MessageType msgType, MaybeChainId chainId) { - auto signableMessage = internal::generateMessage(message); + auto signableMessage = generateMessage(message); return internal::commonSign(privateKey, signableMessage, msgType, chainId); } @@ -59,7 +59,7 @@ std::string MessageSigner::signTypedData(const PrivateKey& privateKey, const std } bool MessageSigner::verifyMessage(const PublicKey& publicKey, const std::string& message, const std::string& signature) noexcept { - Data msg = internal::generateMessage(message); + Data msg = generateMessage(message); //! If it's json && EIP712Domain then we hash the struct if (nlohmann::json::accept(message)) { auto json = nlohmann::json::parse(message); diff --git a/src/Ethereum/MessageSigner.h b/src/Ethereum/MessageSigner.h index 4cb3c1e9598..cd82d9f8de6 100644 --- a/src/Ethereum/MessageSigner.h +++ b/src/Ethereum/MessageSigner.h @@ -45,6 +45,7 @@ class MessageSigner { static bool verifyMessage(const PublicKey& publicKey, const std::string& message, const std::string& signature) noexcept; static constexpr auto MessagePrefix = "Ethereum Signed Message:\n"; static constexpr std::uint8_t EthereumPrefix{0x19}; + static Data generateMessage(const std::string& message); }; } // namespace TW::Ethereum diff --git a/src/Ethereum/Signer.cpp b/src/Ethereum/Signer.cpp index edfca7a0620..13ba33429ae 100644 --- a/src/Ethereum/Signer.cpp +++ b/src/Ethereum/Signer.cpp @@ -90,6 +90,19 @@ Signature Signer::signatureDataToStructSimple(const Data& signature) noexcept { return Signature{r, s, v}; } +Data Signer::simpleStructToSignatureData(const Signature& signature) noexcept { + Data fullSignature; + + auto r = store(signature.r, 32); + append(fullSignature, r); + auto s = store(signature.s, 32); + append(fullSignature, s); + auto v = store(signature.v, 1); + append(fullSignature, v); + + return fullSignature; +} + Signature Signer::signatureDataToStructWithEip155(const uint256_t& chainID, const Data& signature) noexcept { Signature rsv = signatureDataToStructSimple(signature); // Embed chainID in V param, for replay protection, legacy (EIP155) @@ -125,6 +138,17 @@ std::shared_ptr Signer::build(const Proto::SigningInput& input) uint256_t gasLimit = load(input.gas_limit()); uint256_t maxInclusionFeePerGas = load(input.max_inclusion_fee_per_gas()); uint256_t maxFeePerGas = load(input.max_fee_per_gas()); + + // EIP4337 + Data entryPointAddress = addressStringToData(input.user_operation().entry_point()); + Data accountFactoryAddress = addressStringToData(input.user_operation().account_factory()); + Data accountLogicAddress = addressStringToData(input.user_operation().account_logic()); + Data ownerAddress = addressStringToData(input.user_operation().owner()); + bool isAccountDeployed = input.user_operation().is_account_deployed(); + uint256_t preVerificationGas = load(input.user_operation().pre_verification_gas()); + uint256_t verificationGasLimit = load(input.user_operation().verification_gas_limit()); + Data paymasterAndData = Data(input.user_operation().paymaster_and_data().begin(), input.user_operation().paymaster_and_data().end()); + switch (input.transaction().transaction_oneof_case()) { case Proto::Transaction::kTransfer: { switch (input.tx_mode()) { @@ -142,6 +166,25 @@ std::shared_ptr Signer::build(const Proto::SigningInput& input) /* to: */ toAddress, /* amount: */ load(input.transaction().transfer().amount()), /* optional data: */ Data(input.transaction().transfer().data().begin(), input.transaction().transfer().data().end())); + + case Proto::TransactionMode::UserOp: + return UserOperation::buildNativeTransfer( + entryPointAddress, + accountFactoryAddress, + accountLogicAddress, + ownerAddress, + toAddress, + load(input.transaction().transfer().amount()), + nonce, + isAccountDeployed, + gasLimit, + verificationGasLimit, + maxFeePerGas, + maxInclusionFeePerGas, + preVerificationGas, + paymasterAndData, + Data(input.transaction().transfer().data().begin(), input.transaction().transfer().data().end()) + ); } } @@ -162,6 +205,24 @@ std::shared_ptr Signer::build(const Proto::SigningInput& input) /* tokenContract: */ toAddress, /* toAddress */ tokenToAddress, /* amount: */ load(input.transaction().erc20_transfer().amount())); + + case Proto::TransactionMode::UserOp: + return UserOperation::buildERC20Transfer( + entryPointAddress, + accountFactoryAddress, + accountLogicAddress, + ownerAddress, + toAddress, + tokenToAddress, + load(input.transaction().erc20_transfer().amount()), + nonce, + isAccountDeployed, + gasLimit, + verificationGasLimit, + maxFeePerGas, + maxInclusionFeePerGas, + preVerificationGas, + paymasterAndData); } } @@ -182,6 +243,24 @@ std::shared_ptr Signer::build(const Proto::SigningInput& input) /* tokenContract: */ toAddress, /* toAddress */ spenderAddress, /* amount: */ load(input.transaction().erc20_approve().amount())); + + case Proto::TransactionMode::UserOp: + return UserOperation::buildERC20Approve( + entryPointAddress, + accountFactoryAddress, + accountLogicAddress, + ownerAddress, + toAddress, + spenderAddress, + load(input.transaction().erc20_approve().amount()), + nonce, + isAccountDeployed, + gasLimit, + verificationGasLimit, + maxFeePerGas, + maxInclusionFeePerGas, + preVerificationGas, + paymasterAndData); } } @@ -205,6 +284,25 @@ std::shared_ptr Signer::build(const Proto::SigningInput& input) /* fromAddress: */ tokenFromAddress, /* toAddress */ tokenToAddress, /* tokenId: */ load(input.transaction().erc721_transfer().token_id())); + + case Proto::TransactionMode::UserOp: + return UserOperation::buildERC721Transfer( + entryPointAddress, + accountFactoryAddress, + accountLogicAddress, + ownerAddress, + toAddress, + tokenFromAddress, + tokenToAddress, + load(input.transaction().erc721_transfer().token_id()), + nonce, + isAccountDeployed, + gasLimit, + verificationGasLimit, + maxFeePerGas, + maxInclusionFeePerGas, + preVerificationGas, + paymasterAndData); } } @@ -232,6 +330,27 @@ std::shared_ptr Signer::build(const Proto::SigningInput& input) /* tokenId: */ load(input.transaction().erc1155_transfer().token_id()), /* value */ load(input.transaction().erc1155_transfer().value()), /* data */ Data(input.transaction().erc1155_transfer().data().begin(), input.transaction().erc1155_transfer().data().end())); + + case Proto::TransactionMode::UserOp: + return UserOperation::buildERC1155Transfer( + entryPointAddress, + accountFactoryAddress, + accountLogicAddress, + ownerAddress, + toAddress, + tokenFromAddress, + tokenToAddress, + load(input.transaction().erc1155_transfer().token_id()), + load(input.transaction().erc1155_transfer().value()), + Data(input.transaction().erc1155_transfer().data().begin(), input.transaction().erc1155_transfer().data().end()), + nonce, + isAccountDeployed, + gasLimit, + verificationGasLimit, + maxFeePerGas, + maxInclusionFeePerGas, + preVerificationGas, + paymasterAndData); } } @@ -252,6 +371,24 @@ std::shared_ptr Signer::build(const Proto::SigningInput& input) /* to: */ toAddress, /* amount: */ load(input.transaction().contract_generic().amount()), /* transaction: */ Data(input.transaction().contract_generic().data().begin(), input.transaction().contract_generic().data().end())); + + case Proto::TransactionMode::UserOp: + return UserOperation::buildNativeTransfer( + entryPointAddress, + accountFactoryAddress, + accountLogicAddress, + ownerAddress, + toAddress, + load(input.transaction().contract_generic().amount()), + nonce, + isAccountDeployed, + gasLimit, + verificationGasLimit, + maxFeePerGas, + maxInclusionFeePerGas, + preVerificationGas, + paymasterAndData, + Data(input.transaction().contract_generic().data().begin(), input.transaction().contract_generic().data().end())); } } } diff --git a/src/Ethereum/Signer.h b/src/Ethereum/Signer.h index 3fb42172c1d..cdf32672ec9 100644 --- a/src/Ethereum/Signer.h +++ b/src/Ethereum/Signer.h @@ -54,6 +54,10 @@ class Signer { /// \returns the r, s, and v values of the transaction signature static Signature signatureDataToStructSimple(const Data& signature) noexcept; + /// Converts R, S, and V values into the full signature, with no replay protection. + /// \returns the full signature bytes + static Data simpleStructToSignatureData(const Signature& signature) noexcept; + /// Break up the signature into the R, S, and V values, and include chainID in V for replay protection (Eip155) /// \returns the r, s, and v values of the transaction signature static Signature signatureDataToStructWithEip155(const uint256_t& chainID, const Data& signature) noexcept; diff --git a/src/Ethereum/Transaction.cpp b/src/Ethereum/Transaction.cpp index d033dbb6f80..bb168b91cee 100644 --- a/src/Ethereum/Transaction.cpp +++ b/src/Ethereum/Transaction.cpp @@ -5,16 +5,24 @@ // file LICENSE at the root of the source code distribution tree. #include "Transaction.h" -#include "ABI/Function.h" -#include "ABI/ParamAddress.h" -#include "ABI/ParamBase.h" +#include "Ethereum/ABI.h" #include "HexCoding.h" #include "RLP.h" +#include "Signer.h" +#include +#include +#include namespace TW::Ethereum { +using json = nlohmann::json; +using ParamBasePtr = std::shared_ptr; +using ParamCollection = std::vector; +using UserOperationPtr = std::shared_ptr; + static const Data EmptyListEncoded = parse_hex("c0"); +/// TransactionNonTyped std::shared_ptr TransactionNonTyped::buildNativeTransfer(const uint256_t& nonce, const uint256_t& gasPrice, const uint256_t& gasLimit, @@ -84,7 +92,7 @@ Data TransactionNonTyped::encoded(const Signature& signature, [[maybe_unused]] c Data TransactionNonTyped::buildERC20TransferCall(const Data& to, const uint256_t& amount) { // clang-format off - auto func = ABI::Function("transfer", std::vector>{ + auto func = ABI::Function("transfer", ParamCollection{ std::make_shared(to), std::make_shared(amount) }); @@ -96,7 +104,7 @@ Data TransactionNonTyped::buildERC20TransferCall(const Data& to, const uint256_t Data TransactionNonTyped::buildERC20ApproveCall(const Data& spender, const uint256_t& amount) { // clang-format off - auto func = ABI::Function("approve", std::vector>{ + auto func = ABI::Function("approve", ParamCollection{ std::make_shared(spender), std::make_shared(amount) }); @@ -108,7 +116,7 @@ Data TransactionNonTyped::buildERC20ApproveCall(const Data& spender, const uint2 Data TransactionNonTyped::buildERC721TransferFromCall(const Data& from, const Data& to, const uint256_t& tokenId) { // clang-format off - auto func = ABI::Function("transferFrom", std::vector>{ + auto func = ABI::Function("transferFrom", ParamCollection{ std::make_shared(from), std::make_shared(to), std::make_shared(tokenId) @@ -121,7 +129,7 @@ Data TransactionNonTyped::buildERC721TransferFromCall(const Data& from, const Da Data TransactionNonTyped::buildERC1155TransferFromCall(const Data& from, const Data& to, const uint256_t& tokenId, const uint256_t& value, const Data& data) { // clang-format off - auto func = ABI::Function("safeTransferFrom", std::vector>{ + auto func = ABI::Function("safeTransferFrom", ParamCollection{ std::make_shared(from), std::make_shared(to), std::make_shared(tokenId), @@ -134,6 +142,7 @@ Data TransactionNonTyped::buildERC1155TransferFromCall(const Data& from, const D return payload; } +/// TransactionEip1559 Data TransactionEip1559::preHash(const uint256_t chainID) const { return Hash::keccak256(serialize(chainID)); } @@ -212,4 +221,171 @@ TransactionEip1559::buildERC1155Transfer(const uint256_t& nonce, return std::make_shared(nonce, maxInclusionFeePerGas, maxFeePerGas, gasPrice, tokenContract, 0, TransactionNonTyped::buildERC1155TransferFromCall(from, to, tokenId, value, data)); } -} // namespace TW::Ethereum +/// UserOperation +Data UserOperation::preHash(const uint256_t chainID) const { + auto params = ABI::ParamTuple(ParamCollection{ + std::make_shared(32, Hash::keccak256(serialize(chainID))), + std::make_shared(entryPoint), + std::make_shared(chainID)}); + Data encoded; + params.encode(encoded); + const auto hash = Hash::keccak256(encoded); + const auto hashStr = std::string(hash.begin(), hash.end()); + return MessageSigner::generateMessage(hashStr); +} + +Data UserOperation::serialize(const uint256_t chainID) const { + auto params = ABI::ParamTuple(ParamCollection{ + std::make_shared(sender), + std::make_shared(nonce), + std::make_shared(initCode), + std::make_shared(payload), + std::make_shared(gasLimit), + std::make_shared(verificationGasLimit), + std::make_shared(preVerificationGas), + std::make_shared(maxFeePerGas), + std::make_shared(maxInclusionFeePerGas), + std::make_shared(paymasterAndData), + std::make_shared(parse_hex("0x"))}); + Data serialized; + params.encode(serialized); + + return Data(serialized.begin(), serialized.end() - 32); // remove trailing word (zero-length signature) +} + +Data UserOperation::encoded(const Signature& signature, const uint256_t chainID) const { + Data rawSignature = Signer::simpleStructToSignatureData(signature); + rawSignature[64] += 27; + + const json tx = { + {"sender", hexEncoded(sender)}, + {"nonce", nonce.str()}, + {"initCode", hexEncoded(initCode)}, + {"callData", hexEncoded(payload)}, + {"callGasLimit", gasLimit.str()}, + {"verificationGasLimit", verificationGasLimit.str()}, + {"maxFeePerGas", maxFeePerGas.str()}, + {"maxPriorityFeePerGas", maxInclusionFeePerGas.str()}, + {"paymasterAndData", hexEncoded(paymasterAndData)}, + {"preVerificationGas", preVerificationGas.str()}, + {"signature", hexEncoded(rawSignature)}}; + const auto txString = tx.dump(); + return Data(txString.begin(), txString.end()); +} + +UserOperationPtr +UserOperation::buildNativeTransfer(const Data& entryPointAddress, const Data& factoryAddress, const Data& logicAddress, const Data& ownerAddress, + const Data& toAddress, const uint256_t& amount, const uint256_t& nonce, const bool& isAccountDeployed, + const uint256_t& gasLimit, const uint256_t& verificationGasLimit, const uint256_t& maxFeePerGas, const uint256_t& maxInclusionFeePerGas, const uint256_t& preVerificationGas, + const Data& paymasterAndData, const Data& payload) { + Data initCode = {}; + if (!isAccountDeployed) { + initCode = Ethereum::getEIP4337AccountInitializeBytecode(hex(ownerAddress), hex(factoryAddress)); + } + return std::make_shared( + entryPointAddress, + parse_hex(Ethereum::getEIP4337DeploymentAddress(hex(factoryAddress), hex(logicAddress), hex(ownerAddress))), + nonce, + initCode, + gasLimit, + verificationGasLimit, + maxFeePerGas, + maxInclusionFeePerGas, + preVerificationGas, + Ethereum::getEIP4337ExecuteBytecode(toAddress, amount, payload), + paymasterAndData); +} + +UserOperationPtr +UserOperation::buildERC20Transfer(const Data& entryPointAddress, const Data& factoryAddress, const Data& logicAddress, const Data& ownerAddress, + const Data& tokenContract, const Data& toAddress, const uint256_t& amount, const uint256_t& nonce, const bool& isAccountDeployed, + const uint256_t& gasLimit, const uint256_t& verificationGasLimit, const uint256_t& maxFeePerGas, const uint256_t& maxInclusionFeePerGas, const uint256_t& preVerificationGas, + const Data& paymasterAndData) { + Data initCode = {}; + if (!isAccountDeployed) { + initCode = Ethereum::getEIP4337AccountInitializeBytecode(hex(ownerAddress), hex(factoryAddress)); + } + return std::make_shared( + entryPointAddress, + parse_hex(Ethereum::getEIP4337DeploymentAddress(hex(factoryAddress), hex(logicAddress), hex(ownerAddress))), + nonce, + initCode, + gasLimit, + verificationGasLimit, + maxFeePerGas, + maxInclusionFeePerGas, + preVerificationGas, + Ethereum::getEIP4337ExecuteBytecode(tokenContract, 0, TransactionNonTyped::buildERC20TransferCall(toAddress, amount)), + paymasterAndData); +} + +UserOperationPtr +UserOperation::buildERC20Approve(const Data& entryPointAddress, const Data& factoryAddress, const Data& logicAddress, const Data& ownerAddress, + const Data& tokenContract, const Data& spenderAddress, const uint256_t& amount, const uint256_t& nonce, const bool& isAccountDeployed, + const uint256_t& gasLimit, const uint256_t& verificationGasLimit, const uint256_t& maxFeePerGas, const uint256_t& maxInclusionFeePerGas, const uint256_t& preVerificationGas, + const Data& paymasterAndData) { + Data initCode = {}; + if (!isAccountDeployed) { + initCode = Ethereum::getEIP4337AccountInitializeBytecode(hex(ownerAddress), hex(factoryAddress)); + } + return std::make_shared( + entryPointAddress, + parse_hex(Ethereum::getEIP4337DeploymentAddress(hex(factoryAddress), hex(logicAddress), hex(ownerAddress))), + nonce, + initCode, + gasLimit, + verificationGasLimit, + maxFeePerGas, + maxInclusionFeePerGas, + preVerificationGas, + Ethereum::getEIP4337ExecuteBytecode(tokenContract, 0, TransactionNonTyped::buildERC20ApproveCall(spenderAddress, amount)), + paymasterAndData); +} + +UserOperationPtr +UserOperation::buildERC721Transfer(const Data& entryPointAddress, const Data& factoryAddress, const Data& logicAddress, const Data& ownerAddress, + const Data& tokenContract, const Data& from, const Data& to, const uint256_t& tokenId, const uint256_t& nonce, const bool& isAccountDeployed, + const uint256_t& gasLimit, const uint256_t& verificationGasLimit, const uint256_t& maxFeePerGas, const uint256_t& maxInclusionFeePerGas, const uint256_t& preVerificationGas, + const Data& paymasterAndData) { + Data initCode = {}; + if (!isAccountDeployed) { + initCode = Ethereum::getEIP4337AccountInitializeBytecode(hex(ownerAddress), hex(factoryAddress)); + } + return std::make_shared( + entryPointAddress, + parse_hex(Ethereum::getEIP4337DeploymentAddress(hex(factoryAddress), hex(logicAddress), hex(ownerAddress))), + nonce, + initCode, + gasLimit, + verificationGasLimit, + maxFeePerGas, + maxInclusionFeePerGas, + preVerificationGas, + Ethereum::getEIP4337ExecuteBytecode(tokenContract, 0, TransactionNonTyped::buildERC721TransferFromCall(from, to, tokenId)), + paymasterAndData); +} + +UserOperationPtr +UserOperation::buildERC1155Transfer(const Data& entryPointAddress, const Data& factoryAddress, const Data& logicAddress, const Data& ownerAddress, + const Data& tokenContract, const Data& from, const Data& to, const uint256_t& tokenId, const uint256_t& value, const Data& data, const uint256_t& nonce, const bool& isAccountDeployed, + const uint256_t& gasLimit, const uint256_t& verificationGasLimit, const uint256_t& maxFeePerGas, const uint256_t& maxInclusionFeePerGas, const uint256_t& preVerificationGas, + const Data& paymasterAndData) { + Data initCode = {}; + if (!isAccountDeployed) { + initCode = Ethereum::getEIP4337AccountInitializeBytecode(hex(ownerAddress), hex(factoryAddress)); + } + return std::make_shared( + entryPointAddress, + parse_hex(Ethereum::getEIP4337DeploymentAddress(hex(factoryAddress), hex(logicAddress), hex(ownerAddress))), + nonce, + initCode, + gasLimit, + verificationGasLimit, + maxFeePerGas, + maxInclusionFeePerGas, + preVerificationGas, + Ethereum::getEIP4337ExecuteBytecode(tokenContract, 0, TransactionNonTyped::buildERC1155TransferFromCall(from, to, tokenId, value, data)), + paymasterAndData); +} + +} // namespace TW::Ethereum \ No newline at end of file diff --git a/src/Ethereum/Transaction.h b/src/Ethereum/Transaction.h index d43fd77aa10..0cf47190e3d 100644 --- a/src/Ethereum/Transaction.h +++ b/src/Ethereum/Transaction.h @@ -108,6 +108,7 @@ class TransactionNonTyped: public TransactionBase { enum TransactionType: uint8_t { TxType_OptionalAccessList = 0x01, TxType_Eip1559 = 0x02, + TxType_Eip4337 = 0x03, }; /// Base class for various typed transactions. @@ -169,4 +170,66 @@ class TransactionEip1559: public TransactionTyped { , amount(std::move(amount)) {} }; +/// EIP4337 UserOperation +// https://github.com/ethereum/EIPs/blob/3fd65b1a782912bfc18cb975c62c55f733c7c96e/EIPS/eip-4337.md#specification +class UserOperation: public TransactionTyped { + using UserOperationPtr = std::shared_ptr; +public: + Data entryPoint; + Data sender; + Data initCode; + uint256_t gasLimit; + uint256_t verificationGasLimit; + uint256_t maxFeePerGas; + uint256_t maxInclusionFeePerGas; + uint256_t preVerificationGas; + Data paymasterAndData; + + // Factory methods + // Create a native transfer transaction + static UserOperationPtr buildNativeTransfer(const Data& entryPointAddress, const Data& factoryAddress, const Data& logicAddress, const Data& ownerAddress, + const Data& toAddress, const uint256_t& amount, const uint256_t& nonce, const bool& isAccountDeployed, + const uint256_t& gasLimit, const uint256_t& verificationGasLimit, const uint256_t& maxFeePerGas, const uint256_t& maxInclusionFeePerGas, const uint256_t& preVerificationGas, + const Data& paymasterAndData = {}, const Data& payload = {}); + // Create an ERC20 token transfer transaction + static UserOperationPtr buildERC20Transfer(const Data& entryPointAddress, const Data& factoryAddress, const Data& logicAddress, const Data& ownerAddress, + const Data& tokenContract, const Data& toAddress, const uint256_t& amount, const uint256_t& nonce, const bool& isAccountDeployed, + const uint256_t& gasLimit, const uint256_t& verificationGasLimit, const uint256_t& maxFeePerGas, const uint256_t& maxInclusionFeePerGas, const uint256_t& preVerificationGas, + const Data& paymasterAndData = {}); + // Create an ERC20 approve transaction + static UserOperationPtr buildERC20Approve(const Data& entryPointAddress, const Data& factoryAddress, const Data& logicAddress, const Data& ownerAddress, + const Data& tokenContract, const Data& spenderAddress, const uint256_t& amount, const uint256_t& nonce, const bool& isAccountDeployed, + const uint256_t& gasLimit, const uint256_t& verificationGasLimit, const uint256_t& maxFeePerGas, const uint256_t& maxInclusionFeePerGas, const uint256_t& preVerificationGas, + const Data& paymasterAndData = {}); + // Create an ERC721 NFT transfer transaction + static UserOperationPtr buildERC721Transfer(const Data& entryPointAddress, const Data& factoryAddress, const Data& logicAddress, const Data& ownerAddress, + const Data& tokenContract, const Data& from, const Data& to, const uint256_t& tokenId, const uint256_t& nonce, const bool& isAccountDeployed, + const uint256_t& gasLimit, const uint256_t& verificationGasLimit, const uint256_t& maxFeePerGas, const uint256_t& maxInclusionFeePerGas, const uint256_t& preVerificationGas, + const Data& paymasterAndData = {}); + // Create an ERC1155 NFT transfer transaction + static UserOperationPtr buildERC1155Transfer(const Data& entryPointAddress, const Data& factoryAddress, const Data& logicAddress, const Data& ownerAddress, + const Data& tokenContract, const Data& from, const Data& to, const uint256_t& tokenId, const uint256_t& value, const Data& data, const uint256_t& nonce, const bool& isAccountDeployed, + const uint256_t& gasLimit, const uint256_t& verificationGasLimit, const uint256_t& maxFeePerGas, const uint256_t& maxInclusionFeePerGas, const uint256_t& preVerificationGas, + const Data& paymasterAndData = {}); + + virtual Data preHash(const uint256_t chainID) const; + virtual Data serialize(const uint256_t chainID) const; + virtual Data encoded(const Signature& signature, const uint256_t chainID) const; + +public: + UserOperation(const Data& entryPoint, const Data& sender, const uint256_t& nonce, const Data& initCode, + const uint256_t& gasLimit, const uint256_t& verificationGasLimit, const uint256_t& maxFeePerGas, const uint256_t& maxInclusionFeePerGas, const uint256_t& preVerificationGas, + const Data& payload = {}, const Data& paymasterAndData = {}) + : TransactionTyped(TxType_Eip4337, nonce, payload) + , entryPoint(std::move(entryPoint)) + , sender(std::move(sender)) + , initCode(std::move(initCode)) + , gasLimit(std::move(gasLimit)) + , verificationGasLimit(std::move(verificationGasLimit)) + , maxFeePerGas(std::move(maxFeePerGas)) + , maxInclusionFeePerGas(std::move(maxInclusionFeePerGas)) + , preVerificationGas(std::move(preVerificationGas)) + , paymasterAndData(std::move(paymasterAndData)) {} +}; + } // namespace TW::Ethereum diff --git a/src/proto/Ethereum.proto b/src/proto/Ethereum.proto index ce3ab148556..b84af3e1a70 100644 --- a/src/proto/Ethereum.proto +++ b/src/proto/Ethereum.proto @@ -89,7 +89,37 @@ enum TransactionMode { Legacy = 0; // Enveloped transaction EIP2718 (with type 0x2), fee is according to EIP1559 (base fee, inclusion fee, ...) - Enveloped = 1; + Enveloped = 1; + + // EIP4337-compatible UserOperation + UserOp = 2; +} + +// ERC-4337 structure that describes a transaction to be sent on behalf of a user +message UserOperation { + // Entry point contract address + string entry_point = 1; + + // Account factory contract address + string account_factory = 2; + + // Account logic contract address + string account_logic = 3; + + // Public address of the account signer + string owner = 4; + + // Whether the smart contract for this address has already been deployed + bool is_account_deployed = 5; + + // The amount of gas to pay for to compensate the bundler for pre-verification execution and calldata + bytes pre_verification_gas = 6; + + // The amount of gas to allocate for the verification step + bytes verification_gas_limit = 7; + + // Address of paymaster sponsoring the transaction, followed by extra data to send to the paymaster (empty for self-sponsored transaction) + bytes paymaster_and_data = 8; } // Input data necessary to create a signed transaction. @@ -128,6 +158,9 @@ message SigningInput { // The payload transaction Transaction transaction = 10; + + // UserOperation for ERC-4337 wallets + UserOperation user_operation = 11; } // Result containing the signed and encoded transaction. diff --git a/swift/Tests/Blockchains/EthereumTests.swift b/swift/Tests/Blockchains/EthereumTests.swift index 4a94e459445..8a67d5e9756 100644 --- a/swift/Tests/Blockchains/EthereumTests.swift +++ b/swift/Tests/Blockchains/EthereumTests.swift @@ -8,22 +8,6 @@ import XCTest import WalletCore class EthereumTests: XCTestCase { - - func testCreate2Address() { - let address = "0x0000000000000000000000000000000000000000" - let salt = Data(hexString: "0x0000000000000000000000000000000000000000000000000000000000000000")! - let initCodeHash = Hash.keccak256(data: Data(hexString: "0x00")!) - let result = Ethereum.eip1014AddressCreate2(fromEthAddress: address, salt: salt, initCodeHash: initCodeHash) - XCTAssertEqual(result, "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38") - } - - func testEIP4337DeploymentAddress() { - let factoryAddress = "0xd9145CCE52D386f254917e481eB44e9943F39138" - let logicAddress = "0x5C9eb5D6a6C2c1B3EFc52255C0b356f116f6f66D" - let ownerAddress = "0xA5a1dddEF094095AfB7b6e322dE72961DF2e1988" - let result = Ethereum.eip4337GetDeploymentAddress(factoryAddress: factoryAddress, logicAddress: logicAddress, ownerAddress: ownerAddress) - XCTAssertEqual(result, "0xbEaA87cEEaC906C21aaacd258FbFB87CfA3c90a8") - } func testAddress() { let anyAddress = AnyAddress(string: "0x7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1", coin: .ethereum) @@ -387,4 +371,249 @@ class EthereumTests: XCTestCase { let pubKey = privateKey.getPublicKey(coinType: .ethereum) XCTAssertTrue(EthereumMessageSigner.verifyMessage(pubKey: pubKey, message: msg, signature: signature)) } + + // EIP4337 + + func testCreate2Address() { + let address = "0x0000000000000000000000000000000000000000" + let salt = Data(hexString: "0x0000000000000000000000000000000000000000000000000000000000000000")! + let initCodeHash = Hash.keccak256(data: Data(hexString: "0x00")!) + let result = Ethereum.eip1014AddressCreate2(fromEthAddress: address, salt: salt, initCodeHash: initCodeHash) + XCTAssertEqual(result, "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38") + } + + func testEIP4337DeploymentAddress() { + let factoryAddress = "0xd9145CCE52D386f254917e481eB44e9943F39138" + let logicAddress = "0x5C9eb5D6a6C2c1B3EFc52255C0b356f116f6f66D" + let ownerAddress = "0xA5a1dddEF094095AfB7b6e322dE72961DF2e1988" + let result = Ethereum.eip4337GetDeploymentAddress(factoryAddress: factoryAddress, logicAddress: logicAddress, ownerAddress: ownerAddress) + XCTAssertEqual(result, "0xbEaA87cEEaC906C21aaacd258FbFB87CfA3c90a8") + } + + func testEIP4337NativeTransferAccountNotDeployed() throws { + let input = EthereumSigningInput.with { + $0.txMode = .userOp + $0.chainID = Data(hexString: "05")! + $0.nonce = Data(hexString: "00")! + $0.toAddress = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a" + + $0.gasLimit = Data(hexString: "0x5580")! + $0.maxFeePerGas = Data(hexString: "0x01952f1f85")! + $0.maxInclusionFeePerGas = Data(hexString: "0x0f")! + + $0.userOperation = EthereumUserOperation.with { + $0.entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53" + $0.accountFactory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92" + $0.accountLogic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620" + $0.owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238" + $0.isAccountDeployed = false + + $0.preVerificationGas = Data(hexString: "0xbc18")! + $0.verificationGasLimit = Data(hexString: "0x073272")! + } + + $0.privateKey = Data(hexString: "0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")! + $0.transaction = EthereumTransaction.with { + $0.transfer = EthereumTransaction.Transfer.with { + $0.amount = Data(hexString: "0x2386f26fc10000")! + } + } + } + + let output: EthereumSigningOutput = AnySigner.sign(input: input, coin: .ethereum) + let json = String(data: output.encoded, encoding: .utf8) + + XCTAssertEqual(try input.serializedData().hexString, "0a010512010018022a02558032010f3a0501952f1f85422a3078636536343233353546613535336634303843333461323635304164324634413136333464303333614a20f9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8520b0a090a072386f26fc100005ab9010a2a307831333036623031624333653441443230323631324433383433333837653934373337363733463533122a3078354138373230396237353537383163463635664565456464333835356164653033313766346139321a2a307832316363323764376462346661313938353761333730323635336137613637656533306361363230222a3078373864394333326239364262383732443636443531383138323237353633663434653637453233383202bc183a03073272") + XCTAssertEqual(json, "{\"callData\":\"0xb61d27f6000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"21888\",\"initCode\":\"0x5a87209b755781cf65feeedd3855ade0317f4a925fbfb9cf00000000000000000000000078d9c32b96bb872d66d51818227563f44e67e2380000000000000000000000000000000000000000000000000000000000000000\",\"maxFeePerGas\":\"6797860741\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"0\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"48152\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0x1560b19d17613ec8580cb0feaf7ac2953771404c5bd7830f585e5062e6ddd4b82ae3bb8dbddb659c0300e8009857b5c77501e1cfd5bbab48d03de0ea7207d07c1b\",\"verificationGasLimit\":\"471666\"}"); + } + + func testEIP4337NativeTransferAccountDeployed() throws { + let input = EthereumSigningInput.with { + $0.txMode = .userOp + $0.chainID = Data(hexString: "05")! + $0.nonce = Data(hexString: "01")! + $0.toAddress = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a" + + $0.gasLimit = Data(hexString: "0x9d55")! + $0.maxFeePerGas = Data(hexString: "0x01a339c9e9")! + $0.maxInclusionFeePerGas = Data(hexString: "0x0f")! + + $0.userOperation = EthereumUserOperation.with { + $0.entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53" + $0.accountFactory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92" + $0.accountLogic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620" + $0.owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238" + $0.isAccountDeployed = true + + $0.preVerificationGas = Data(hexString: "0xb708")! + $0.verificationGasLimit = Data(hexString: "0x0186a0")! + } + + $0.privateKey = Data(hexString: "0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")! + $0.transaction = EthereumTransaction.with { + $0.transfer = EthereumTransaction.Transfer.with { + $0.amount = Data(hexString: "0x2386f26fc10000")! + } + } + } + + let output: EthereumSigningOutput = AnySigner.sign(input: input, coin: .ethereum) + let json = String(data: output.encoded, encoding: .utf8) + + XCTAssertEqual(try input.serializedData().hexString, "0a010512010118022a029d5532010f3a0501a339c9e9422a3078636536343233353546613535336634303843333461323635304164324634413136333464303333614a20f9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8520b0a090a072386f26fc100005abb010a2a307831333036623031624333653441443230323631324433383433333837653934373337363733463533122a3078354138373230396237353537383163463635664565456464333835356164653033313766346139321a2a307832316363323764376462346661313938353761333730323635336137613637656533306361363230222a30783738643943333262393642623837324436364435313831383232373536336634346536374532333828013202b7083a030186a0") + XCTAssertEqual(json, "{\"callData\":\"0xb61d27f6000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"40277\",\"initCode\":\"0x\",\"maxFeePerGas\":\"7033440745\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"1\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"46856\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0xaed2011e5cf267de495b38ecf86ad6f1d4c05217a99e59f47e8d52ba3d41c10144785893fa3e7c116a054999e3902fc2771064d0545148bc49f6d7c827fc7a9a1c\",\"verificationGasLimit\":\"100000\"}"); + } + + func testEIP4337ERC20TransferAccountDeployed() throws { + let input = EthereumSigningInput.with { + $0.txMode = .userOp + $0.chainID = Data(hexString: "05")! + $0.nonce = Data(hexString: "06")! + $0.toAddress = "0x98339d8c260052b7ad81c28c16c0b98420f2b46a" + + $0.gasLimit = Data(hexString: "0xf78e")! + $0.maxFeePerGas = Data(hexString: "0x168ad5950f")! + $0.maxInclusionFeePerGas = Data(hexString: "0x0f")! + + + $0.userOperation = EthereumUserOperation.with { + $0.entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53" + $0.accountFactory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92" + $0.accountLogic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620" + $0.owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238" + $0.isAccountDeployed = true + + $0.preVerificationGas = Data(hexString: "0xbb10")! + $0.verificationGasLimit = Data(hexString: "0x0186a0")! + } + + $0.privateKey = Data(hexString: "0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")! + $0.transaction = EthereumTransaction.with { + $0.erc20Transfer = EthereumTransaction.ERC20Transfer.with { + $0.to = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a" + $0.amount = Data(hexString: "0x0186a0")! + } + } + } + + let output: EthereumSigningOutput = AnySigner.sign(input: input, coin: .ethereum) + let json = String(data: output.encoded, encoding: .utf8) + + XCTAssertEqual(json, "{\"callData\":\"0xb61d27f600000000000000000000000098339d8c260052b7ad81c28c16c0b98420f2b46a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a00000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"63374\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"6\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"47888\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0xd006c93d6a8753b5e7c1e6349de0dea34eab2e7a533106e0f2e1a3a3b013c8e97b007546dab9d7b8fc471ad14ff2e8aa351dc4f1ecb63bf20f33858dc7366cbe1c\",\"verificationGasLimit\":\"100000\"}"); + } + + func testEIP4337ERC20ApproveAccountDeployed() throws { + let input = EthereumSigningInput.with { + $0.txMode = .userOp + $0.chainID = Data(hexString: "05")! + $0.nonce = Data(hexString: "09")! + $0.toAddress = "0x98339d8c260052b7ad81c28c16c0b98420f2b46a" + + $0.gasLimit = Data(hexString: "0xf78e")! + $0.maxFeePerGas = Data(hexString: "0x168ad5950f")! + $0.maxInclusionFeePerGas = Data(hexString: "0x0f")! + + $0.userOperation = EthereumUserOperation.with { + $0.entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53" + $0.accountFactory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92" + $0.accountLogic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620" + $0.owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238" + $0.isAccountDeployed = true + + $0.preVerificationGas = Data(hexString: "0xbb10")! + $0.verificationGasLimit = Data(hexString: "0x0186a0")! + } + + $0.privateKey = Data(hexString: "0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")! + $0.transaction = EthereumTransaction.with { + $0.erc20Approve = EthereumTransaction.ERC20Approve.with { + $0.spender = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a" + $0.amount = Data(hexString: "0x0186a0")! + } + } + } + + let output: EthereumSigningOutput = AnySigner.sign(input: input, coin: .ethereum) + let json = String(data: output.encoded, encoding: .utf8) + + XCTAssertEqual(json, "{\"callData\":\"0xb61d27f600000000000000000000000098339d8c260052b7ad81c28c16c0b98420f2b46a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a00000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"63374\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"9\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"47888\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0x262a67dd8cf3d16a72b7809b3b5ed55e9f4c2b93eedd5a3c6be035fbbd7111164464ec933d0fdfa359e266e318f3ac22702ae428ce14fc142e4475603e6ec15e1c\",\"verificationGasLimit\":\"100000\"}"); + } + + func testEIP4337ERC721TransferAccountDeployed() throws { + let input = EthereumSigningInput.with { + $0.txMode = .userOp + $0.chainID = Data(hexString: "05")! + $0.nonce = Data(hexString: "0x0C")! + $0.toAddress = "0xf5de760f2e916647fd766b4ad9e85ff943ce3a2b" + + $0.gasLimit = Data(hexString: "0x60B378")! + $0.maxFeePerGas = Data(hexString: "0x168ad5950f")! + $0.maxInclusionFeePerGas = Data(hexString: "0x0f")! + + $0.userOperation = EthereumUserOperation.with { + $0.entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53" + $0.accountFactory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92" + $0.accountLogic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620" + $0.owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238" + $0.isAccountDeployed = true + + $0.preVerificationGas = Data(hexString: "0xC34F")! + $0.verificationGasLimit = Data(hexString: "0x16E360")! + } + + $0.privateKey = Data(hexString: "0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")! + $0.transaction = EthereumTransaction.with { + $0.erc721Transfer = EthereumTransaction.ERC721Transfer.with { + $0.from = "0x8cE23B8769ac01d0df0d5f47Be1A38FeA97F3879" + $0.to = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a" + $0.tokenID = Data(hexString: "0x2A8E57")! + } + } + } + + let output: EthereumSigningOutput = AnySigner.sign(input: input, coin: .ethereum) + let json = String(data: output.encoded, encoding: .utf8) + + XCTAssertEqual(json, "{\"callData\":\"0xb61d27f6000000000000000000000000f5de760f2e916647fd766b4ad9e85ff943ce3a2b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000006423b872dd0000000000000000000000008ce23b8769ac01d0df0d5f47be1a38fea97f3879000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a00000000000000000000000000000000000000000000000000000000002a8e5700000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"6337400\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"12\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"49999\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0x5951cc161a4d60d6b59503efb93e446f5d1a2e3a41d4503ba6393bcf2a2637340d0a865ed5d4d7650a68cbb95915eaa7ed54fd2c42b4bf7c83376f5c5d70691d1b\",\"verificationGasLimit\":\"1500000\"}"); + } + + func testEIP4337ERC1155TransferAccountDeployed() throws { + let input = EthereumSigningInput.with { + $0.txMode = .userOp + $0.chainID = Data(hexString: "05")! + $0.nonce = Data(hexString: "0x")! + $0.toAddress = "0x428ce4b916332e1afccfddce08baecc97cb40b12" + + $0.gasLimit = Data(hexString: "0x60B378")! + $0.maxFeePerGas = Data(hexString: "0x168ad5950f")! + $0.maxInclusionFeePerGas = Data(hexString: "0x0f")! + + $0.userOperation = EthereumUserOperation.with { + $0.entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53" + $0.accountFactory = "0x76627b8D1E01fAF0C73B69625BC1fCb8FA19a2AD" + $0.accountLogic = "0x510ab68bd111ce7115df797118b0334d727d564b" + $0.owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238" + $0.isAccountDeployed = true + + $0.preVerificationGas = Data(hexString: "0xC738")! + $0.verificationGasLimit = Data(hexString: "0x16E360")! + } + + $0.privateKey = Data(hexString: "0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")! + $0.transaction = EthereumTransaction.with { + $0.erc1155Transfer = EthereumTransaction.ERC1155Transfer.with { + $0.from = "0x8c560E00680b973645900528EDe71a99b8d4dca8" + $0.to = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a" + $0.tokenID = Data(hexString: "0x01")! + $0.value = Data(hexString: "0x")! + $0.data = Data(hexString: "0x")! + } + } + } + + let output: EthereumSigningOutput = AnySigner.sign(input: input, coin: .ethereum) + let json = String(data: output.encoded, encoding: .utf8) + + XCTAssertEqual(json, "{\"callData\":\"0xb61d27f6000000000000000000000000428ce4b916332e1afccfddce08baecc97cb40b120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c4f242432a0000000000000000000000008c560e00680b973645900528ede71a99b8d4dca8000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"6337400\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"0\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"51000\",\"sender\":\"0x8c560e00680b973645900528ede71a99b8d4dca8\",\"signature\":\"0xaae38bcf9f946921541b44c2a66596968beecb9420471e2c9c531f758a2d652930ffdeeab95742e57e8520fb5c8ca4fee6a8e47e37336d4201fe104103f85e111c\",\"verificationGasLimit\":\"1500000\"}"); + } } diff --git a/tests/chains/Ethereum/EIP4337Tests.cpp b/tests/chains/Ethereum/EIP4337Tests.cpp index 294a3dc75e5..0d702aabde4 100644 --- a/tests/chains/Ethereum/EIP4337Tests.cpp +++ b/tests/chains/Ethereum/EIP4337Tests.cpp @@ -15,6 +15,15 @@ namespace TW::Ethereum::tests { +TEST(EthereumEip4337, GetEIP4337AccountInitializeBytecode) { + { + const std::string& ownerAddress = "0x78d9C32b96Bb872D66D51818227563f44e67E238"; + const std::string& factoryAddress = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92"; + const auto& initializeEncoded = Ethereum::getEIP4337AccountInitializeBytecode(ownerAddress, factoryAddress); + ASSERT_EQ(hexEncoded(initializeEncoded), "0x5a87209b755781cf65feeedd3855ade0317f4a925fbfb9cf00000000000000000000000078d9c32b96bb872d66d51818227563f44e67e2380000000000000000000000000000000000000000000000000000000000000000"); + } +} + TEST(EthereumEip4337, GetEIP4337LogicInitializeBytecode) { { const std::string& ownerAddress = "0xA5a1dddEF094095AfB7b6e322dE72961DF2e1988"; @@ -23,6 +32,17 @@ TEST(EthereumEip4337, GetEIP4337LogicInitializeBytecode) { } } +TEST(EthereumEip4337, GetEIP4337ExecuteBytecode) { + { + const Data& toAddress = parse_hex("0xce642355Fa553f408C34a2650Ad2F4A1634d033a"); + const uint256_t& value = 0x2386f26fc10000; + const Data data = {}; + const auto& executeEncoded = Ethereum::getEIP4337ExecuteBytecode(toAddress, value, data); + ASSERT_EQ(hexEncoded(executeEncoded), "0xb61d27f6000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000"); + } +} + +// // https://goerli.etherscan.io/address/0x5a87209b755781cf65feeedd3855ade0317f4a92#readContract TEST(EthereumEip4337, GetEIP4337DeploymentAddress) { // C++ diff --git a/tests/chains/Ethereum/SignerTests.cpp b/tests/chains/Ethereum/SignerTests.cpp index bb938626569..14de9e19dc9 100644 --- a/tests/chains/Ethereum/SignerTests.cpp +++ b/tests/chains/Ethereum/SignerTests.cpp @@ -109,4 +109,231 @@ TEST(EthereumSigner, EIP1559_1442) { EXPECT_EQ(hex(encoded), "02f8710306847735940084b2d05e0082526c94b9f5771c27664bf2282d98e09d7f50cec7cb01a78701ee0c29f50cb180c080a092c336138f7d0231fe9422bb30ee9ef10bf222761fe9e04442e3a11e88880c64a06487026011dae03dc281bc21c7d7ede5c2226d197befb813a4ecad686b559e58"); } +TEST(EthereumSigner, EIP4337_NativeTransfer_Account_Not_Deployed) { + const uint256_t chainID = 5; + const auto transaction = UserOperation::buildNativeTransfer( + parse_hex("0x1306b01bC3e4AD202612D3843387e94737673F53"), + parse_hex("0x5A87209b755781cF65fEeEdd3855ade0317f4a92"), + parse_hex("0x21cc27d7db4fa19857a3702653a7a67ee30ca620"), + parse_hex("0x78d9C32b96Bb872D66D51818227563f44e67E238"), + parse_hex("0xce642355Fa553f408C34a2650Ad2F4A1634d033a"), + 0x2386f26fc10000, + 0x00, + false, + 0x5580, + 0x073272, + 0x01952f1f85, + 0x0f, + 0xbc18 + ); + + const auto serialized = transaction->serialize(chainID); + const auto key = PrivateKey(parse_hex("f9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")); + const auto signature = Signer::sign(key, chainID, transaction); + const auto encoded = transaction->encoded(signature, chainID); + const auto result = std::string(encoded.begin(), encoded.end()); + + // https://goerli.etherscan.io/tx/0xf4e9c9899da7d083f260fd8d0d326a6a0e965f03444a32c73e30cd30ccc609f7 + EXPECT_EQ(result, "{\"callData\":\"0xb61d27f6000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"21888\",\"initCode\":\"0x5a87209b755781cf65feeedd3855ade0317f4a925fbfb9cf00000000000000000000000078d9c32b96bb872d66d51818227563f44e67e2380000000000000000000000000000000000000000000000000000000000000000\",\"maxFeePerGas\":\"6797860741\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"0\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"48152\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0x1560b19d17613ec8580cb0feaf7ac2953771404c5bd7830f585e5062e6ddd4b82ae3bb8dbddb659c0300e8009857b5c77501e1cfd5bbab48d03de0ea7207d07c1b\",\"verificationGasLimit\":\"471666\"}"); +} + +TEST(EthereumSigner, EIP4337_NativeTransfer_Account_Deployed) { + const uint256_t chainID = 5; + const auto transaction = UserOperation::buildNativeTransfer( + parse_hex("0x1306b01bC3e4AD202612D3843387e94737673F53"), + parse_hex("0x5A87209b755781cF65fEeEdd3855ade0317f4a92"), + parse_hex("0x21cc27d7db4fa19857a3702653a7a67ee30ca620"), + parse_hex("0x78d9C32b96Bb872D66D51818227563f44e67E238"), + parse_hex("0xce642355Fa553f408C34a2650Ad2F4A1634d033a"), + 0x2386f26fc10000, + 0x1, + true, + 0x9d55, + 0x186a0, + 0x1a339c9e9, + 0xf, + 0xb708 + ); + + const auto serialized = transaction->serialize(chainID); + const auto key = PrivateKey(parse_hex("f9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")); + const auto signature = Signer::sign(key, chainID, transaction); + const auto encoded = transaction->encoded(signature, chainID); + const auto result = std::string(encoded.begin(), encoded.end()); + + // https://goerli.etherscan.io/tx/0x707ee622b87a35eb2ffc3762553db8ba0efc5053cfdbeb44a841562df2a7c2bf + EXPECT_EQ(result, "{\"callData\":\"0xb61d27f6000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"40277\",\"initCode\":\"0x\",\"maxFeePerGas\":\"7033440745\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"1\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"46856\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0xaed2011e5cf267de495b38ecf86ad6f1d4c05217a99e59f47e8d52ba3d41c10144785893fa3e7c116a054999e3902fc2771064d0545148bc49f6d7c827fc7a9a1c\",\"verificationGasLimit\":\"100000\"}"); +} + +TEST(EthereumSigner, EIP4337_ERC20_Transfer_Account_Deployed) { + const uint256_t chainID = 5; + const auto transaction = UserOperation::buildERC20Transfer( + parse_hex("0x1306b01bC3e4AD202612D3843387e94737673F53"), + parse_hex("0x5A87209b755781cF65fEeEdd3855ade0317f4a92"), + parse_hex("0x21cc27d7db4fa19857a3702653a7a67ee30ca620"), + parse_hex("0x78d9C32b96Bb872D66D51818227563f44e67E238"), + parse_hex("0x98339d8c260052b7ad81c28c16c0b98420f2b46a"), + parse_hex("0xce642355Fa553f408C34a2650Ad2F4A1634d033a"), + 0x186a0, + 0x6, + true, + 0xf78e, + 0x186a0, + 0x168ad5950f, + 0xf, + 0xbb10 + ); + + const auto serialized = transaction->serialize(chainID); + const auto key = PrivateKey(parse_hex("f9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")); + const auto signature = Signer::sign(key, chainID, transaction); + const auto encoded = transaction->encoded(signature, chainID); + const auto result = std::string(encoded.begin(), encoded.end()); + + // https://goerli.etherscan.io/tx/0xe1c45f163cec0b9b2c3fd2307f75e48337d35c7c336ad96675c0adb6ce6fc58f + EXPECT_EQ(result, "{\"callData\":\"0xb61d27f600000000000000000000000098339d8c260052b7ad81c28c16c0b98420f2b46a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a00000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"63374\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"6\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"47888\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0xd006c93d6a8753b5e7c1e6349de0dea34eab2e7a533106e0f2e1a3a3b013c8e97b007546dab9d7b8fc471ad14ff2e8aa351dc4f1ecb63bf20f33858dc7366cbe1c\",\"verificationGasLimit\":\"100000\"}"); +} + +TEST(EthereumSigner, EIP4337_ERC20_Approve_Account_Deployed) { + const uint256_t chainID = 5; + const auto transaction = UserOperation::buildERC20Approve( + parse_hex("0x1306b01bC3e4AD202612D3843387e94737673F53"), + parse_hex("0x5A87209b755781cF65fEeEdd3855ade0317f4a92"), + parse_hex("0x21cc27d7db4fa19857a3702653a7a67ee30ca620"), + parse_hex("0x78d9C32b96Bb872D66D51818227563f44e67E238"), + parse_hex("0x98339d8c260052b7ad81c28c16c0b98420f2b46a"), + parse_hex("0xce642355Fa553f408C34a2650Ad2F4A1634d033a"), + 0x186a0, + 0x9, + true, + 0xf78e, + 0x186a0, + 0x168ad5950f, + 0xf, + 0xbb10); + + const auto serialized = transaction->serialize(chainID); + const auto key = PrivateKey(parse_hex("f9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")); + const auto signature = Signer::sign(key, chainID, transaction); + const auto encoded = transaction->encoded(signature, chainID); + const auto result = std::string(encoded.begin(), encoded.end()); + + // https://goerli.etherscan.io/tx/0xa267136c0a66534f86b04ef5ba0939e22b547d71ddc2e0ab31018696ef1c916f + EXPECT_EQ(result, "{\"callData\":\"0xb61d27f600000000000000000000000098339d8c260052b7ad81c28c16c0b98420f2b46a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a00000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"63374\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"9\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"47888\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0x262a67dd8cf3d16a72b7809b3b5ed55e9f4c2b93eedd5a3c6be035fbbd7111164464ec933d0fdfa359e266e318f3ac22702ae428ce14fc142e4475603e6ec15e1c\",\"verificationGasLimit\":\"100000\"}"); +} + +TEST(EthereumSigner, EIP4337_ERC721_Transfer_Account_Deployed) { + const uint256_t chainID = 5; + const auto transaction = UserOperation::buildERC721Transfer( + parse_hex("0x1306b01bC3e4AD202612D3843387e94737673F53"), + parse_hex("0x5A87209b755781cF65fEeEdd3855ade0317f4a92"), + parse_hex("0x21cc27d7db4fa19857a3702653a7a67ee30ca620"), + parse_hex("0x78d9C32b96Bb872D66D51818227563f44e67E238"), + parse_hex("0xf5de760f2e916647fd766b4ad9e85ff943ce3a2b"), + parse_hex("0x8cE23B8769ac01d0df0d5f47Be1A38FeA97F3879"), + parse_hex("0xce642355Fa553f408C34a2650Ad2F4A1634d033a"), + 0x2A8E57, + 12, + true, + 6337400, + 1500000, + 0x168ad5950f, + 0xf, + 49999); + + const auto serialized = transaction->serialize(chainID); + const auto key = PrivateKey(parse_hex("f9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")); + const auto signature = Signer::sign(key, chainID, transaction); + const auto encoded = transaction->encoded(signature, chainID); + const auto result = std::string(encoded.begin(), encoded.end()); + + // https://goerli.etherscan.io/tx/0x043f7cf4858c8480c8abbd5a5485bee11c8e70e7c6b87825a78eef00a42b662d + EXPECT_EQ(result, "{\"callData\":\"0xb61d27f6000000000000000000000000f5de760f2e916647fd766b4ad9e85ff943ce3a2b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000006423b872dd0000000000000000000000008ce23b8769ac01d0df0d5f47be1a38fea97f3879000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a00000000000000000000000000000000000000000000000000000000002a8e5700000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"6337400\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"12\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"49999\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0x5951cc161a4d60d6b59503efb93e446f5d1a2e3a41d4503ba6393bcf2a2637340d0a865ed5d4d7650a68cbb95915eaa7ed54fd2c42b4bf7c83376f5c5d70691d1b\",\"verificationGasLimit\":\"1500000\"}"); +} + +TEST(EthereumSigner, EIP4337_ERC1155_Transfer_Account_Deployed) { + const uint256_t chainID = 5; + const auto transaction = UserOperation::buildERC1155Transfer( + parse_hex("0x1306b01bC3e4AD202612D3843387e94737673F53"), + parse_hex("0x76627b8D1E01fAF0C73B69625BC1fCb8FA19a2AD"), + parse_hex("0x510ab68bd111ce7115df797118b0334d727d564b"), + parse_hex("0x78d9C32b96Bb872D66D51818227563f44e67E238"), + parse_hex("0x428ce4b916332e1afccfddce08baecc97cb40b12"), + parse_hex("0x8c560E00680b973645900528EDe71a99b8d4dca8"), + parse_hex("0xce642355Fa553f408C34a2650Ad2F4A1634d033a"), + 0x01, + 0, + {}, + 0, + true, + 6337400, + 1500000, + 0x168ad5950f, + 0xf, + 51000); + + const auto serialized = transaction->serialize(chainID); + const auto key = PrivateKey(parse_hex("f9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")); + const auto signature = Signer::sign(key, chainID, transaction); + const auto encoded = transaction->encoded(signature, chainID); + const auto result = std::string(encoded.begin(), encoded.end()); + + // https://goerli.etherscan.io/tx/0x6e9875715f2e46dfb45f6d7ba15dc8bd1561abb3ae7d19e549929835fca5f6af + EXPECT_EQ(result, "{\"callData\":\"0xb61d27f6000000000000000000000000428ce4b916332e1afccfddce08baecc97cb40b120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c4f242432a0000000000000000000000008c560e00680b973645900528ede71a99b8d4dca8000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"6337400\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"0\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"51000\",\"sender\":\"0x8c560e00680b973645900528ede71a99b8d4dca8\",\"signature\":\"0xaae38bcf9f946921541b44c2a66596968beecb9420471e2c9c531f758a2d652930ffdeeab95742e57e8520fb5c8ca4fee6a8e47e37336d4201fe104103f85e111c\",\"verificationGasLimit\":\"1500000\"}"); +} + +TEST(EthereumSigner, SignatureBreakdownNoEip155) { + const auto key = PrivateKey(parse_hex("f9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")); + const auto hash = parse_hex("0xf86a808509c7652400830130b9946b175474e89094c44da98b954eedeac495271d0f80b844a9059cbb0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000001bc16d674ec80000808080"); + const auto signature = Signer::sign(key, hash, false, 5); + + const auto r = store(signature.r); + EXPECT_EQ(hex(r), "d93fc9ae934d4f72db91cb149e7e84b50ca83b5a8a7b873b0fdb009546e3af47"); + + const auto v = store(signature.v); + EXPECT_EQ(hex(v), "00"); + + const auto s = store(signature.s); + EXPECT_EQ(hex(s), "786bfaf31af61eea6471dbb1bec7d94f73fb90887e4f04d0e9b85676c47ab02a"); + + const auto converted = Signer::simpleStructToSignatureData(signature); + EXPECT_EQ(hex(converted), "d93fc9ae934d4f72db91cb149e7e84b50ca83b5a8a7b873b0fdb009546e3af47786bfaf31af61eea6471dbb1bec7d94f73fb90887e4f04d0e9b85676c47ab02a00"); +} + +TEST(EthereumSigner, SignatureBreakdownEip155Legacy) { + const auto key = PrivateKey(parse_hex("f9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")); + const auto hash = parse_hex("0xf86a808509c7652400830130b9946b175474e89094c44da98b954eedeac495271d0f80b844a9059cbb0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000001bc16d674ec80000808080"); + const auto signature = Signer::sign(key, hash, true, 0); + + const auto r = store(signature.r); + EXPECT_EQ(hex(r), "d93fc9ae934d4f72db91cb149e7e84b50ca83b5a8a7b873b0fdb009546e3af47"); + + const auto v = store(signature.v); + EXPECT_EQ(hex(v), "1b"); + + const auto s = store(signature.s); + EXPECT_EQ(hex(s), "786bfaf31af61eea6471dbb1bec7d94f73fb90887e4f04d0e9b85676c47ab02a"); + + const auto converted = Signer::simpleStructToSignatureData(signature); + EXPECT_EQ(hex(converted), "d93fc9ae934d4f72db91cb149e7e84b50ca83b5a8a7b873b0fdb009546e3af47786bfaf31af61eea6471dbb1bec7d94f73fb90887e4f04d0e9b85676c47ab02a1b"); +} + +TEST(EthereumSigner, SignatureBreakdownEip155) { + const auto key = PrivateKey(parse_hex("f9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8")); + const auto hash = parse_hex("0xf86a808509c7652400830130b9946b175474e89094c44da98b954eedeac495271d0f80b844a9059cbb0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000001bc16d674ec80000808080"); + const auto signature = Signer::sign(key, hash, true, 1); + + const auto r = store(signature.r); + EXPECT_EQ(hex(r), "d93fc9ae934d4f72db91cb149e7e84b50ca83b5a8a7b873b0fdb009546e3af47"); + + const auto v = store(signature.v); + EXPECT_EQ(hex(v), "25"); + + const auto s = store(signature.s); + EXPECT_EQ(hex(s), "786bfaf31af61eea6471dbb1bec7d94f73fb90887e4f04d0e9b85676c47ab02a"); + + const auto converted = Signer::simpleStructToSignatureData(signature); + EXPECT_EQ(hex(converted), "d93fc9ae934d4f72db91cb149e7e84b50ca83b5a8a7b873b0fdb009546e3af47786bfaf31af61eea6471dbb1bec7d94f73fb90887e4f04d0e9b85676c47ab02a25"); +} + } // namespace TW::Ethereum diff --git a/tests/chains/Ethereum/TWAnySignerTests.cpp b/tests/chains/Ethereum/TWAnySignerTests.cpp index bf4079e3f77..40c50427be3 100644 --- a/tests/chains/Ethereum/TWAnySignerTests.cpp +++ b/tests/chains/Ethereum/TWAnySignerTests.cpp @@ -297,6 +297,321 @@ TEST(TWAnySignerEthereum, SignERC1155Transfer) { ASSERT_EQ(hex(output.data()), "f242432a000000000000000000000000718046867b5b1782379a14ea4fc0c9b724da94fc0000000000000000000000005322b34c88ed0691971bf52a7047448f0f4efc840000000000000000000000000000000000000000000000000000000023c47ee50000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000"); } +// EIP4337 + +TEST(TWAnySignerEthereum, EIP4337_SignTransferAccountNotDeployed) { + // https://goerli.etherscan.io/tx/0xf4e9c9899da7d083f260fd8d0d326a6a0e965f03444a32c73e30cd30ccc609f7 + Proto::SigningInput input; + auto chainId = store(uint256_t(5)); + auto nonce = store(uint256_t(0)); + auto amount = store(uint256_t(0x2386f26fc10000)); + auto gasLimit = store(uint256_t(0x5580)); + auto verificationGasLimit = store(uint256_t(0x073272)); + auto maxFeePerGas = store(uint256_t(0x01952f1f85)); + auto maxInclusionFeePerGas = store(uint256_t(0x0f)); + auto preVerificationGas = store(uint256_t(0xbc18)); + auto entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53"; + auto factory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92"; + auto logic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620"; + auto owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238"; + auto to = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a"; + + auto key = parse_hex("0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8"); + + input.set_chain_id(chainId.data(), chainId.size()); + input.set_nonce(nonce.data(), nonce.size()); + input.set_tx_mode(Proto::TransactionMode::UserOp); + input.set_gas_limit(gasLimit.data(), gasLimit.size()); + input.set_max_fee_per_gas(maxFeePerGas.data(), maxFeePerGas.size()); + input.set_max_inclusion_fee_per_gas(maxInclusionFeePerGas.data(), maxInclusionFeePerGas.size()); + input.set_to_address(to); + + auto& user_operation = *input.mutable_user_operation(); + user_operation.set_verification_gas_limit(verificationGasLimit.data(), verificationGasLimit.size()); + user_operation.set_pre_verification_gas(preVerificationGas.data(), preVerificationGas.size()); + user_operation.set_is_account_deployed(false); + user_operation.set_entry_point(entryPoint); + user_operation.set_account_factory(factory); + user_operation.set_account_logic(logic); + user_operation.set_owner(owner); + + input.set_private_key(key.data(), key.size()); + auto& transfer = *input.mutable_transaction()->mutable_transfer(); + transfer.set_amount(amount.data(), amount.size()); + + std::string expected = "{\"callData\":\"0xb61d27f6000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"21888\",\"initCode\":\"0x5a87209b755781cf65feeedd3855ade0317f4a925fbfb9cf00000000000000000000000078d9c32b96bb872d66d51818227563f44e67e2380000000000000000000000000000000000000000000000000000000000000000\",\"maxFeePerGas\":\"6797860741\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"0\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"48152\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0x1560b19d17613ec8580cb0feaf7ac2953771404c5bd7830f585e5062e6ddd4b82ae3bb8dbddb659c0300e8009857b5c77501e1cfd5bbab48d03de0ea7207d07c1b\",\"verificationGasLimit\":\"471666\"}"; + { + // sign test + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeEthereum); + + ASSERT_EQ(std::string(output.encoded()), expected); + } +} + +TEST(TWAnySignerEthereum, EIP4337_SignTransferAccountDeployed) { + // https://goerli.etherscan.io/tx/0x707ee622b87a35eb2ffc3762553db8ba0efc5053cfdbeb44a841562df2a7c2bf + Proto::SigningInput input; + auto chainId = store(uint256_t(5)); + auto nonce = store(uint256_t(1)); + auto amount = store(uint256_t(0x2386f26fc10000)); + auto gasLimit = store(uint256_t(0x9d55)); + auto verificationGasLimit = store(uint256_t(0x186a0)); + auto maxFeePerGas = store(uint256_t(0x1a339c9e9)); + auto maxInclusionFeePerGas = store(uint256_t(0xf)); + auto preVerificationGas = store(uint256_t(0xb708)); + auto entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53"; + auto factory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92"; + auto logic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620"; + auto owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238"; + auto to = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a"; + + auto key = parse_hex("0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8"); + + input.set_chain_id(chainId.data(), chainId.size()); + input.set_nonce(nonce.data(), nonce.size()); + input.set_tx_mode(Proto::TransactionMode::UserOp); + input.set_gas_limit(gasLimit.data(), gasLimit.size()); + input.set_max_fee_per_gas(maxFeePerGas.data(), maxFeePerGas.size()); + input.set_max_inclusion_fee_per_gas(maxInclusionFeePerGas.data(), maxInclusionFeePerGas.size()); + input.set_to_address(to); + + auto& user_operation = *input.mutable_user_operation(); + user_operation.set_verification_gas_limit(verificationGasLimit.data(), verificationGasLimit.size()); + user_operation.set_pre_verification_gas(preVerificationGas.data(), preVerificationGas.size()); + user_operation.set_is_account_deployed(true); + user_operation.set_entry_point(entryPoint); + user_operation.set_account_factory(factory); + user_operation.set_account_logic(logic); + user_operation.set_owner(owner); + + input.set_private_key(key.data(), key.size()); + auto& transfer = *input.mutable_transaction()->mutable_transfer(); + transfer.set_amount(amount.data(), amount.size()); + + std::string expected = "{\"callData\":\"0xb61d27f6000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"40277\",\"initCode\":\"0x\",\"maxFeePerGas\":\"7033440745\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"1\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"46856\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0xaed2011e5cf267de495b38ecf86ad6f1d4c05217a99e59f47e8d52ba3d41c10144785893fa3e7c116a054999e3902fc2771064d0545148bc49f6d7c827fc7a9a1c\",\"verificationGasLimit\":\"100000\"}"; + + { + // sign test + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeEthereum); + + ASSERT_EQ(std::string(output.encoded()), expected); + } +} + +TEST(TWAnySignerEthereum, EIP4337_SignERC20TransferAccountDeployed) { + // https://goerli.etherscan.io/tx/0xe1c45f163cec0b9b2c3fd2307f75e48337d35c7c336ad96675c0adb6ce6fc58f + Proto::SigningInput input; + auto chainId = store(uint256_t(5)); + auto nonce = store(uint256_t(6)); + auto amount = store(uint256_t(0x186a0)); + auto gasLimit = store(uint256_t(0xf78e)); + auto verificationGasLimit = store(uint256_t(0x186a0)); + auto maxFeePerGas = store(uint256_t(0x168ad5950f)); + auto maxInclusionFeePerGas = store(uint256_t(0xf)); + auto preVerificationGas = store(uint256_t(0xbb10)); + auto entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53"; + auto factory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92"; + auto logic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620"; + auto owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238"; + auto tokenContract = "0x98339d8c260052b7ad81c28c16c0b98420f2b46a"; + auto to = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a"; + + auto key = parse_hex("0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8"); + + input.set_chain_id(chainId.data(), chainId.size()); + input.set_nonce(nonce.data(), nonce.size()); + input.set_tx_mode(Proto::TransactionMode::UserOp); + input.set_gas_limit(gasLimit.data(), gasLimit.size()); + input.set_max_fee_per_gas(maxFeePerGas.data(), maxFeePerGas.size()); + input.set_max_inclusion_fee_per_gas(maxInclusionFeePerGas.data(), maxInclusionFeePerGas.size()); + input.set_to_address(tokenContract); + + auto& user_operation = *input.mutable_user_operation(); + user_operation.set_verification_gas_limit(verificationGasLimit.data(), verificationGasLimit.size()); + user_operation.set_pre_verification_gas(preVerificationGas.data(), preVerificationGas.size()); + user_operation.set_is_account_deployed(true); + user_operation.set_entry_point(entryPoint); + user_operation.set_account_factory(factory); + user_operation.set_account_logic(logic); + user_operation.set_owner(owner); + + input.set_private_key(key.data(), key.size()); + auto& transfer = *input.mutable_transaction()->mutable_erc20_transfer(); + transfer.set_amount(amount.data(), amount.size()); + transfer.set_to(to); + + std::string expected = "{\"callData\":\"0xb61d27f600000000000000000000000098339d8c260052b7ad81c28c16c0b98420f2b46a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a00000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"63374\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"6\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"47888\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0xd006c93d6a8753b5e7c1e6349de0dea34eab2e7a533106e0f2e1a3a3b013c8e97b007546dab9d7b8fc471ad14ff2e8aa351dc4f1ecb63bf20f33858dc7366cbe1c\",\"verificationGasLimit\":\"100000\"}"; + { + // sign test + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeEthereum); + + ASSERT_EQ(std::string(output.encoded()), expected); + } +} + +TEST(TWAnySignerEthereum, EIP4337_SignERC20ApproveAccountDeployed) { + // https://goerli.etherscan.io/tx/0xe1c45f163cec0b9b2c3fd2307f75e48337d35c7c336ad96675c0adb6ce6fc58f + Proto::SigningInput input; + auto chainId = store(uint256_t(5)); + auto nonce = store(uint256_t(9)); + auto amount = store(uint256_t(0x186a0)); + auto gasLimit = store(uint256_t(0xf78e)); + auto verificationGasLimit = store(uint256_t(0x186a0)); + auto maxFeePerGas = store(uint256_t(0x168ad5950f)); + auto maxInclusionFeePerGas = store(uint256_t(0xf)); + auto preVerificationGas = store(uint256_t(0xbb10)); + auto entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53"; + auto factory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92"; + auto logic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620"; + auto owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238"; + auto tokenContract = "0x98339d8c260052b7ad81c28c16c0b98420f2b46a"; + auto to = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a"; + + auto key = parse_hex("0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8"); + + input.set_chain_id(chainId.data(), chainId.size()); + input.set_nonce(nonce.data(), nonce.size()); + input.set_tx_mode(Proto::TransactionMode::UserOp); + input.set_gas_limit(gasLimit.data(), gasLimit.size()); + input.set_max_fee_per_gas(maxFeePerGas.data(), maxFeePerGas.size()); + input.set_max_inclusion_fee_per_gas(maxInclusionFeePerGas.data(), maxInclusionFeePerGas.size()); + input.set_to_address(tokenContract); + + auto& user_operation = *input.mutable_user_operation(); + user_operation.set_verification_gas_limit(verificationGasLimit.data(), verificationGasLimit.size()); + user_operation.set_pre_verification_gas(preVerificationGas.data(), preVerificationGas.size()); + user_operation.set_is_account_deployed(true); + user_operation.set_entry_point(entryPoint); + user_operation.set_account_factory(factory); + user_operation.set_account_logic(logic); + user_operation.set_owner(owner); + + input.set_private_key(key.data(), key.size()); + auto& transfer = *input.mutable_transaction()->mutable_erc20_approve(); + transfer.set_amount(amount.data(), amount.size()); + transfer.set_spender(to); + + std::string expected = "{\"callData\":\"0xb61d27f600000000000000000000000098339d8c260052b7ad81c28c16c0b98420f2b46a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a00000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"63374\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"9\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"47888\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0x262a67dd8cf3d16a72b7809b3b5ed55e9f4c2b93eedd5a3c6be035fbbd7111164464ec933d0fdfa359e266e318f3ac22702ae428ce14fc142e4475603e6ec15e1c\",\"verificationGasLimit\":\"100000\"}"; + { + // sign test + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeEthereum); + + ASSERT_EQ(std::string(output.encoded()), expected); + } +} + +TEST(TWAnySignerEthereum, EIP4337_SignERC721TransferAccountDeployed) { + // https://goerli.etherscan.io/tx/0x043f7cf4858c8480c8abbd5a5485bee11c8e70e7c6b87825a78eef00a42b662d + Proto::SigningInput input; + auto chainId = store(uint256_t(5)); + auto nonce = store(uint256_t(12)); + auto tokenId = store(uint256_t(0x2A8E57)); + auto gasLimit = store(uint256_t(6337400)); + auto verificationGasLimit = store(uint256_t(1500000)); + auto maxFeePerGas = store(uint256_t(0x168ad5950f)); + auto maxInclusionFeePerGas = store(uint256_t(0xf)); + auto preVerificationGas = store(uint256_t(49999)); + auto entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53"; + auto factory = "0x5A87209b755781cF65fEeEdd3855ade0317f4a92"; + auto logic = "0x21cc27d7db4fa19857a3702653a7a67ee30ca620"; + auto owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238"; + auto tokenContract = "0xf5de760f2e916647fd766b4ad9e85ff943ce3a2b"; + auto to = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a"; + auto from = "0x8cE23B8769ac01d0df0d5f47Be1A38FeA97F3879"; + + auto key = parse_hex("0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8"); + + input.set_chain_id(chainId.data(), chainId.size()); + input.set_nonce(nonce.data(), nonce.size()); + input.set_tx_mode(Proto::TransactionMode::UserOp); + input.set_gas_limit(gasLimit.data(), gasLimit.size()); + input.set_max_fee_per_gas(maxFeePerGas.data(), maxFeePerGas.size()); + input.set_max_inclusion_fee_per_gas(maxInclusionFeePerGas.data(), maxInclusionFeePerGas.size()); + input.set_to_address(tokenContract); + + auto& user_operation = *input.mutable_user_operation(); + user_operation.set_verification_gas_limit(verificationGasLimit.data(), verificationGasLimit.size()); + user_operation.set_pre_verification_gas(preVerificationGas.data(), preVerificationGas.size()); + user_operation.set_is_account_deployed(true); + user_operation.set_entry_point(entryPoint); + user_operation.set_account_factory(factory); + user_operation.set_account_logic(logic); + user_operation.set_owner(owner); + + input.set_private_key(key.data(), key.size()); + auto& transfer = *input.mutable_transaction()->mutable_erc721_transfer(); + transfer.set_token_id(tokenId.data(), tokenId.size()); + transfer.set_to(to); + transfer.set_from(from); + + std::string expected = "{\"callData\":\"0xb61d27f6000000000000000000000000f5de760f2e916647fd766b4ad9e85ff943ce3a2b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000006423b872dd0000000000000000000000008ce23b8769ac01d0df0d5f47be1a38fea97f3879000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a00000000000000000000000000000000000000000000000000000000002a8e5700000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"6337400\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"12\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"49999\",\"sender\":\"0x8ce23b8769ac01d0df0d5f47be1a38fea97f3879\",\"signature\":\"0x5951cc161a4d60d6b59503efb93e446f5d1a2e3a41d4503ba6393bcf2a2637340d0a865ed5d4d7650a68cbb95915eaa7ed54fd2c42b4bf7c83376f5c5d70691d1b\",\"verificationGasLimit\":\"1500000\"}"; + { + // sign test + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeEthereum); + + ASSERT_EQ(std::string(output.encoded()), expected); + } +} + +TEST(TWAnySignerEthereum, EIP4337_SignERC1155TransferAccountDeployed) { + // https://goerli.etherscan.io/tx/0x6e9875715f2e46dfb45f6d7ba15dc8bd1561abb3ae7d19e549929835fca5f6af + Proto::SigningInput input; + auto chainId = store(uint256_t(5)); + auto nonce = store(uint256_t(0)); + auto tokenId = store(uint256_t(0x01)); + auto gasLimit = store(uint256_t(6337400)); + auto verificationGasLimit = store(uint256_t(1500000)); + auto maxFeePerGas = store(uint256_t(0x168ad5950f)); + auto maxInclusionFeePerGas = store(uint256_t(0xf)); + auto preVerificationGas = store(uint256_t(51000)); + auto entryPoint = "0x1306b01bC3e4AD202612D3843387e94737673F53"; + auto factory = "0x76627b8D1E01fAF0C73B69625BC1fCb8FA19a2AD"; + auto logic = "0x510ab68bd111ce7115df797118b0334d727d564b"; + auto owner = "0x78d9C32b96Bb872D66D51818227563f44e67E238"; + auto tokenContract = "0x428ce4b916332e1afccfddce08baecc97cb40b12"; + auto to = "0xce642355Fa553f408C34a2650Ad2F4A1634d033a"; + auto from = "0x8c560E00680b973645900528EDe71a99b8d4dca8"; + + auto key = parse_hex("0xf9fb27c90dcaa5631f373330eeef62ae7931587a19bd8215d0c2addf28e439c8"); + + input.set_chain_id(chainId.data(), chainId.size()); + input.set_nonce(nonce.data(), nonce.size()); + input.set_tx_mode(Proto::TransactionMode::UserOp); + input.set_gas_limit(gasLimit.data(), gasLimit.size()); + input.set_max_fee_per_gas(maxFeePerGas.data(), maxFeePerGas.size()); + input.set_max_inclusion_fee_per_gas(maxInclusionFeePerGas.data(), maxInclusionFeePerGas.size()); + input.set_to_address(tokenContract); + + auto& user_operation = *input.mutable_user_operation(); + user_operation.set_verification_gas_limit(verificationGasLimit.data(), verificationGasLimit.size()); + user_operation.set_pre_verification_gas(preVerificationGas.data(), preVerificationGas.size()); + user_operation.set_is_account_deployed(true); + user_operation.set_entry_point(entryPoint); + user_operation.set_account_factory(factory); + user_operation.set_account_logic(logic); + user_operation.set_owner(owner); + + input.set_private_key(key.data(), key.size()); + auto& transfer = *input.mutable_transaction()->mutable_erc1155_transfer(); + transfer.set_token_id(tokenId.data(), tokenId.size()); + transfer.set_to(to); + transfer.set_from(from); + + std::string expected = "{\"callData\":\"0xb61d27f6000000000000000000000000428ce4b916332e1afccfddce08baecc97cb40b120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c4f242432a0000000000000000000000008c560e00680b973645900528ede71a99b8d4dca8000000000000000000000000ce642355fa553f408c34a2650ad2f4a1634d033a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"callGasLimit\":\"6337400\",\"initCode\":\"0x\",\"maxFeePerGas\":\"96818533647\",\"maxPriorityFeePerGas\":\"15\",\"nonce\":\"0\",\"paymasterAndData\":\"0x\",\"preVerificationGas\":\"51000\",\"sender\":\"0x8c560e00680b973645900528ede71a99b8d4dca8\",\"signature\":\"0xaae38bcf9f946921541b44c2a66596968beecb9420471e2c9c531f758a2d652930ffdeeab95742e57e8520fb5c8ca4fee6a8e47e37336d4201fe104103f85e111c\",\"verificationGasLimit\":\"1500000\"}"; + { + // sign test + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeEthereum); + + ASSERT_EQ(std::string(output.encoded()), expected); + } +} + TEST(TWAnySignerEthereum, SignJSON) { auto json = STRING(R"({"chainId":"AQ==","gasPrice":"1pOkAA==","gasLimit":"Ugg=","toAddress":"0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1","transaction":{"transfer":{"amount":"A0i8paFgAA=="}}})"); auto key = DATA("17209af590a86462395d5881e60d11c7fa7d482cfb02b5a01b93c2eeef243543"); From 3deeae2f308a8de85b3147a9b263441df517c703 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 6 Feb 2023 11:33:09 +0100 Subject: [PATCH 187/497] feat(fastlane): temporary disable mac build (#2911) --- swift/fastlane/Fastfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/fastlane/Fastfile b/swift/fastlane/Fastfile index 298bcb35a56..5fa18ea4945 100644 --- a/swift/fastlane/Fastfile +++ b/swift/fastlane/Fastfile @@ -13,7 +13,7 @@ platform :ios do create_xcframework( workspace: 'TrustWalletCore.xcworkspace', scheme: 'WalletCore', - destinations: ['iOS', 'macOS'], + destinations: ['iOS'], xcframework_output_directory: 'build', enable_bitcode: false ) @@ -24,7 +24,7 @@ platform :ios do create_xcframework( workspace: 'TrustWalletCore.xcworkspace', scheme: 'SwiftProtobuf', - destinations: ['iOS', 'macOS'], + destinations: ['iOS'], xcframework_output_directory: 'build', enable_bitcode: false ) From d8ddf7b8102a0ae505ced10b3ccdcb884fedeef7 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 7 Feb 2023 06:32:54 +0100 Subject: [PATCH 188/497] Re-enable rust build for mac catalyst (#2913) --- .github/workflows/linux-ci-sonarcloud.yml | 2 +- .github/workflows/linux-ci.yml | 2 +- .github/workflows/linux-sampleapp-ci.yml | 2 +- .github/workflows/wasm-ci.yml | 2 +- swift/common-xcframework.yml | 2 +- swift/project.yml | 2 +- tools/ios-build | 3 +- tools/rust-bindgen | 77 +++++++++++++++++++++++ 8 files changed, 85 insertions(+), 7 deletions(-) diff --git a/.github/workflows/linux-ci-sonarcloud.yml b/.github/workflows/linux-ci-sonarcloud.yml index 8941656e9b5..dd1829a065c 100644 --- a/.github/workflows/linux-ci-sonarcloud.yml +++ b/.github/workflows/linux-ci-sonarcloud.yml @@ -9,7 +9,7 @@ on: jobs: build: if: github.event.pull_request.head.repo.fork == false - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install system dependencies diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 5bef8727e51..944ee976432 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -8,7 +8,7 @@ on: jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install system dependencies diff --git a/.github/workflows/linux-sampleapp-ci.yml b/.github/workflows/linux-sampleapp-ci.yml index 7ed0fdcbbb0..c963437f5d3 100644 --- a/.github/workflows/linux-sampleapp-ci.yml +++ b/.github/workflows/linux-sampleapp-ci.yml @@ -8,7 +8,7 @@ on: jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install system dependencies diff --git a/.github/workflows/wasm-ci.yml b/.github/workflows/wasm-ci.yml index d41158c4933..3eba0a86a70 100644 --- a/.github/workflows/wasm-ci.yml +++ b/.github/workflows/wasm-ci.yml @@ -8,7 +8,7 @@ on: jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/swift/common-xcframework.yml b/swift/common-xcframework.yml index d556db5dcdc..dae0d4b55c7 100644 --- a/swift/common-xcframework.yml +++ b/swift/common-xcframework.yml @@ -45,7 +45,7 @@ targets: - framework: WalletCoreRs.xcframework settings: SKIP_INSTALL: false - SUPPORTS_MACCATALYST: false + SUPPORTS_MACCATALYST: true INFOPLIST_FILE: 'Info.plist' CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION: YES_ERROR CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER: $(inherited) false diff --git a/swift/project.yml b/swift/project.yml index 69afe8dff90..df46f6a29e5 100644 --- a/swift/project.yml +++ b/swift/project.yml @@ -45,7 +45,7 @@ targets: gatherCoverageData: true settings: SKIP_INSTALL: false - SUPPORTS_MACCATALYST: false + SUPPORTS_MACCATALYST: true DEBUG_INFORMATION_FORMAT: dwarf-with-dsym BUILD_LIBRARY_FOR_DISTRIBUTION: true INFOPLIST_FILE: 'Info.plist' diff --git a/tools/ios-build b/tools/ios-build index ace228be684..c7ddc0e5721 100755 --- a/tools/ios-build +++ b/tools/ios-build @@ -47,13 +47,14 @@ create_xc_framework() { xcodebuild -create-xcframework -output $BUILD_FOLDER/$FRAMEWORK.xcframework \ -framework $BUILD_FOLDER/ios-arm64.xcarchive/Products/Library/Frameworks/$FRAMEWORK.framework \ -framework $BUILD_FOLDER/ios-arm64_x86_64-simulator.xcarchive/Products/Library/Frameworks/$FRAMEWORK.framework \ + -framework $BUILD_FOLDER/ios-x86_64_arm64-maccatalyst.xcarchive/Products/Library/Frameworks/$FRAMEWORK.framework \ -framework $BUILD_FOLDER/macos-arm64_x86_64.xcarchive/Products/Library/Frameworks/$FRAMEWORK.framework } main() { init build_mac_x64_arm64 - #build_ios_mac_catalyst + build_ios_mac_catalyst build_ios_arm64 && build_ios_simulator create_xc_framework } diff --git a/tools/rust-bindgen b/tools/rust-bindgen index c866a43b2ee..044e16faf6a 100755 --- a/tools/rust-bindgen +++ b/tools/rust-bindgen @@ -11,6 +11,8 @@ HEADER_NAME="WalletCoreRSBindgen.h" create_xc_framework() { rm -rf $TARGET_XCFRAMEWORK_NAME xcodebuild -create-xcframework -library $BUILD_FOLDER/$TARGET_NAME -library $BUILD_FOLDER/darwin_universal/$TARGET_NAME -library $BUILD_FOLDER/aarch64-apple-ios/release/$TARGET_NAME -output $TARGET_XCFRAMEWORK_NAME + mkdir -p $TARGET_XCFRAMEWORK_NAME/ios-arm64_x86_64-maccatalyst + cp $BUILD_FOLDER/catalyst/$TARGET_NAME $TARGET_XCFRAMEWORK_NAME/ios-arm64_x86_64-maccatalyst } cd rust @@ -43,3 +45,78 @@ fi cbindgen --crate $CRATE --output ../src/rust/bindgen/$HEADER_NAME cd - cp build/local/release/${TARGET_NAME} build/local/lib/ + +if [[ `uname` == "Darwin" ]]; then +cd rust +cat > $TARGET_XCFRAMEWORK_NAME/Info.plist << EOF + + + + + AvailableLibraries + + + LibraryIdentifier + macos-arm64_x86_64 + LibraryPath + libwallet_core_rs.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + macos + + + LibraryIdentifier + ios-arm64_x86_64-maccatalyst + LibraryPath + libwallet_core_rs.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + maccatalyst + + + LibraryIdentifier + ios-arm64 + LibraryPath + libwallet_core_rs.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + libwallet_core_rs.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + +EOF +cd - +fi From 074c93e583714268da84f716607c0514973e3552 Mon Sep 17 00:00:00 2001 From: Ruslan Serebriakov Date: Tue, 7 Feb 2023 05:33:51 +0000 Subject: [PATCH 189/497] Some post-PR cleanups (#2914) --- .../ethereum/TestEthereumAddress.kt | 9 ------- include/TrustWalletCore/TWEthereum.h | 10 ------- src/Ethereum/EIP1014.cpp | 5 ---- src/Ethereum/EIP1014.h | 1 - src/Ethereum/EIP4337.cpp | 2 +- src/Ethereum/Transaction.cpp | 4 +-- src/interface/TWEthereum.cpp | 7 ----- swift/Tests/Blockchains/EthereumTests.swift | 8 ------ tests/chains/Ethereum/EIP1014Tests.cpp | 26 ------------------- 9 files changed, 3 insertions(+), 69 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt index 3089d9bd510..9c3ec88fd7d 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt @@ -15,15 +15,6 @@ class TestEthereumAddress { System.loadLibrary("TrustWalletCore") } - @Test - fun testEthereumCreate2Addresses() { - val from = "0x0000000000000000000000000000000000000000" - val salt = Numeric.hexStringToByteArray("0x0000000000000000000000000000000000000000000000000000000000000000") - val initCodeHash = Hash.keccak256(Numeric.hexStringToByteArray("0x0")) - val result = Ethereum.eip1014AddressCreate2(from, salt, initCodeHash) - assertEquals(result, "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38") - } - @Test fun testEthereumAddresses() { val any = AnyAddress("0x7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1", CoinType.ETHEREUM) diff --git a/include/TrustWalletCore/TWEthereum.h b/include/TrustWalletCore/TWEthereum.h index 9fab0ddba90..b65a9281a97 100644 --- a/include/TrustWalletCore/TWEthereum.h +++ b/include/TrustWalletCore/TWEthereum.h @@ -7,7 +7,6 @@ #pragma once #include "TWBase.h" -#include "TWData.h" #include "TWString.h" TW_EXTERN_C_BEGIN @@ -15,15 +14,6 @@ TW_EXTERN_C_BEGIN TW_EXPORT_STRUCT struct TWEthereum; -/// EIP-1014: Skinny CREATE2 (guess smart contract create2 address) -/// -/// \param fromEthAddress valid eth address -/// \param salt always 32 bytes stack item -/// \param initCodeHash The init_code is the code that, when executed, produces the runtime bytecode that will be placed into the state, and which typically is used by high level languages to implement a ‘constructor’. Need to be provided hashed with keccak256 -/// \return Ethereum resulting address -TW_EXPORT_STATIC_METHOD -TWString* _Nonnull TWEthereumEip1014AddressCreate2(TWString* _Nonnull fromEthAddress, TWData* _Nonnull salt, TWData* _Nonnull initCodeHash); - /// Generate a layer 2 eip2645 derivation path from eth address, layer, application and given index. /// /// \param wallet non-null TWHDWallet diff --git a/src/Ethereum/EIP1014.cpp b/src/Ethereum/EIP1014.cpp index 4242126a8d1..dfc3be3efae 100644 --- a/src/Ethereum/EIP1014.cpp +++ b/src/Ethereum/EIP1014.cpp @@ -26,9 +26,4 @@ Data create2Address(const std::string& from, const Data& salt, const Data& initC return Data(hash.end() - 20, hash.end()); } -std::string create2AddressString(const std::string& from, const Data& salt, const Data& initCodeHash) { - auto addressData = create2Address(from, salt, initCodeHash); - return Ethereum::checksumed(Address(hexEncoded(addressData))); -} - } // namespace TW::Ethereum diff --git a/src/Ethereum/EIP1014.h b/src/Ethereum/EIP1014.h index d1bde394e22..3356fe926e8 100644 --- a/src/Ethereum/EIP1014.h +++ b/src/Ethereum/EIP1014.h @@ -11,6 +11,5 @@ namespace TW::Ethereum { Data create2Address(const std::string& from, const Data& salt, const Data& initCodeHash); -std::string create2AddressString(const std::string& from, const Data& salt, const Data& initCodeHash); } diff --git a/src/Ethereum/EIP4337.cpp b/src/Ethereum/EIP4337.cpp index e377f996c24..f80e9d59c27 100644 --- a/src/Ethereum/EIP4337.cpp +++ b/src/Ethereum/EIP4337.cpp @@ -57,7 +57,7 @@ std::string getEIP4337DeploymentAddress(const std::string& factoryAddress, const const Data proxyInitCode = getEIP1967ProxyInitCode(logicAddress, logicInitializeBytecode); const Data salt = parse_hex("0x0000000000000000000000000000000000000000000000000000000000000000"); const Data initCodeHash = Hash::keccak256(proxyInitCode); - return create2AddressString(factoryAddress, salt, initCodeHash); + return Ethereum::checksumed(Address(hexEncoded(create2Address(factoryAddress, salt, initCodeHash)))); } } // namespace TW::Ethereum diff --git a/src/Ethereum/Transaction.cpp b/src/Ethereum/Transaction.cpp index bb168b91cee..f81415dab3d 100644 --- a/src/Ethereum/Transaction.cpp +++ b/src/Ethereum/Transaction.cpp @@ -234,7 +234,7 @@ Data UserOperation::preHash(const uint256_t chainID) const { return MessageSigner::generateMessage(hashStr); } -Data UserOperation::serialize(const uint256_t chainID) const { +Data UserOperation::serialize([[maybe_unused]] const uint256_t chainID) const { auto params = ABI::ParamTuple(ParamCollection{ std::make_shared(sender), std::make_shared(nonce), @@ -253,7 +253,7 @@ Data UserOperation::serialize(const uint256_t chainID) const { return Data(serialized.begin(), serialized.end() - 32); // remove trailing word (zero-length signature) } -Data UserOperation::encoded(const Signature& signature, const uint256_t chainID) const { +Data UserOperation::encoded(const Signature& signature, [[maybe_unused]] const uint256_t chainID) const { Data rawSignature = Signer::simpleStructToSignatureData(signature); rawSignature[64] += 27; diff --git a/src/interface/TWEthereum.cpp b/src/interface/TWEthereum.cpp index ee8c42a7b85..4e9440268d5 100644 --- a/src/interface/TWEthereum.cpp +++ b/src/interface/TWEthereum.cpp @@ -12,13 +12,6 @@ #include -TWString* TWEthereumEip1014AddressCreate2(TWString* _Nonnull fromEthAddress, TWData* _Nonnull salt, TWData* _Nonnull initCodeHash) { - const auto& ethAddressStr = *reinterpret_cast(fromEthAddress); - const auto& saltData = *reinterpret_cast(salt); - const auto& initCodeHashData = *reinterpret_cast(initCodeHash); - return new std::string(TW::Ethereum::create2AddressString(ethAddressStr, saltData, initCodeHashData)); -} - TWString* TWEthereumEip2645GetPath(TWString* ethAddress, TWString* layer, TWString* application, TWString* index) { const auto& ethAddressStr = *reinterpret_cast(ethAddress); const auto& layerStr = *reinterpret_cast(layer); diff --git a/swift/Tests/Blockchains/EthereumTests.swift b/swift/Tests/Blockchains/EthereumTests.swift index 8a67d5e9756..fc6e0e6dd4d 100644 --- a/swift/Tests/Blockchains/EthereumTests.swift +++ b/swift/Tests/Blockchains/EthereumTests.swift @@ -374,14 +374,6 @@ class EthereumTests: XCTestCase { // EIP4337 - func testCreate2Address() { - let address = "0x0000000000000000000000000000000000000000" - let salt = Data(hexString: "0x0000000000000000000000000000000000000000000000000000000000000000")! - let initCodeHash = Hash.keccak256(data: Data(hexString: "0x00")!) - let result = Ethereum.eip1014AddressCreate2(fromEthAddress: address, salt: salt, initCodeHash: initCodeHash) - XCTAssertEqual(result, "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38") - } - func testEIP4337DeploymentAddress() { let factoryAddress = "0xd9145CCE52D386f254917e481eB44e9943F39138" let logicAddress = "0x5C9eb5D6a6C2c1B3EFc52255C0b356f116f6f66D" diff --git a/tests/chains/Ethereum/EIP1014Tests.cpp b/tests/chains/Ethereum/EIP1014Tests.cpp index dab96107ebc..a13b9764090 100644 --- a/tests/chains/Ethereum/EIP1014Tests.cpp +++ b/tests/chains/Ethereum/EIP1014Tests.cpp @@ -23,16 +23,6 @@ namespace TW::Ethereum::tests { Data initCodeHash = Hash::keccak256(parse_hex("0x00")); const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38"); - ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38"); - } - - // C - { - const auto from = STRING("0x0000000000000000000000000000000000000000"); - const auto salt = DATA("0x0000000000000000000000000000000000000000000000000000000000000000"); - const auto initCodeHash = WRAPD(TWHashKeccak256(DATA("0x00").get())); - const auto& result = WRAPS(TWEthereumEip1014AddressCreate2(from.get(), salt.get(), initCodeHash.get())); - assertStringsEqual(result, "0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38"); } } @@ -44,16 +34,6 @@ namespace TW::Ethereum::tests { Data initCodeHash = Hash::keccak256(parse_hex("0x00")); const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0xB928f69Bb1D91Cd65274e3c79d8986362984fDA3"); - ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0xB928f69Bb1D91Cd65274e3c79d8986362984fDA3"); - } - - // C - { - const auto from = STRING("0xdeadbeef00000000000000000000000000000000"); - const auto salt = DATA("0x0000000000000000000000000000000000000000000000000000000000000000"); - const auto initCodeHash = WRAPD(TWHashKeccak256(DATA("0x00").get())); - const auto& result = WRAPS(TWEthereumEip1014AddressCreate2(from.get(), salt.get(), initCodeHash.get())); - assertStringsEqual(result, "0xB928f69Bb1D91Cd65274e3c79d8986362984fDA3"); } } @@ -64,7 +44,6 @@ namespace TW::Ethereum::tests { initCode.resize(32); const auto& addressData = Ethereum::create2Address(from, salt, initCode); ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x2DB27D1d6BE32C9abfA484BA3d591101881D4B9f"); - ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCode), "0x2DB27D1d6BE32C9abfA484BA3d591101881D4B9f"); } TEST(EthereumEip1014, Example3) { @@ -74,7 +53,6 @@ namespace TW::Ethereum::tests { initCode.resize(32); const auto& addressData = Ethereum::create2Address(from, salt, initCode); ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x219438aC82230Cb9A9C13Cd99D324fA1d66CF018"); - ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCode), "0x219438aC82230Cb9A9C13Cd99D324fA1d66CF018"); } TEST(EthereumEip1014, Example4) { @@ -83,7 +61,6 @@ namespace TW::Ethereum::tests { Data initCodeHash = Hash::keccak256(parse_hex("0xdeadbeef")); const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x60f3f640a8508fC6a86d45DF051962668E1e8AC7"); - ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0x60f3f640a8508fC6a86d45DF051962668E1e8AC7"); } TEST(EthereumEip1014, Example5) { @@ -92,7 +69,6 @@ namespace TW::Ethereum::tests { Data initCodeHash = Hash::keccak256(parse_hex("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x1d8bfDC5D46DC4f61D6b6115972536eBE6A8854C"); - ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0x1d8bfDC5D46DC4f61D6b6115972536eBE6A8854C"); } TEST(EthereumEip1014, Example6) { @@ -101,7 +77,6 @@ namespace TW::Ethereum::tests { Data initCodeHash = Hash::keccak256(parse_hex("0x")); const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0"); - ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0"); } TEST(EthereumEip1014, Example7) { @@ -110,6 +85,5 @@ namespace TW::Ethereum::tests { Data initCodeHash = Hash::keccak256(parse_hex("0x608060405260405162000c5138038062000c51833981810160405281019062000029919062000580565b6200003d828260006200004560201b60201c565b5050620007d7565b62000056836200008860201b60201c565b600082511180620000645750805b156200008357620000818383620000df60201b620000371760201c565b505b505050565b62000099816200011560201b60201c565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b60606200010d838360405180606001604052806027815260200162000c2a60279139620001eb60201b60201c565b905092915050565b6200012b816200027d60201b620000641760201c565b6200016d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000164906200066d565b60405180910390fd5b80620001a77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b620002a060201b620000871760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60606000808573ffffffffffffffffffffffffffffffffffffffff1685604051620002179190620006dc565b600060405180830381855af49150503d806000811462000254576040519150601f19603f3d011682016040523d82523d6000602084013e62000259565b606091505b50915091506200027286838387620002aa60201b60201c565b925050509392505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b606083156200031a5760008351036200031157620002ce856200027d60201b60201c565b62000310576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620003079062000745565b60405180910390fd5b5b8290506200032d565b6200032c83836200033560201b60201c565b5b949350505050565b600082511115620003495781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200037f9190620007b3565b60405180910390fd5b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620003c9826200039c565b9050919050565b620003db81620003bc565b8114620003e757600080fd5b50565b600081519050620003fb81620003d0565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b62000456826200040b565b810181811067ffffffffffffffff821117156200047857620004776200041c565b5b80604052505050565b60006200048d62000388565b90506200049b82826200044b565b919050565b600067ffffffffffffffff821115620004be57620004bd6200041c565b5b620004c9826200040b565b9050602081019050919050565b60005b83811015620004f6578082015181840152602081019050620004d9565b60008484015250505050565b6000620005196200051384620004a0565b62000481565b90508281526020810184848401111562000538576200053762000406565b5b62000545848285620004d6565b509392505050565b600082601f83011262000565576200056462000401565b5b81516200057784826020860162000502565b91505092915050565b600080604083850312156200059a576200059962000392565b5b6000620005aa85828601620003ea565b925050602083015167ffffffffffffffff811115620005ce57620005cd62000397565b5b620005dc858286016200054d565b9150509250929050565b600082825260208201905092915050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b600062000655602d83620005e6565b91506200066282620005f7565b604082019050919050565b60006020820190508181036000830152620006888162000646565b9050919050565b600081519050919050565b600081905092915050565b6000620006b2826200068f565b620006be81856200069a565b9350620006d0818560208601620004d6565b80840191505092915050565b6000620006ea8284620006a5565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b60006200072d601d83620005e6565b91506200073a82620006f5565b602082019050919050565b6000602082019050818103600083015262000760816200071e565b9050919050565b600081519050919050565b60006200077f8262000767565b6200078b8185620005e6565b93506200079d818560208601620004d6565b620007a8816200040b565b840191505092915050565b60006020820190508181036000830152620007cf818462000772565b905092915050565b61044380620007e76000396000f3fe6080604052366100135761001161001d565b005b61001b61001d565b005b610025610091565b610035610030610093565b6100a2565b565b606061005c83836040518060600160405280602781526020016103e7602791396100c8565b905092915050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000819050919050565b565b600061009d61014e565b905090565b3660008037600080366000845af43d6000803e80600081146100c3573d6000f35b3d6000fd5b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516100f291906102db565b600060405180830381855af49150503d806000811461012d576040519150601f19603f3d011682016040523d82523d6000602084013e610132565b606091505b5091509150610143868383876101a5565b925050509392505050565b600061017c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b610087565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606083156102075760008351036101ff576101bf85610064565b6101fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101f59061034f565b60405180910390fd5b5b829050610212565b610211838361021a565b5b949350505050565b60008251111561022d5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161026191906103c4565b60405180910390fd5b600081519050919050565b600081905092915050565b60005b8381101561029e578082015181840152602081019050610283565b60008484015250505050565b60006102b58261026a565b6102bf8185610275565b93506102cf818560208601610280565b80840191505092915050565b60006102e782846102aa565b915081905092915050565b600082825260208201905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000610339601d836102f2565b915061034482610303565b602082019050919050565b600060208201905081810360008301526103688161032c565b9050919050565b600081519050919050565b6000601f19601f8301169050919050565b60006103968261036f565b6103a081856102f2565b93506103b0818560208601610280565b6103b98161037a565b840191505092915050565b600060208201905081810360008301526103de818461038b565b90509291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220e57dd3eafc9985be746025b6d82d4f011b9a7bb3db56f9a1eb7eadfddd376b6064736f6c63430008110033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564000000000000000000000000d9ec9e840bb5df076dbbb488d01485058f421e5800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000024c4d66de8000000000000000000000000be8fa0112dcb7d21dc63645b633073651e19934800000000000000000000000000000000000000000000000000000000")); const auto& addressData = Ethereum::create2Address(from, salt, initCodeHash); ASSERT_EQ(Ethereum::checksumed(Ethereum::Address(hexEncoded(addressData))), "0x4455e5f0038795939c001aa4d296A45956C460AA"); - ASSERT_EQ(Ethereum::create2AddressString(from, salt, initCodeHash), "0x4455e5f0038795939c001aa4d296A45956C460AA"); } } From 66b89fd860d6075d51a2f2530ff772038691063d Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 7 Feb 2023 06:34:29 +0100 Subject: [PATCH 190/497] [ThorChain]: change deposit function to depositWithExpiry (#2912) --- src/THORChain/Swap.cpp | 17 +++++--- src/THORChain/Swap.h | 10 +++++ src/THORChain/TWSwap.cpp | 1 + src/proto/THORChainSwap.proto | 3 ++ tests/chains/THORChain/SwapTests.cpp | 62 +++++++++++++++------------- 5 files changed, 60 insertions(+), 33 deletions(-) diff --git a/src/THORChain/Swap.cpp b/src/THORChain/Swap.cpp index 52eb156d7be..4e2d41cabb7 100644 --- a/src/THORChain/Swap.cpp +++ b/src/THORChain/Swap.cpp @@ -256,12 +256,19 @@ SwapBundled SwapBuilder::buildEth(uint256_t amount, const std::string& memo) { input.set_to_address(*mRouterAddress); if (!toTokenId.empty()) { + if (!mExpirationPolicy) { + std::cout << "here"<< std::endl; + auto now = std::chrono::system_clock::now(); + auto in_15_minutes = now + std::chrono::minutes(15); + mExpirationPolicy = std::chrono::duration_cast(in_15_minutes.time_since_epoch()).count(); + } auto& transfer = *input.mutable_transaction()->mutable_contract_generic(); - auto func = Ethereum::ABI::Function("deposit", std::vector>{ - std::make_shared(vaultAddressBin), - std::make_shared(toAssetAddressBin), - std::make_shared(uint256_t(amount)), - std::make_shared(memo)}); + auto func = Ethereum::ABI::Function("depositWithExpiry", std::vector>{ + std::make_shared(vaultAddressBin), + std::make_shared(toAssetAddressBin), + std::make_shared(uint256_t(amount)), + std::make_shared(memo), + std::make_shared(uint256_t(*mExpirationPolicy))}); Data payload; func.encode(payload); transfer.set_data(payload.data(), payload.size()); diff --git a/src/THORChain/Swap.h b/src/THORChain/Swap.h index 926ef3535b1..54c5e41fceb 100644 --- a/src/THORChain/Swap.h +++ b/src/THORChain/Swap.h @@ -49,6 +49,7 @@ class SwapBuilder { std::optional mAffFeeAddress{std::nullopt}; std::optional mAffFeeRate{std::nullopt}; std::optional mExtraMemo{std::nullopt}; + std::optional mExpirationPolicy{std::nullopt}; SwapBundled buildBitcoin(uint256_t amount, const std::string& memo, Chain fromChain); SwapBundled buildBinance(Proto::Asset fromAsset, uint256_t amount, const std::string& memo); @@ -129,6 +130,15 @@ class SwapBuilder { return *this; } + SwapBuilder& expirationPolicy(std::size_t expirationTime) noexcept { + if (expirationTime > 0) { + mExpirationPolicy = expirationTime; + } else { + mExpirationPolicy = std::nullopt; + } + return *this; + } + std::string buildMemo(bool shortened = true) noexcept; SwapBundled build(bool shortened = true); diff --git a/src/THORChain/TWSwap.cpp b/src/THORChain/TWSwap.cpp index cad48c53aa6..c7da748de0c 100644 --- a/src/THORChain/TWSwap.cpp +++ b/src/THORChain/TWSwap.cpp @@ -36,6 +36,7 @@ TWData* _Nonnull TWTHORChainSwapBuildSwap(TWData* _Nonnull input) { .affFeeAddress(inputProto.affiliate_fee_address()) .affFeeRate(inputProto.affiliate_fee_rate_bp()) .extraMemo(inputProto.extra_memo()) + .expirationPolicy(inputProto.expiration_time()) .build(); outputProto.set_from_chain(fromChain); diff --git a/src/proto/THORChainSwap.proto b/src/proto/THORChainSwap.proto index 0d5d2c248b6..f29a09e3f41 100644 --- a/src/proto/THORChainSwap.proto +++ b/src/proto/THORChainSwap.proto @@ -84,6 +84,9 @@ message SwapInput { // Optional extra custom memo, reserved for later use. string extra_memo = 11; + + // Optional expirationTime, will be now() + 15 min if not set + uint64 expiration_time = 12; } // Result of the swap, a SigningInput struct for the specific chain diff --git a/tests/chains/THORChain/SwapTests.cpp b/tests/chains/THORChain/SwapTests.cpp index 372bfd70d9e..0e793cbc1b1 100644 --- a/tests/chains/THORChain/SwapTests.cpp +++ b/tests/chains/THORChain/SwapTests.cpp @@ -455,66 +455,72 @@ Data SwapTest_ethAddressStringToData(const std::string& asString) { TEST(THORChainSwap, SwapErc20Rune) { Proto::Asset fromAsset; - fromAsset.set_token_id("0xdAC17F958D2ee523a2206206994597C13D831ec7"); - fromAsset.set_chain(static_cast(Chain::ETH)); + fromAsset.set_token_id("0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E"); + fromAsset.set_chain(static_cast(Chain::AVAX)); Proto::Asset toAsset; toAsset.set_chain(static_cast(Chain::THOR)); toAsset.set_symbol("RUNE"); auto&& [out, errorCode, error] = SwapBuilder::builder() .from(fromAsset) .to(toAsset) - .fromAddress("0xd0972E2312518Ca15A2304D56ff9cc0b7ea0Ea37") - .toAddress("thor1du84c7fj5y7kphq7zfyp8ugwxgrmy6n07xm9yj") - .vault("0x97673DF37E718dF203A834Bd095F69F6b4F314FA") - .router("0xD37BbE5744D730a1d98d8DC97c42F0Ca46aD7146") - .fromAmount("5000000") - .toAmountLimit("418410520") + .fromAddress("0xbe6523017422A983B900b614Baeac51Ef7C1d0A3") + .toAddress("thor1ad6hapypumu7su5ad9qry2d74yt9d56fssa774") + .vault("0xa56f6Cb1D66cd80150b1ea79643b4C5900D6E36E") + .router("0x8f66c4ae756bebc49ec8b81966dd8bba9f127549") + .fromAmount("1000000") + .toAmountLimit("51638857") + .expirationPolicy(1775669796) + .affFeeAddress("t") + .affFeeRate("0") .build(); ASSERT_EQ(errorCode, 0); ASSERT_EQ(error, ""); - EXPECT_EQ(hex(out), "0a010012010018012201002a0100422a307844333742624535373434443733306131643938643844433937633432463043613436614437313436528d02328a020a01001284021fece7b400000000000000000000000097673df37e718df203a834bd095f69f6b4f314fa000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000413d3a54484f522e52554e453a74686f7231647538346337666a3579376b706871377a667970387567777867726d79366e3037786d39796a3a34313834313035323000000000000000000000000000000000000000000000000000000000000000"); + EXPECT_EQ(hex(out), "0a010012010018012201002a0100422a30783866363663346165373536626562633439656338623831393636646438626261396631323735343952ad0232aa020a010012a40244bc937b000000000000000000000000a56f6cb1d66cd80150b1ea79643b4c5900d6e36e000000000000000000000000b97ef9ef8734c71904d8002f8b6bc66dd9c48a6e00000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000069d6922400000000000000000000000000000000000000000000000000000000000000443d3a54484f522e52554e453a74686f72316164366861707970756d753773753561643971727932643734797439643536667373613737343a35313633383835373a743a3000000000000000000000000000000000000000000000000000000000"); auto tx = Ethereum::Proto::SigningInput(); ASSERT_TRUE(tx.ParseFromArray(out.data(), (int)out.size())); // check fields - EXPECT_EQ(tx.to_address(), "0xD37BbE5744D730a1d98d8DC97c42F0Ca46aD7146"); + EXPECT_EQ(tx.to_address(), "0x8f66c4ae756bebc49ec8b81966dd8bba9f127549"); ASSERT_TRUE(tx.transaction().has_contract_generic()); - Data vaultAddressBin = SwapTest_ethAddressStringToData("0x97673DF37E718dF203A834Bd095F69F6b4F314FA"); - EXPECT_EQ(hex(vaultAddressBin), "97673df37e718df203a834bd095f69f6b4f314fa"); - auto func = Ethereum::ABI::Function("deposit", std::vector>{ + Data vaultAddressBin = SwapTest_ethAddressStringToData("0xa56f6Cb1D66cd80150b1ea79643b4C5900D6E36E"); + EXPECT_EQ(hex(vaultAddressBin), "a56f6cb1d66cd80150b1ea79643b4c5900d6e36e"); + auto func = Ethereum::ABI::Function("depositWithExpiry", std::vector>{ std::make_shared(vaultAddressBin), - std::make_shared(parse_hex("0xdAC17F958D2ee523a2206206994597C13D831ec7")), - std::make_shared(uint256_t(5000000)), - std::make_shared("=:THOR.RUNE:thor1du84c7fj5y7kphq7zfyp8ugwxgrmy6n07xm9yj:418410520")}); + std::make_shared(parse_hex("0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E")), + std::make_shared(uint256_t(1000000)), + std::make_shared("=:THOR.RUNE:thor1ad6hapypumu7su5ad9qry2d74yt9d56fssa774:51638857:t:0"), + std::make_shared(uint256_t(1775669796))}); Data payload; func.encode(payload); - EXPECT_EQ(hex(payload), "1fece7b400000000000000000000000097673df37e718df203a834bd095f69f6b4f314fa000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000413d3a54484f522e52554e453a74686f7231647538346337666a3579376b706871377a667970387567777867726d79366e3037786d39796a3a34313834313035323000000000000000000000000000000000000000000000000000000000000000"); + EXPECT_EQ(hex(payload), "44bc937b000000000000000000000000a56f6cb1d66cd80150b1ea79643b4c5900d6e36e000000000000000000000000b97ef9ef8734c71904d8002f8b6bc66dd9c48a6e00000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000069d6922400000000000000000000000000000000000000000000000000000000000000443d3a54484f522e52554e453a74686f72316164366861707970756d753773753561643971727932643734797439643536667373613737343a35313633383835373a743a3000000000000000000000000000000000000000000000000000000000"); EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().amount())), "00"); EXPECT_EQ(hex(TW::data(tx.transaction().contract_generic().data())), hex(payload)); EXPECT_EQ(hex(TW::data(tx.private_key())), ""); // set few fields before signing - auto chainId = store(uint256_t(1)); + auto chainId = store(uint256_t(43114)); tx.set_chain_id(chainId.data(), chainId.size()); - auto nonce = store(uint256_t(7)); + auto nonce = store(uint256_t(6)); tx.set_nonce(nonce.data(), nonce.size()); - auto gasPrice = store(uint256_t(30000000000)); - tx.set_gas_price(gasPrice.data(), gasPrice.size()); - auto gasLimit = store(uint256_t(80000)); + auto maxInclusionFeePerGas = store(uint256_t(2000000000)); + auto maxFeePerGas = store(uint256_t(25000000000)); + tx.set_max_inclusion_fee_per_gas(maxInclusionFeePerGas.data(), maxInclusionFeePerGas.size()); + tx.set_max_fee_per_gas(maxFeePerGas.data(), maxFeePerGas.size()); + auto gasLimit = store(uint256_t(108810)); tx.set_gas_limit(gasLimit.data(), gasLimit.size()); - auto privKey = parse_hex("03a9ca895dca1623c7dfd69693f7b4111f5d819d2e145536e0b03c136025a25d"); + auto privKey = parse_hex("6649ba1d931059e7b419f97ee41c3f98b8f8054dfeb4cb57b9898bc5b9bbe318"); tx.set_private_key(privKey.data(), privKey.size()); // sign and encode resulting input Ethereum::Proto::SigningOutput output; - ANY_SIGN(tx, TWCoinTypeEthereum); - EXPECT_EQ(hex(output.encoded()), "02f90169010780808301388094d37bbe5744d730a1d98d8dc97c42f0ca46ad714680b901041fece7b400000000000000000000000097673df37e718df203a834bd095f69f6b4f314fa000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000413d3a54484f522e52554e453a74686f7231647538346337666a3579376b706871377a667970387567777867726d79366e3037786d39796a3a34313834313035323000000000000000000000000000000000000000000000000000000000000000c001a01ff085d06b39d6efeb6663b065758f463564a555e41070ca8a8398bb1fc3426ba018bd8c6897f86d6ca4af7fe4cfac92e3fcb6224f896df62376ac1df556744ac6"); - // https://viewblock.io/thorchain/tx/56D2A63608E6EC09FA1D2934457CC09196683013905F69EDFC72B33EC68681AA - // https://etherscan.io/tx/0x56d2a63608e6ec09fa1d2934457cc09196683013905f69edfc72b33ec68681aa - // https://viewblock.io/thorchain/tx/BC1464CF3B56B07E40CF57985511814AEC9EAE2F1329CEE059A21529FDDFDB8C + ANY_SIGN(tx, TWCoinTypeAvalancheCChain); + EXPECT_EQ(hex(output.encoded()), "02f9019482a86a0684773594008505d21dba008301a90a948f66c4ae756bebc49ec8b81966dd8bba9f12754980b9012444bc937b000000000000000000000000a56f6cb1d66cd80150b1ea79643b4c5900d6e36e000000000000000000000000b97ef9ef8734c71904d8002f8b6bc66dd9c48a6e00000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000069d6922400000000000000000000000000000000000000000000000000000000000000443d3a54484f522e52554e453a74686f72316164366861707970756d753773753561643971727932643734797439643536667373613737343a35313633383835373a743a3000000000000000000000000000000000000000000000000000000000c080a04a3a01941906579f1c6888771fe0621d66ee78998bfbb87219c0b5970235fc5ca03aefe4bb0c074f90798e078270c380930f4ae75366217f85535dd9be196a4244"); + // https://viewblock.io/thorchain/tx/B5E88D61157E7073995CA8729B75DAB2C1684A7B145DB711327CA4B8FF7DBDE7 + // https://snowtrace.io/tx/0xb5e88d61157e7073995ca8729b75dab2c1684a7b145db711327ca4b8ff7dbde7 + // https://thorchain.net/tx/B5E88D61157E7073995CA8729B75DAB2C1684A7B145DB711327CA4B8FF7DBDE7 } TEST(THORChainSwap, SwapAvaxBnb) { From 04534f52285ddc1a1576251ccd6cb283d8d2d55e Mon Sep 17 00:00:00 2001 From: Maxim Pestryakov Date: Fri, 10 Feb 2023 00:23:10 +0800 Subject: [PATCH 191/497] Add Kotlin Multiplatform support (#2894) --- .github/CODEOWNERS | 1 + .github/workflows/android-ci.yml | 18 +- .github/workflows/docker.yml | 2 +- .github/workflows/ios-ci.yml | 6 +- .github/workflows/kotlin-ci.yml | 48 + .github/workflows/linux-ci-sonarcloud.yml | 4 +- .github/workflows/linux-ci.yml | 4 +- .github/workflows/linux-sampleapp-ci.yml | 4 +- .github/workflows/wasm-ci.yml | 4 +- CMakeLists.txt | 8 +- codegen/bin/codegen | 12 + codegen/lib/code_generator.rb | 26 + codegen/lib/kotlin_helper.rb | 205 ++ codegen/lib/kotlin_jni_helper.rb | 113 + .../lib/templates/kotlin/android_class.erb | 56 + codegen/lib/templates/kotlin/android_enum.erb | 36 + .../lib/templates/kotlin/android_struct.erb | 19 + codegen/lib/templates/kotlin/common_class.erb | 55 + codegen/lib/templates/kotlin/common_enum.erb | 24 + .../lib/templates/kotlin/common_struct.erb | 13 + codegen/lib/templates/kotlin/ios_class.erb | 48 + codegen/lib/templates/kotlin/ios_enum.erb | 35 + codegen/lib/templates/kotlin/ios_struct.erb | 16 + codegen/lib/templates/kotlin/js_class.erb | 45 + codegen/lib/templates/kotlin/js_enum.erb | 32 + codegen/lib/templates/kotlin/js_struct.erb | 16 + codegen/lib/templates/kotlin/package.erb | 1 + codegen/lib/templates/kotlin_android.erb | 7 + codegen/lib/templates/kotlin_common.erb | 7 + codegen/lib/templates/kotlin_ios.erb | 7 + .../lib/templates/kotlin_jni/class_access.erb | 6 + .../lib/templates/kotlin_jni/compare_to.erb | 22 + .../lib/templates/kotlin_jni/enum_access.erb | 6 + .../templates/kotlin_jni/instance_access.erb | 14 + .../templates/kotlin_jni/instance_release.erb | 6 + codegen/lib/templates/kotlin_jni/method.erb | 8 + .../lib/templates/kotlin_jni/method_call.erb | 6 + .../templates/kotlin_jni/method_forward.erb | 118 + .../templates/kotlin_jni/method_prototype.erb | 9 + .../templates/kotlin_jni/parameter_access.erb | 23 + .../kotlin_jni/parameter_release.erb | 26 + .../lib/templates/kotlin_jni/proto_access.erb | 7 + .../templates/kotlin_jni/struct_access.erb | 8 + codegen/lib/templates/kotlin_jni_c.erb | 90 + codegen/lib/templates/kotlin_jni_h.erb | 66 + codegen/lib/templates/kotlin_js.erb | 7 + jni/{cpp => android}/AnySigner.c | 0 jni/{cpp => android}/AnySigner.h | 0 jni/cpp/Random.cpp | 4 +- jni/cpp/TWJNI.h | 2 +- jni/cpp/TWJNIData.cpp | 4 +- jni/cpp/TWJNIData.h | 2 +- jni/cpp/TWJNIString.cpp | 6 +- jni/cpp/TWJNIString.h | 2 +- jni/kotlin/AnySigner.c | 56 + jni/kotlin/AnySigner.h | 29 + kotlin/.editorconfig | 19 + kotlin/.gitignore | 2 + kotlin/README.md | 5 + kotlin/build-logic/build.gradle.kts | 14 + kotlin/build-logic/settings.gradle.kts | 23 + .../convention.file-generation.gradle.kts | 86 + .../convention.maven-publish.gradle.kts | 21 + kotlin/build.gradle.kts | 20 + kotlin/gradle.properties | 12 + kotlin/gradle/libs.versions.toml | 14 + kotlin/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + kotlin/gradlew | 244 ++ kotlin/gradlew.bat | 92 + kotlin/kotlin-js-store/yarn.lock | 2020 +++++++++++++++++ kotlin/settings.gradle.kts | 27 + kotlin/wallet-core-kotlin/.gitignore | 3 + kotlin/wallet-core-kotlin/build.gradle.kts | 130 ++ .../kotlin/com/trustwallet/core/AnySigner.kt | 15 + .../kotlin/com/trustwallet/core/AnySigner.kt | 32 + .../kotlin/com/trustwallet/core/AnySigner.kt | 19 + .../com/trustwallet/core/ByteArrayExt.kt | 18 + .../kotlin/com/trustwallet/core/StringExt.kt | 17 + .../src/jsMain/kotlin/WalletCore.kt | 27 + .../kotlin/com/trustwallet/core/AnySigner.kt | 25 + .../kotlin/com/trustwallet/core/UInt8Array.kt | 17 + tools/install-kotlin-dependencies | 7 + tools/kotlin-build | 8 + tools/kotlin-release | 17 + 85 files changed, 4309 insertions(+), 30 deletions(-) create mode 100644 .github/workflows/kotlin-ci.yml create mode 100644 codegen/lib/kotlin_helper.rb create mode 100644 codegen/lib/kotlin_jni_helper.rb create mode 100644 codegen/lib/templates/kotlin/android_class.erb create mode 100644 codegen/lib/templates/kotlin/android_enum.erb create mode 100644 codegen/lib/templates/kotlin/android_struct.erb create mode 100644 codegen/lib/templates/kotlin/common_class.erb create mode 100644 codegen/lib/templates/kotlin/common_enum.erb create mode 100644 codegen/lib/templates/kotlin/common_struct.erb create mode 100644 codegen/lib/templates/kotlin/ios_class.erb create mode 100644 codegen/lib/templates/kotlin/ios_enum.erb create mode 100644 codegen/lib/templates/kotlin/ios_struct.erb create mode 100644 codegen/lib/templates/kotlin/js_class.erb create mode 100644 codegen/lib/templates/kotlin/js_enum.erb create mode 100644 codegen/lib/templates/kotlin/js_struct.erb create mode 100644 codegen/lib/templates/kotlin/package.erb create mode 100644 codegen/lib/templates/kotlin_android.erb create mode 100644 codegen/lib/templates/kotlin_common.erb create mode 100644 codegen/lib/templates/kotlin_ios.erb create mode 100644 codegen/lib/templates/kotlin_jni/class_access.erb create mode 100644 codegen/lib/templates/kotlin_jni/compare_to.erb create mode 100644 codegen/lib/templates/kotlin_jni/enum_access.erb create mode 100644 codegen/lib/templates/kotlin_jni/instance_access.erb create mode 100644 codegen/lib/templates/kotlin_jni/instance_release.erb create mode 100644 codegen/lib/templates/kotlin_jni/method.erb create mode 100644 codegen/lib/templates/kotlin_jni/method_call.erb create mode 100644 codegen/lib/templates/kotlin_jni/method_forward.erb create mode 100644 codegen/lib/templates/kotlin_jni/method_prototype.erb create mode 100644 codegen/lib/templates/kotlin_jni/parameter_access.erb create mode 100644 codegen/lib/templates/kotlin_jni/parameter_release.erb create mode 100644 codegen/lib/templates/kotlin_jni/proto_access.erb create mode 100644 codegen/lib/templates/kotlin_jni/struct_access.erb create mode 100644 codegen/lib/templates/kotlin_jni_c.erb create mode 100644 codegen/lib/templates/kotlin_jni_h.erb create mode 100644 codegen/lib/templates/kotlin_js.erb rename jni/{cpp => android}/AnySigner.c (100%) rename jni/{cpp => android}/AnySigner.h (100%) create mode 100644 jni/kotlin/AnySigner.c create mode 100644 jni/kotlin/AnySigner.h create mode 100644 kotlin/.editorconfig create mode 100644 kotlin/.gitignore create mode 100644 kotlin/README.md create mode 100644 kotlin/build-logic/build.gradle.kts create mode 100644 kotlin/build-logic/settings.gradle.kts create mode 100644 kotlin/build-logic/src/main/kotlin/convention.file-generation.gradle.kts create mode 100644 kotlin/build-logic/src/main/kotlin/convention.maven-publish.gradle.kts create mode 100644 kotlin/build.gradle.kts create mode 100644 kotlin/gradle.properties create mode 100644 kotlin/gradle/libs.versions.toml create mode 100644 kotlin/gradle/wrapper/gradle-wrapper.jar create mode 100644 kotlin/gradle/wrapper/gradle-wrapper.properties create mode 100755 kotlin/gradlew create mode 100755 kotlin/gradlew.bat create mode 100644 kotlin/kotlin-js-store/yarn.lock create mode 100644 kotlin/settings.gradle.kts create mode 100644 kotlin/wallet-core-kotlin/.gitignore create mode 100644 kotlin/wallet-core-kotlin/build.gradle.kts create mode 100644 kotlin/wallet-core-kotlin/src/androidMain/kotlin/com/trustwallet/core/AnySigner.kt create mode 100644 kotlin/wallet-core-kotlin/src/commonMain/kotlin/com/trustwallet/core/AnySigner.kt create mode 100644 kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/AnySigner.kt create mode 100644 kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/ByteArrayExt.kt create mode 100644 kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/StringExt.kt create mode 100644 kotlin/wallet-core-kotlin/src/jsMain/kotlin/WalletCore.kt create mode 100644 kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/AnySigner.kt create mode 100644 kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/UInt8Array.kt create mode 100755 tools/install-kotlin-dependencies create mode 100755 tools/kotlin-build create mode 100755 tools/kotlin-release diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 79869e12cc8..533f10e3dcd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,3 +4,4 @@ # review when someone opens a pull request. * @hewigovens @rsrbk @milerius +kotlin/ @MaximPestryakov diff --git a/.github/workflows/android-ci.yml b/.github/workflows/android-ci.yml index 5203adc04dc..fc7f61fe874 100644 --- a/.github/workflows/android-ci.yml +++ b/.github/workflows/android-ci.yml @@ -8,15 +8,19 @@ on: jobs: build: - - runs-on: macos-12 + runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - name: Set up JDK 11 - uses: actions/setup-java@v1 + uses: actions/setup-java@v3 with: - java-version: 11 + java-version: '11' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 - name: Install system dependencies run: | @@ -28,7 +32,7 @@ jobs: - name: Cache internal dependencies id: internal_cache - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: build/local key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} @@ -36,7 +40,7 @@ jobs: - name: Install internal dependencies run: tools/install-dependencies if: steps.internal_cache.outputs.cache-hit != 'true' - + - name: Generate files run: tools/generate-files diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 369efae9cbd..fb7bf2d691a 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -16,7 +16,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Lint Dockerfile run: | curl -L https://github.com/hadolint/hadolint/releases/download/v1.17.6/hadolint-Linux-x86_64 -o hadolint && chmod +x hadolint diff --git a/.github/workflows/ios-ci.yml b/.github/workflows/ios-ci.yml index 61813885a4d..4490e8a48dd 100644 --- a/.github/workflows/ios-ci.yml +++ b/.github/workflows/ios-ci.yml @@ -8,16 +8,16 @@ on: jobs: build: - runs-on: macos-12 + runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install system dependencies run: | tools/install-sys-dependencies-mac tools/install-rust-dependencies - name: Cache internal dependencies id: internal_cache - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: build/local key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} diff --git a/.github/workflows/kotlin-ci.yml b/.github/workflows/kotlin-ci.yml new file mode 100644 index 00000000000..3e88aa6aa45 --- /dev/null +++ b/.github/workflows/kotlin-ci.yml @@ -0,0 +1,48 @@ +name: Kotlin CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + + - name: Install system dependencies + run: | + tools/install-sys-dependencies-mac + tools/install-rust-dependencies + + - name: Install Kotlin Dependencies + run: tools/install-kotlin-dependencies + + - name: Cache internal dependencies + id: internal_cache + uses: actions/cache@v3 + with: + path: build/local + key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} + + - name: Install internal dependencies + run: tools/install-dependencies + if: steps.internal_cache.outputs.cache-hit != 'true' + + - name: Generate files + run: tools/generate-files + + - name: Build Kotlin Multiplatform + run: tools/kotlin-build diff --git a/.github/workflows/linux-ci-sonarcloud.yml b/.github/workflows/linux-ci-sonarcloud.yml index dd1829a065c..5acae199798 100644 --- a/.github/workflows/linux-ci-sonarcloud.yml +++ b/.github/workflows/linux-ci-sonarcloud.yml @@ -11,14 +11,14 @@ jobs: if: github.event.pull_request.head.repo.fork == false runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install system dependencies run: | tools/install-sys-dependencies-linux tools/install-rust-dependencies - name: Cache internal dependencies id: internal_cache - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: build/local key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 944ee976432..84d53924e49 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -10,14 +10,14 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install system dependencies run: | tools/install-sys-dependencies-linux tools/install-rust-dependencies - name: Cache internal dependencies id: internal_cache - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: build/local key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} diff --git a/.github/workflows/linux-sampleapp-ci.yml b/.github/workflows/linux-sampleapp-ci.yml index c963437f5d3..acd7026a04c 100644 --- a/.github/workflows/linux-sampleapp-ci.yml +++ b/.github/workflows/linux-sampleapp-ci.yml @@ -10,14 +10,14 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install system dependencies run: | tools/install-sys-dependencies-linux tools/install-rust-dependencies - name: Cache internal dependencies id: internal_cache - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: build/local key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} diff --git a/.github/workflows/wasm-ci.yml b/.github/workflows/wasm-ci.yml index 3eba0a86a70..013b6be472f 100644 --- a/.github/workflows/wasm-ci.yml +++ b/.github/workflows/wasm-ci.yml @@ -10,7 +10,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install system dependencies run: | @@ -21,7 +21,7 @@ jobs: - name: Cache internal dependencies id: internal_cache - uses: actions/cache@v1.1.2 + uses: actions/cache@v3 with: path: build/local key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }} diff --git a/CMakeLists.txt b/CMakeLists.txt index a6dbdf3c1f0..f097a622916 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,13 @@ include(cmake/Protobuf.cmake) # Source files if (${ANDROID}) message("Configuring for JNI") - file(GLOB_RECURSE sources src/*.c src/*.cc src/*.cpp src/*.h jni/cpp/*.c jni/cpp/*.cpp jni/cpp/*.h jni/cpp/*.c) + file(GLOB_RECURSE core_sources src/*.c src/*.cc src/*.cpp src/*.h jni/cpp/*.c jni/cpp/*.cpp jni/cpp/*.h) + if (${KOTLIN}) + file(GLOB_RECURSE specific_sources jni/kotlin/*.h jni/kotlin/*.c) + else () + file(GLOB_RECURSE specific_sources jni/android/*.h jni/android/*.c) + endif() + set(sources ${core_sources} ${specific_sources}) add_library(TrustWalletCore SHARED ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) find_library(log-lib log) if (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "arm64-v8a") diff --git a/codegen/bin/codegen b/codegen/bin/codegen index 8fc86c7e86e..10dfda8d9ff 100755 --- a/codegen/bin/codegen +++ b/codegen/bin/codegen @@ -22,6 +22,7 @@ options.jni_h = true options.jni_c = true options.wasm_cpp = true options.ts_declaration = true +options.kotlin = true OptionParser.new do |opts| opts.banner = 'Usage: codegen [options]' @@ -50,6 +51,9 @@ OptionParser.new do |opts| opts.on('-t', '--typescript-declaration', "Generate typescript declaration file Default: #{options.ts_declaration}") do |v| options.ts_declaration = v end + opts.on('-k', '--kotlin', "Generate Kotlin code. Default: #{options.kotlin}") do |v| + options.kotlin = v + end opts.on_tail('-h', '--help', 'Show this message') do puts opts exit @@ -88,3 +92,11 @@ end if options.ts_declaration generator.render_ts_declaration end +if options.kotlin + generator.render_kotlin_common + generator.render_kotlin_android + generator.render_kotlin_ios + generator.render_kotlin_js + generator.render_kotlin_jni_h + generator.render_kotlin_jni_c +end diff --git a/codegen/lib/code_generator.rb b/codegen/lib/code_generator.rb index 7896c2f8dca..d870418b222 100644 --- a/codegen/lib/code_generator.rb +++ b/codegen/lib/code_generator.rb @@ -7,6 +7,8 @@ require 'swift_helper' require 'wasm_cpp_helper' require 'ts_helper' +require 'kotlin_helper' +require 'kotlin_jni_helper' # Code generation class CodeGenerator @@ -103,6 +105,30 @@ def render_ts_declaration TsHelper.combine_declaration_files() end + def render_kotlin_common + render_template(header: nil, template: 'kotlin_common.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/commonMain/generated/com/trustwallet/core', extension: 'kt') + end + + def render_kotlin_android + render_template(header: nil, template: 'kotlin_android.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/androidMain/generated/com/trustwallet/core', extension: 'kt') + end + + def render_kotlin_ios + render_template(header: nil, template: 'kotlin_ios.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/iosMain/generated/com/trustwallet/core', extension: 'kt') + end + + def render_kotlin_js + render_template(header: nil, template: 'kotlin_js.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/jsMain/generated/com/trustwallet/core', extension: 'kt') + end + + def render_kotlin_jni_h + render_template(header: 'copyright_header.erb', template: 'kotlin_jni_h.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/androidMain/cpp/generated', extension: 'h') + end + + def render_kotlin_jni_c + render_template(header: 'copyright_header.erb', template: 'kotlin_jni_c.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/androidMain/cpp/generated', extension: 'c') + end + def render(file, locals = {}) @locals = locals path = File.expand_path(file, File.join(File.dirname(__FILE__), 'templates')) diff --git a/codegen/lib/kotlin_helper.rb b/codegen/lib/kotlin_helper.rb new file mode 100644 index 00000000000..bd40ac74d97 --- /dev/null +++ b/codegen/lib/kotlin_helper.rb @@ -0,0 +1,205 @@ +# frozen_string_literal: true + +module KotlinHelper + # Transforms an interface name to a Java method name + def self.format_name(name) + return 'equals' if name == 'Equal' + + result = name + match = /^([A-Z]+)/.match(name) + result = name.sub(match[1], match[1].downcase) unless match.nil? + + result.sub(/_/, '') + end + + def self.parameters(params) + names = params.map do |param| + name = fix_name(param.name) + "#{name}: #{type(param.type)}" + end + names.join(', ') + end + + def self.calling_parameters_ios(params) + names = params.map do |param| + name = fix_name(param.name) + "#{name}#{convert_calling_type_ios(param.type)}" + end + names.join(', ') + end + + def self.calling_parameters_android(params) + names = params.map do |param| + fix_name(param.name) + end + names.join(', ') + end + + def self.calling_parameters_js(params) + names = params.map do |param| + name = fix_name(param.name) + "#{name}#{convert_calling_type_js(param.type)}" + end + names.join(', ') + end + + def self.fix_name(name) + case name + when '' + "value" + when 'val' + "value" + when 'return' + '`return`' + else + name + end + end + + def self.convert_calling_type_ios(t) + case t.name + when :data + "#{if t.is_nullable then '?' else '' end}.toTwData()" + when :string + "#{if t.is_nullable then '?' else '' end}.toTwString()" + else + if t.is_enum + "#{if t.is_nullable then '?' else '' end}.value" + elsif t.is_class + "#{if t.is_nullable then '?' else '' end}.pointer" + else + '' + end + end + end + + def self.convert_calling_type_js(t) + case t.name + when :data + "#{if t.is_nullable then '?' else '' end}.toUInt8Array()" + else + if t.is_enum + "#{if t.is_nullable then '?' else '' end}._value" + elsif t.is_class + "#{if t.is_nullable then '?' else '' end}._value" + else + '' + end + end + end + + def self.convert_calling_return_type_ios(t, expression = '') + case t.name + when :data + "#{expression}.readTwBytes()#{if t.is_nullable then '' else '!!' end}" + when :string + "#{expression}.fromTwString()#{if t.is_nullable then '' else '!!' end}" + else + if t.is_enum + "#{t.name}.fromValue(#{expression})#{if t.is_nullable then '' else '!!' end}" + elsif t.is_class + if t.is_nullable + "#{expression}?.let { #{t.name}(it) }" + else + "#{t.name}(#{expression}!!)" + end + else + expression + end + end + end + + def self.convert_calling_return_type_js(t, expression = '') + nullable = "#{if t.is_nullable then '?' else '' end}" + case t.name + when :void + expression + when :data + "#{expression}.unsafeCast()#{nullable}.toByteArray()" + when :int + "#{expression}.unsafeCast().toInt()" + when :uint8 + "#{expression}.unsafeCast().toByte().toUByte()" + when :uint16 + "#{expression}.unsafeCast().toShort().toUShort()" + when :uint32 + "#{expression}.unsafeCast().toInt().toUInt()" + when :uint64 + "#{expression}.unsafeCast().toLong().toULong()" + when :int8 + "#{expression}.unsafeCast().toByte()" + when :int16 + "#{expression}.unsafeCast().toShort()" + when :int32 + "#{expression}.unsafeCast().toInt()" + when :int64 + "#{expression}.unsafeCast().toLong()" + when :size + "#{expression}.unsafeCast().toLong().toULong()" + else + if t.is_enum + "#{t.name}.fromValue(#{expression})#{if t.is_nullable then '' else '!!' end}" + elsif t.is_class + if t.is_nullable + "#{expression}.unsafeCast()?.let { #{t.name}(it, Unit) }" + else + "#{t.name}(#{expression}, Unit)" + end + else + "#{expression} as #{type(t)}" + end + end + end + + def self.arguments(params) + params.map do |param| + param.name || 'value' + end.join(', ') + end + + def self.type(t) + nullable = "#{if t.is_nullable then '?' else '' end}" + case t.name + when :void + "" + when :bool + "Boolean#{nullable}" + when :int + "Int#{nullable}" + when :uint8 + "UByte#{nullable}" + when :uint16 + "UShort#{nullable}" + when :uint32 + "UInt#{nullable}" + when :uint64 + "ULong#{nullable}" + when :int8 + "Byte#{nullable}" + when :int16 + "Short#{nullable}" + when :int32 + "Int#{nullable}" + when :int64 + "Long#{nullable}" + when :size + "ULong#{nullable}" + when :data + "ByteArray#{nullable}" + when :string + "String#{nullable}" + else + "#{t.name}#{nullable}" + end + end + + def self.return_type(t) + case t.name + when :void + "" + else + ": #{type(t)}" + end + end + +end diff --git a/codegen/lib/kotlin_jni_helper.rb b/codegen/lib/kotlin_jni_helper.rb new file mode 100644 index 00000000000..b1303a6d69e --- /dev/null +++ b/codegen/lib/kotlin_jni_helper.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +module KotlinJniHelper + # Transforms an interface name to a JNI method name + def self.format_name(name) + return 'equals' if name == 'Equal' + + result = name + match = /^([A-Z]+)/.match(name) + result = name.sub(match[1], match[1].downcase) unless match.nil? + + result.sub(/_/, '') + end + + # Transforms a method/property name to a JNI function name + def self.function_name(entity:, function:, native_prefix: false) + "Java_com_trustwallet_core_#{entity.name}_#{format_name(function.name)}" + end + + # Transforms a proto name name to a JNI class name + def self.proto_to_class(name) + parts = name.split('_') + return nil if parts.count < 3 || parts[0] != 'TW' + + if parts.count == 3 + "wallet/core/jni/proto/Common$#{parts.last}" + else + "wallet/core/jni/proto/#{parts[1]}$#{parts[3]}" + end + end + + def self.parameters(params) + names = params.map do |param| + ", #{type(param.type)} #{param.name || 'value'}" + end + names.join('') + end + + def self.arguments(params) + params.map do |param| + if param.type.is_class + (param.name || 'value') + 'Instance' + elsif param.type.is_struct + '*' + (param.name || 'value') + 'Instance' + elsif param.type.name == :data + (param.name || 'value') + 'Data' + elsif param.type.name == :string + (param.name || 'value') + 'String' + elsif param.type.is_enum + (param.name || 'value') + 'Value' + elsif param.type.is_proto + (param.name || 'value') + 'Data' + else + param.name || 'value' + end + end + end + + def self.type(t) + case t.name + when :void + 'void' + when :bool + 'jboolean' + when :int + 'jint' + when :uint8 + 'jchar' + when :uint16 + 'jshort' + when :uint32 + 'jint' + when :uint64 + 'jlong' + when :int8 + 'jbyte' + when :int16 + 'jshort' + when :int32 + 'jint' + when :int64 + 'jlong' + when :size + 'jsize' + when :data + 'jbyteArray' + when 'Data' + 'jbyteArray' + when :string + 'jstring' + else + if t.is_class || t.is_struct + 'jobject' + elsif t.is_enum + 'jobject' + elsif t.is_proto + 'jobject' + else + raise "Invalid type #{t.name}" + end + end + end + + def self.compareMethod(entity) + FunctionDecl.new( + name: 'compareTo', + entity: entity, + is_method: true, + return_type: TypeDecl.new(name: :int), + parameters: [Parameter.new(name: 'thisObject', type: entity.type), Parameter.new(name: 'other', type: entity.type)], + static: false) + end +end diff --git a/codegen/lib/templates/kotlin/android_class.erb b/codegen/lib/templates/kotlin/android_class.erb new file mode 100644 index 00000000000..f3006d57526 --- /dev/null +++ b/codegen/lib/templates/kotlin/android_class.erb @@ -0,0 +1,56 @@ +<%= render('kotlin/package.erb') %> + +<% constructors = entity.static_methods.select { |method| method.name.start_with?('Create') } -%> +<% methods = entity.methods.select { |method| not method.name.start_with?('Delete') } -%> +<% static_methods = entity.static_methods.select { |method| not method.name.start_with?('Create') } -%> +actual class <%= entity.name %> private constructor( + private val nativeHandle: Long, +) { +<%# Constructors -%> +<%- constructors.each do |constructor| -%> + + actual constructor(<%= KotlinHelper.parameters(constructor.parameters) %>) : this(<%= KotlinHelper.format_name(constructor.name) %>(<%= KotlinHelper.calling_parameters_android(constructor.parameters) %>)) +<% end -%> +<%# Property declarations -%> +<% entity.properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + @JvmName("<%= KotlinHelper.format_name(property.name) %>") + external get +<% end -%> +<%# Method declarations -%> +<% methods.each do |method| -%> + + @JvmName("<%= KotlinHelper.format_name(method.name) %>") + actual external fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> +<% end -%> +<% if entity.static_properties.any? || static_methods.any? || constructors.any? -%> + + <%= if entity.static_properties.any? || static_methods.any? then "actual" else "private" end %> companion object { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + @JvmName("<%= KotlinHelper.format_name(property.name) %>") + external get +<% end -%> +<%# Static method declarations -%> +<% static_methods.each do |method| -%> + + @JvmStatic + @JvmName("<%= KotlinHelper.format_name(method.name) %>") + actual external fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> +<% end -%> + + @JvmStatic + @JvmName("createFromNative") + private fun createFromNative(nativeHandle: Long) = <%= entity.name %>(nativeHandle) +<%- constructors.each do |constructor| -%> + + @JvmStatic + @JvmName("<%= KotlinHelper.format_name(constructor.name) %>") + private external fun <%= KotlinHelper.format_name(constructor.name) %>(<%= KotlinHelper.parameters(constructor.parameters) %>): Long +<%- end -%> + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/android_enum.erb b/codegen/lib/templates/kotlin/android_enum.erb new file mode 100644 index 00000000000..4c9a44e523b --- /dev/null +++ b/codegen/lib/templates/kotlin/android_enum.erb @@ -0,0 +1,36 @@ +<%= render('kotlin/package.erb') %> + +actual enum class <%= entity.name %>( + @get:JvmName("value") + internal val value: UInt, +) { +<%# Cases -%> +<% entity.cases.each_with_index do |c, i| -%> + <%= c.name %>(<%= c.value %>u), +<% end -%> + ; +<%# Property declarations -%> +<%- entity.properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + @JvmName("<%= KotlinHelper.format_name(property.name) %>") + external get +<%- end -%> +<%# Method declarations -%> +<%- entity.methods.each do |method| -%> +<%- next if method.name.start_with?('Delete') -%> + + @JvmName("<%= KotlinHelper.format_name(method.name) %>") + actual external fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> +<%- end -%> +<%# Value -%> +<% if entity.cases.any? { |e| !e.value.nil? } -%> + + internal companion object { + @JvmStatic + @JvmName("createFromValue") + internal fun fromValue(value: UInt): <%= entity.name %>? = + values().firstOrNull { it.value == value } + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/android_struct.erb b/codegen/lib/templates/kotlin/android_struct.erb new file mode 100644 index 00000000000..099704dd35b --- /dev/null +++ b/codegen/lib/templates/kotlin/android_struct.erb @@ -0,0 +1,19 @@ +<%= render('kotlin/package.erb') %> + +actual object <%= entity.name %> { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + @JvmName("<%= KotlinHelper.format_name(property.name) %>") + external get +<% end -%> +<%# Static method declarations -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') -%> + + @JvmStatic + @JvmName("<%= KotlinHelper.format_name(method.name) %>") + actual external fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/common_class.erb b/codegen/lib/templates/kotlin/common_class.erb new file mode 100644 index 00000000000..b47c1eb85f0 --- /dev/null +++ b/codegen/lib/templates/kotlin/common_class.erb @@ -0,0 +1,55 @@ +<%= render('kotlin/package.erb') %> + +<% constructors = entity.static_methods.select { |method| method.name.start_with?('Create') } -%> +<% methods = entity.methods.select { |method| not method.name.start_with?('Delete') } -%> +<% static_methods = entity.static_methods.select { |method| not method.name.start_with?('Create') } -%> +<% if constructors.one? -%> +expect class <%= entity.name %>( +<%- constructors.first.parameters.each do |parameter| -%> + <%= KotlinHelper.parameters([parameter]) %>, +<%- end -%> +) { +<%- else -%> +expect class <%= entity.name %> { +<%# Constructors -%> +<% if constructors.any? -%> + +<% end -%> +<%- constructors.each do |constructor| -%> + constructor(<%= KotlinHelper.parameters(constructor.parameters) %>) +<%- end -%> +<% end -%> +<%# Property declarations -%> +<% if entity.properties.any? -%> + +<% end -%> +<% entity.properties.each do |property| -%> + val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> +<% end -%> +<%# Method declarations -%> +<% if methods.any? -%> + +<% end -%> +<% methods.each do |method| -%> + fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> +<% end -%> +<% if entity.static_properties.any? || static_methods.any? -%> + + companion object { +<%# Static property declarations -%> +<% if entity.static_properties.any? -%> + +<% end -%> +<% entity.static_properties.each do |property| -%> + val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> +<% end -%> +<%# Static method declarations -%> +<% if static_methods.any? -%> + +<% end -%> +<% static_methods.each do |method| -%> + fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> +<% end -%> + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/common_enum.erb b/codegen/lib/templates/kotlin/common_enum.erb new file mode 100644 index 00000000000..87f0d814598 --- /dev/null +++ b/codegen/lib/templates/kotlin/common_enum.erb @@ -0,0 +1,24 @@ +<%= render('kotlin/package.erb') %> + +expect enum class <%= entity.name %> { +<%# Cases -%> +<% entity.cases.each_with_index do |c, i| -%> + <%= c.name %>, +<% end -%> + ; +<%# Property declarations -%> +<%- entity.properties.each do |property| -%> + val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> +<%- end -%> +<%# Method declarations -%> +<% if entity.methods.any? -%> + +<% end -%> +<%- entity.methods.each do |method| -%> +<%- next if method.name.start_with?('Delete') -%> + fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> +<%- end -%> +<%# Value -%> +<% if entity.cases.any? { |e| !e.value.nil? } -%> +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/common_struct.erb b/codegen/lib/templates/kotlin/common_struct.erb new file mode 100644 index 00000000000..39e085799ea --- /dev/null +++ b/codegen/lib/templates/kotlin/common_struct.erb @@ -0,0 +1,13 @@ +<%= render('kotlin/package.erb') %> + +expect object <%= entity.name %> { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> +<% end -%> +<%# Static method declarations -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') -%> + fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/ios_class.erb b/codegen/lib/templates/kotlin/ios_class.erb new file mode 100644 index 00000000000..886be145b10 --- /dev/null +++ b/codegen/lib/templates/kotlin/ios_class.erb @@ -0,0 +1,48 @@ +<%= render('kotlin/package.erb') %> + +import cnames.structs.TW<%= entity.name %> +import kotlinx.cinterop.CPointer + +<% constructors = entity.static_methods.select { |method| method.name.start_with?('Create') } -%> +<% methods = entity.methods.select { |method| not method.name.start_with?('Delete') } -%> +<% static_methods = entity.static_methods.select { |method| not method.name.start_with?('Create') } -%> +actual class <%= entity.name %> internal constructor( + internal val pointer: CPointer>, +) { +<%# Constructors -%> +<%- constructors.each do |constructor| -%> + + actual constructor(<%= KotlinHelper.parameters(constructor.parameters) %>) : this( + TW<%= entity.name %><%= constructor.name %>(<%= KotlinHelper.calling_parameters_ios(constructor.parameters) %>)!! + ) +<% end -%> +<%# Property declarations -%> +<% entity.properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = <%= KotlinHelper.convert_calling_return_type_ios(property.return_type, "TW#{entity.name}#{property.name}(pointer)") %> +<% end -%> +<%# Method declarations -%> +<% methods.each do |method| -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_ios(method.return_type, "TW#{entity.name}#{method.name}(pointer#{', ' if not method.parameters.one?}#{KotlinHelper.calling_parameters_ios(method.parameters.drop(1))})") %> +<% end -%> +<% if entity.static_properties.any? || static_methods.any? -%> + + actual companion object { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = TW<%= entity.name %><%= property.name %>()<%= KotlinHelper.convert_calling_return_type_ios(property.return_type) %> +<% end -%> +<%# Static method declarations -%> +<% static_methods.each do |method| -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_ios(method.return_type, "TW#{entity.name}#{method.name}(#{KotlinHelper.calling_parameters_ios(method.parameters)})") %> +<% end -%> + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/ios_enum.erb b/codegen/lib/templates/kotlin/ios_enum.erb new file mode 100644 index 00000000000..cae9ff33f75 --- /dev/null +++ b/codegen/lib/templates/kotlin/ios_enum.erb @@ -0,0 +1,35 @@ +<%= render('kotlin/package.erb') %> + +import com.trustwallet.core.<%= "TW#{entity.name}" %>.* + +<% type = ": TW#{entity.name}" -%> +actual enum class <%= entity.name %>( + internal val value<%= type %>, +) { +<%# Cases -%> +<% entity.cases.each_with_index do |c, i| -%> + <%= c.name %>(TW<%= entity.name %><%= c.name %>), +<% end -%> + ; +<%# Property declarations -%> +<%- entity.properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = <%= KotlinHelper.convert_calling_return_type_ios(property.return_type, "TW#{entity.name}#{property.name}(value)") %> +<%- end -%> +<%# Method declarations -%> +<%- entity.methods.each do |method| -%> +<%- next if method.name.start_with?('Delete') -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> = + TW<%= entity.name %><%= method.name %>(value<%= ', ' if not method.parameters.one? %><%= KotlinHelper.calling_parameters_ios(method.parameters.drop(1)) %>)<%= KotlinHelper.convert_calling_return_type_ios(method.return_type) %> +<%- end -%> +<%# Value -%> +<% if entity.cases.any? { |e| !e.value.nil? } -%> + + internal companion object { + internal fun fromValue(value<%= type %>): <%= entity.name %>? = + values().firstOrNull { it.value == value } + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/ios_struct.erb b/codegen/lib/templates/kotlin/ios_struct.erb new file mode 100644 index 00000000000..6bf3da876ee --- /dev/null +++ b/codegen/lib/templates/kotlin/ios_struct.erb @@ -0,0 +1,16 @@ +<%= render('kotlin/package.erb') %> + +actual object <%= entity.name %> { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = TODO() +<% end -%> +<%# Static method declarations -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_ios(method.return_type, "TW#{entity.name}#{method.name}(#{KotlinHelper.calling_parameters_ios(method.parameters)})") %> +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/js_class.erb b/codegen/lib/templates/kotlin/js_class.erb new file mode 100644 index 00000000000..187cbbd940b --- /dev/null +++ b/codegen/lib/templates/kotlin/js_class.erb @@ -0,0 +1,45 @@ +<%= render('kotlin/package.erb') %> + +<% constructors = entity.static_methods.select { |method| method.name.start_with?('Create') } -%> +<% methods = entity.methods.select { |method| not method.name.start_with?('Delete') } -%> +<% static_methods = entity.static_methods.select { |method| not method.name.start_with?('Create') } -%> +actual class <%= entity.name %> constructor( + val _value: dynamic, + unit: Unit, // Hack +) { +<%# Constructors -%> +<%- constructors.each do |constructor| -%> + + actual constructor(<%= KotlinHelper.parameters(constructor.parameters) %>) : + this(WalletCore.Instance.<%= entity.name %>.<%= WasmCppHelper.function_name(entity: entity, function: constructor) %>(<%= KotlinHelper.calling_parameters_js(constructor.parameters) %>), Unit) +<% end -%> +<%# Property declarations -%> +<% entity.properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = <%= KotlinHelper.convert_calling_return_type_js(property.return_type, "_value.#{WasmCppHelper.function_name(entity: entity, function: property)}()") %> +<% end -%> +<%# Method declarations -%> +<% methods.each do |method| -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "_value.#{WasmCppHelper.function_name(entity: entity, function: method)}(#{KotlinHelper.calling_parameters_js(method.parameters.drop(1))})") %> +<% end -%> +<% if entity.static_properties.any? || static_methods.any? -%> + + <%= if entity.static_properties.any? || static_methods.any? then "actual" else "private" end %> companion object { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = TODO() +<% end -%> +<%# Static method declarations -%> +<% static_methods.each do |method| -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "WalletCore.Instance.#{entity.name}.#{WasmCppHelper.function_name(entity: entity, function: method)}(#{KotlinHelper.calling_parameters_js(method.parameters)})") %> +<% end -%> + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/js_enum.erb b/codegen/lib/templates/kotlin/js_enum.erb new file mode 100644 index 00000000000..d54ffcf6630 --- /dev/null +++ b/codegen/lib/templates/kotlin/js_enum.erb @@ -0,0 +1,32 @@ +<%= render('kotlin/package.erb') %> + +actual enum class <%= entity.name %>( + internal val _value: dynamic, +) { +<%# Cases -%> +<% entity.cases.each_with_index do |c, i| -%> + <%= c.name %>(WalletCore.Instance.<%= entity.name %>.<%= KotlinHelper.fix_name(WasmCppHelper.format_name(c.name)) %>), +<% end -%> + ; +<%# Property declarations -%> +<%- entity.properties.each do |property| -%> + + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = <%= KotlinHelper.convert_calling_return_type_js(property.return_type, "_value.#{WasmCppHelper.function_name(entity: entity, function: property)}()") %> +<%- end -%> +<%# Method declarations -%> +<%- entity.methods.each do |method| -%> +<%- next if method.name.start_with?('Delete') -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "_value.#{WasmCppHelper.function_name(entity: entity, function: method)}(#{KotlinHelper.calling_parameters_js(method.parameters.drop(1))})") %> +<%- end -%> +<%# Value -%> +<% if entity.cases.any? { |e| !e.value.nil? } -%> + + internal companion object { + internal fun fromValue(value: dynamic): <%= entity.name %>? = + values().firstOrNull { it._value == value } + } +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/js_struct.erb b/codegen/lib/templates/kotlin/js_struct.erb new file mode 100644 index 00000000000..80fd05feb72 --- /dev/null +++ b/codegen/lib/templates/kotlin/js_struct.erb @@ -0,0 +1,16 @@ +<%= render('kotlin/package.erb') %> + +actual object <%= entity.name %> { +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> + actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> + get() = TODO() +<% end -%> +<%# Static method declarations -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') -%> + + actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters) %>)<%= KotlinHelper.return_type(method.return_type) %> = + <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "WalletCore.Instance.#{entity.name}.#{WasmCppHelper.function_name(entity: entity, function: method)}(#{KotlinHelper.calling_parameters_js(method.parameters)})") %> +<% end -%> +} diff --git a/codegen/lib/templates/kotlin/package.erb b/codegen/lib/templates/kotlin/package.erb new file mode 100644 index 00000000000..64142a21c30 --- /dev/null +++ b/codegen/lib/templates/kotlin/package.erb @@ -0,0 +1 @@ +package com.trustwallet.core \ No newline at end of file diff --git a/codegen/lib/templates/kotlin_android.erb b/codegen/lib/templates/kotlin_android.erb new file mode 100644 index 00000000000..a9767e71d97 --- /dev/null +++ b/codegen/lib/templates/kotlin_android.erb @@ -0,0 +1,7 @@ +<%- if entity.is_a?(EnumDecl) -%> +<%= render('kotlin/android_enum.erb') -%> +<%- elsif entity.is_struct -%> +<%= render('kotlin/android_struct.erb') -%> +<%- else -%> +<%= render('kotlin/android_class.erb') -%> +<%- end -%> diff --git a/codegen/lib/templates/kotlin_common.erb b/codegen/lib/templates/kotlin_common.erb new file mode 100644 index 00000000000..31db319babd --- /dev/null +++ b/codegen/lib/templates/kotlin_common.erb @@ -0,0 +1,7 @@ +<%- if entity.is_a?(EnumDecl) -%> +<%= render('kotlin/common_enum.erb') -%> +<%- elsif entity.is_struct -%> +<%= render('kotlin/common_struct.erb') -%> +<%- else -%> +<%= render('kotlin/common_class.erb') -%> +<%- end -%> diff --git a/codegen/lib/templates/kotlin_ios.erb b/codegen/lib/templates/kotlin_ios.erb new file mode 100644 index 00000000000..272ad2cf1df --- /dev/null +++ b/codegen/lib/templates/kotlin_ios.erb @@ -0,0 +1,7 @@ +<%- if entity.is_a?(EnumDecl) -%> +<%= render('kotlin/ios_enum.erb') -%> +<%- elsif entity.is_struct -%> +<%= render('kotlin/ios_struct.erb') -%> +<%- else -%> +<%= render('kotlin/ios_class.erb') -%> +<%- end -%> diff --git a/codegen/lib/templates/kotlin_jni/class_access.erb b/codegen/lib/templates/kotlin_jni/class_access.erb new file mode 100644 index 00000000000..a260b8cfd35 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/class_access.erb @@ -0,0 +1,6 @@ +<% param = locals[:param] -%> +<% name = param.name -%> +<% type = param.type -%> + jclass <%= name %>Class = (*env)->GetObjectClass(env, <%= name %>); + jfieldID <%= name %>HandleFieldID = (*env)->GetFieldID(env, <%= name %>Class, "nativeHandle", "J"); + struct TW<%= type.name %> *<%= name %>Instance = (struct TW<%= type.name %> *) (*env)->GetLongField(env, <%= name %>, <%= name %>HandleFieldID); diff --git a/codegen/lib/templates/kotlin_jni/compare_to.erb b/codegen/lib/templates/kotlin_jni/compare_to.erb new file mode 100644 index 00000000000..253a8584b6e --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/compare_to.erb @@ -0,0 +1,22 @@ +<% less = locals[:less] -%> +<% equal = locals[:equal] -%> +<% compareMethod = KotlinJniHelper.compareMethod(entity) -%> +<%= render('kotlin_jni/method_prototype.erb', { method: compareMethod }) %> { +<%= render('kotlin_jni/instance_access.erb', { entity: entity }) %> +<%= render('kotlin_jni/parameter_access.erb', { method: compareMethod }) -%> +<% if entity.struct? -%> + jboolean equal = (jboolean) TW<%= entity.name %>Equal(*instance, *otherInstance); +<% else -%> + jboolean equal = (jboolean) TW<%= entity.name %>Equal(instance, otherInstance); +<% end -%> + if (equal) { + return 0; + } +<% if entity.struct? -%> + jboolean less = (jboolean) TW<%= entity.name %>Less(*instance, *otherInstance); +<% else -%> + jboolean less = (jboolean) TW<%= entity.name %>Less(instance, otherInstance); +<% end -%> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> + return less ? -1 : 1; +} diff --git a/codegen/lib/templates/kotlin_jni/enum_access.erb b/codegen/lib/templates/kotlin_jni/enum_access.erb new file mode 100644 index 00000000000..43d612c0fa0 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/enum_access.erb @@ -0,0 +1,6 @@ +<% param = locals[:param] -%> +<% name = param.name -%> +<% type = param.type -%> + jclass <%= name %>Class = (*env)->GetObjectClass(env, <%= name %>); + jmethodID <%= name %>ValueMethodID = (*env)->GetMethodID(env, <%= name %>Class, "value", "()I"); + jint <%= name %>Value = (*env)->CallIntMethod(env, <%= name %>, <%= name %>ValueMethodID); diff --git a/codegen/lib/templates/kotlin_jni/instance_access.erb b/codegen/lib/templates/kotlin_jni/instance_access.erb new file mode 100644 index 00000000000..5654c472858 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/instance_access.erb @@ -0,0 +1,14 @@ +<% entity = locals[:entity] -%> + jclass thisClass = (*env)->GetObjectClass(env, thisObject); +<% if entity.struct? -%> + jfieldID bytesFieldID = (*env)->GetFieldID(env, thisClass, "bytes", "[B"); + jbyteArray bytesArray = (*env)->GetObjectField(env, thisObject, bytesFieldID); + jbyte* bytesBuffer = (*env)->GetByteArrayElements(env, bytesArray, NULL); + struct TW<%= entity.name %> *instance = (struct TW<%= entity.name %> *) bytesBuffer; +<% elsif entity.enum? -%> + jfieldID handleFieldID = (*env)->GetFieldID(env, thisClass, "value", "I"); + enum TW<%= entity.name %> instance = (enum TW<%= entity.name %>) (*env)->GetIntField(env, thisObject, handleFieldID); +<% else -%> + jfieldID handleFieldID = (*env)->GetFieldID(env, thisClass, "nativeHandle", "J"); + struct TW<%= entity.name %> *instance = (struct TW<%= entity.name %> *) (*env)->GetLongField(env, thisObject, handleFieldID); +<% end -%> diff --git a/codegen/lib/templates/kotlin_jni/instance_release.erb b/codegen/lib/templates/kotlin_jni/instance_release.erb new file mode 100644 index 00000000000..1231d03119b --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/instance_release.erb @@ -0,0 +1,6 @@ +<% entity = locals[:entity] -%> +<% if entity.struct? -%> + (*env)->ReleaseByteArrayElements(env, bytesArray, bytesBuffer, JNI_ABORT); + (*env)->DeleteLocalRef(env, bytesArray); +<% end -%> + (*env)->DeleteLocalRef(env, thisClass); \ No newline at end of file diff --git a/codegen/lib/templates/kotlin_jni/method.erb b/codegen/lib/templates/kotlin_jni/method.erb new file mode 100644 index 00000000000..f41b05435a8 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/method.erb @@ -0,0 +1,8 @@ +<% method = locals[:method] -%> +<%= render('kotlin_jni/method_prototype.erb', { method: method }) %> { +<% if !method.static -%> +<%= render('kotlin_jni/instance_access.erb', { entity: entity }) %> +<% end -%> +<%= render('kotlin_jni/parameter_access.erb', { method: method }) -%> +<%= render('kotlin_jni/method_forward.erb', { method: method }) -%> +} diff --git a/codegen/lib/templates/kotlin_jni/method_call.erb b/codegen/lib/templates/kotlin_jni/method_call.erb new file mode 100644 index 00000000000..68dfee4205a --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/method_call.erb @@ -0,0 +1,6 @@ +<% + method = locals[:method] + instance = (method.entity.struct? ? '*' : '') + 'instance' + arguments = locals[:arguments] || [instance] + KotlinJniHelper.arguments(method.parameters.drop(1)) +-%> +TW<%= entity.name %><%= method.name %>(<%= arguments.join(', ') %>) \ No newline at end of file diff --git a/codegen/lib/templates/kotlin_jni/method_forward.erb b/codegen/lib/templates/kotlin_jni/method_forward.erb new file mode 100644 index 00000000000..3673db58a48 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/method_forward.erb @@ -0,0 +1,118 @@ +<% + method = locals[:method] + if method.static + arguments = locals[:arguments] || KotlinJniHelper.arguments(method.parameters) + call = render('kotlin_jni/method_call.erb', { method: method, arguments: arguments }) + else + instance = (method.entity.struct? ? '*' : '') + 'instance' + arguments = locals[:arguments] || [instance] + KotlinJniHelper.arguments(method.parameters.drop(1)) + call = render('kotlin_jni/method_call.erb', { method: method, arguments: arguments }) + end + + # Method returns data + if should_return_data(method) -%> + <%= KotlinJniHelper.type(method.return_type) %> result = NULL; + TWData *resultData = <%= call %>; +<% if method.return_type.is_nullable %> + if (resultData == NULL) { + goto cleanup; + } +<% end -%> + result = TWDataJByteArray(resultData, env); +<% if method.return_type.is_nullable %> +cleanup: +<% end -%> +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> +<% if !method.static %> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> +<% end -%> + return result; +<% + # Method returns a string + elsif should_return_string(method) -%> + jstring result = NULL; + TWString *resultString = <%= call %>; +<% if method.return_type.is_nullable %> + if (resultString == NULL) { + goto cleanup; + } +<% end -%> + result = TWStringJString(resultString, env); +<% if method.return_type.is_nullable %> +cleanup: +<% end -%> +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> +<% if !method.static %> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> +<% end -%> + return result; +<% + # Method returns proto + elsif method.return_type.is_proto -%> + jbyteArray resultData = TWDataJByteArray(<%= call %>, env); + jclass resultClass = (*env)->FindClass(env, "<%= KotlinJniHelper.proto_to_class(method.return_type.name) %>"); + jmethodID parseFromMethodID = (*env)->GetStaticMethodID(env, resultClass, "parseFrom", "([B)L<%= KotlinJniHelper.proto_to_class(method.return_type.name) %>;"); + jobject result = (*env)->CallStaticObjectMethod(env, resultClass, parseFromMethodID, resultData); + + (*env)->DeleteLocalRef(env, resultClass); +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> +<% if !method.static %> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> +<% end -%> + + return result; +<% + # Method returns an object + elsif method.return_type.is_struct || method.return_type.is_class || method.return_type.is_enum + if method.return_type.is_struct -%> + struct TW<%= method.return_type.name %> result = <%= call %>; +<% elsif method.return_type.is_class -%> + struct TW<%= method.return_type.name %> *result = <%= call %>; +<% elsif method.return_type.is_enum -%> + enum TW<%= method.return_type.name %> result = <%= call %>; +<% else -%> + TW<%= method.return_type.name %> *result = <%= call %>; +<% end -%> + +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> +<% if !method.static %> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> +<% end -%> + + jclass class = (*env)->FindClass(env, "com/trustwallet/core/<%= method.return_type.name %>"); +<% if method.return_type.is_struct -%> + jbyteArray resultArray = (*env)->NewByteArray(env, sizeof(struct TW<%= method.return_type.name %>)); + (*env)->SetByteArrayRegion(env, resultArray, 0, sizeof(struct TW<%= method.return_type.name %>), (jbyte *) &result); + jmethodID method = (*env)->GetStaticMethodID(env, class, "createFromNative", "([B)Lcom/trustwallet/core/<%= method.return_type.name %>;"); + return (*env)->CallStaticObjectMethod(env, class, method, resultArray); +<% elsif method.return_type.is_enum -%> + jmethodID method = (*env)->GetStaticMethodID(env, class, "createFromValue", "(I)Lcom/trustwallet/core/<%= method.return_type.name %>;"); + return (*env)->CallStaticObjectMethod(env, class, method, (jint) result); +<% else -%> + if (result == NULL) { + return NULL; + } + jmethodID method = (*env)->GetStaticMethodID(env, class, "createFromNative", "(J)Lcom/trustwallet/core/<%= method.return_type.name %>;"); + return (*env)->CallStaticObjectMethod(env, class, method, (jlong) result); +<% end + + # Method returns void + elsif method.return_type.name == :void -%> + <%= call %>; + +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> +<% if !method.static %> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> +<% end + + # Method returns a primitive + else -%> + <%= KotlinJniHelper.type(method.return_type) %> resultValue = (<%= KotlinJniHelper.type(method.return_type) %>) <%= call %>; + +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> +<% if !method.static %> +<%= render('kotlin_jni/instance_release.erb', { entity: entity }) %> +<% end -%> + + return resultValue; +<%end -%> \ No newline at end of file diff --git a/codegen/lib/templates/kotlin_jni/method_prototype.erb b/codegen/lib/templates/kotlin_jni/method_prototype.erb new file mode 100644 index 00000000000..a971ce95bd5 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/method_prototype.erb @@ -0,0 +1,9 @@ +<% + method = locals[:method] + if method.static + parameters = 'jclass thisClass' + KotlinJniHelper.parameters(method.parameters) + else + parameters = 'jobject thisObject' + KotlinJniHelper.parameters(method.parameters.drop(1)) + end +-%> +<%= KotlinJniHelper.type(method.return_type) %> JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method) %>(JNIEnv *env, <%= parameters %>)<% -%> diff --git a/codegen/lib/templates/kotlin_jni/parameter_access.erb b/codegen/lib/templates/kotlin_jni/parameter_access.erb new file mode 100644 index 00000000000..8022686514b --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/parameter_access.erb @@ -0,0 +1,23 @@ +<% + method = locals[:method] + if method.static && !method.name.include?('Init') + parameters = method.parameters + else + parameters = method.parameters.drop(1) + end + + parameters.each do |param| + if param.type.name == :data -%> + TWData *<%= param.name %>Data = TWDataCreateWithJByteArray(env, <%= param.name %>); +<% elsif param.type.name == :string -%> + TWString *<%= param.name %>String = TWStringCreateWithJString(env, <%= param.name %>); +<% elsif param.type.is_struct -%> +<%= render('kotlin_jni/struct_access.erb', { param: param }) -%> +<% elsif param.type.is_class -%> +<%= render('kotlin_jni/class_access.erb', { param: param }) -%> +<% elsif param.type.is_enum -%> +<%= render('kotlin_jni/enum_access.erb', { param: param }) -%> +<% elsif param.type.is_proto -%> +<%= render('kotlin_jni/proto_access.erb', { param: param }) -%> +<% end -%> +<%end -%> diff --git a/codegen/lib/templates/kotlin_jni/parameter_release.erb b/codegen/lib/templates/kotlin_jni/parameter_release.erb new file mode 100644 index 00000000000..147e40c3496 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/parameter_release.erb @@ -0,0 +1,26 @@ +<% + method = locals[:method] + if method.static && !method.name.include?('Init') + parameters = method.parameters + else + parameters = method.parameters.drop(1) + end + + parameters.each do |param| + if param.type.name == :data -%> + TWDataDelete(<%= param.name %>Data); +<% elsif param.type.name == :string -%> + TWStringDelete(<%= param.name %>String); +<% elsif param.type.is_struct -%> + (*env)->ReleaseByteArrayElements(env, <%= param.name %>BytesArray, <%= param.name %>BytesBuffer, JNI_ABORT); + (*env)->DeleteLocalRef(env, <%= param.name %>BytesArray); + (*env)->DeleteLocalRef(env, <%= param.name %>Class); +<% elsif param.type.is_class -%> + (*env)->DeleteLocalRef(env, <%= param.name %>Class); +<% elsif param.type.is_enum -%> + (*env)->DeleteLocalRef(env, <%= param.name %>Class); +<% elsif param.type.is_proto -%> + (*env)->DeleteLocalRef(env, <%= param.name %>ByteArray); + (*env)->DeleteLocalRef(env, <%= param.name %>Class); +<% end -%> +<%end -%> diff --git a/codegen/lib/templates/kotlin_jni/proto_access.erb b/codegen/lib/templates/kotlin_jni/proto_access.erb new file mode 100644 index 00000000000..36d930a73cd --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/proto_access.erb @@ -0,0 +1,7 @@ +<% param = locals[:param] -%> +<% name = param.name -%> +<% type = param.type -%> + jclass <%= name %>Class = (*env)->GetObjectClass(env, <%= name %>); + jmethodID <%= name %>ToByteArrayMethodID = (*env)->GetMethodID(env, <%= name %>Class, "toByteArray", "()[B"); + jbyteArray <%= name %>ByteArray = (*env)->CallObjectMethod(env, <%= name %>, <%= name %>ToByteArrayMethodID); + TWData *<%= param.name %>Data = TWDataCreateWithJByteArray(env, <%= name %>ByteArray); diff --git a/codegen/lib/templates/kotlin_jni/struct_access.erb b/codegen/lib/templates/kotlin_jni/struct_access.erb new file mode 100644 index 00000000000..ed8c88c027b --- /dev/null +++ b/codegen/lib/templates/kotlin_jni/struct_access.erb @@ -0,0 +1,8 @@ +<% param = locals[:param] -%> +<% name = param.name -%> +<% type = param.type -%> + jclass <%= name %>Class = (*env)->GetObjectClass(env, <%= name %>); + jfieldID <%= name %>BytesFieldID = (*env)->GetFieldID(env, <%= name %>Class, "bytes", "[B"); + jbyteArray <%= name %>BytesArray = (*env)->GetObjectField(env, <%= name %>, <%= name %>BytesFieldID); + jbyte* <%= name %>BytesBuffer = (*env)->GetByteArrayElements(env, <%= name %>BytesArray, NULL); + struct TW<%= type.name %> *<%= name %>Instance = (struct TW<%= type.name %> *) <%= name %>BytesBuffer; diff --git a/codegen/lib/templates/kotlin_jni_c.erb b/codegen/lib/templates/kotlin_jni_c.erb new file mode 100644 index 00000000000..3b1f05b0588 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni_c.erb @@ -0,0 +1,90 @@ +#include +#include +#include + +<% require 'set' -%> +<% includes = Set.new([entity.name]) -%> +<% entity.static_methods.each do |method| -%> +<% includes << method.return_type.name if method.return_type.is_struct || method.return_type.is_class -%> +<% method.parameters.each do |param| -%> +<% includes << param.type.name if param.type.is_struct || param.type.is_class -%> +<% end -%> +<% end -%> +<% includes.each do |include| -%> +#include .h> +<% end -%> + +#include "TWJNI.h" +#include "<%= entity.name %>.h" + +<%# Constructors -%> +<% entity.static_methods.each do |method| -%> +<% next unless method.name.start_with?('Create') -%> +jlong JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method, native_prefix: true) %>(JNIEnv *env, jclass thisClass<%= KotlinJniHelper.parameters(method.parameters) %>) { +<%= render('kotlin_jni/parameter_access.erb', { method: method }) -%> + struct TW<%= entity.name %> *instance = TW<%= entity.name %><%= method.name %>(<%= KotlinJniHelper.arguments(method.parameters).join(', ') %>); +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> + return (jlong) instance; +} + +<% end -%> +<%# Destructors -%> +<% entity.methods.each do |method| -%> +<% next unless method.name.start_with?('Delete') -%> +void JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method, native_prefix: true) %>(JNIEnv *env, jclass thisClass, jlong handle) { + TW<%= entity.name %>Delete((struct TW<%= entity.name %> *) handle); +} + +<% end -%> +<%# Initializers -%> +<% entity.static_methods.each do |method| -%> +<% next unless method.name.start_with?('Init') -%> +jbyteArray JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method) %>(JNIEnv *env, jclass thisClass<%= KotlinJniHelper.parameters(method.parameters.drop(1)) %>) { + jbyteArray array = (*env)->NewByteArray(env, sizeof(struct TW<%= entity.name %>)); + jbyte* bytesBuffer = (*env)->GetByteArrayElements(env, array, NULL); + struct TW<%= entity.name %> *instance = (struct TW<%= entity.name %> *) bytesBuffer; +<%= render('kotlin_jni/parameter_access.erb', { method: method }) -%> +<% if method.return_type.name != :void -%> + <%= KotlinJniHelper.type(method.return_type) %> result = (<%= KotlinJniHelper.type(method.return_type) %>) TW<%= entity.name %><%= method.name %>(instance, <%= KotlinJniHelper.arguments(method.parameters.drop(1)).join(', ') %>); +<% else -%> + TW<%= entity.name %><%= method.name %>(instance, <%= KotlinJniHelper.arguments(method.parameters.drop(1)).join(', ') %>); +<% end -%> +<%= render('kotlin_jni/parameter_release.erb', { method: method }) -%> + (*env)->ReleaseByteArrayElements(env, array, bytesBuffer, 0); + +<% if method.return_type.name != :void -%> + if (result) { + return array; + } else { + (*env)->DeleteLocalRef(env, array); + return NULL; + } +<% else -%> + return array; +<% end -%> +} + +<% end -%> +<%# Static properties -%> +<% entity.static_properties.each do |method| -%> +<%= render('kotlin_jni/method.erb', { method: method }) %> +<% end -%> +<%# Static methods -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') || method.name.start_with?('Init') -%> +<%= render('kotlin_jni/method.erb', { method: method }) %> +<% end -%> +<%# Properties -%> +<% entity.properties.each do |method| -%> +<%= render('kotlin_jni/method.erb', { method: method }) %> +<% end -%> +<%# Methods -%> +<% entity.methods.each do |method| -%> +<% next if method.name == "Delete" -%> +<%= render('kotlin_jni/method.erb', { method: method }) %> +<% end -%> +<% less = entity.static_methods.detect{ |i| i.name == 'Less' } -%> +<% equal = entity.static_methods.detect{ |i| i.name == 'Equal' } -%> +<% if !less.nil? && !equal.nil? -%> +<%= render('kotlin_jni/compare_to.erb', { less: less, equal: equal }) %> +<% end -%> diff --git a/codegen/lib/templates/kotlin_jni_h.erb b/codegen/lib/templates/kotlin_jni_h.erb new file mode 100644 index 00000000000..44e3bec9cf8 --- /dev/null +++ b/codegen/lib/templates/kotlin_jni_h.erb @@ -0,0 +1,66 @@ +#ifndef JNI_TW_<%= entity.name.upcase %>_H +#define JNI_TW_<%= entity.name.upcase %>_H + +#include +#include + +TW_EXTERN_C_BEGIN + +<%# Constructor declarations -%> +<% entity.static_methods.each do |method| -%> +<% next unless method.name.start_with?('Create') -%> +JNIEXPORT +jlong JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method, native_prefix: true) %>(JNIEnv *env, jclass thisClass<%= KotlinJniHelper.parameters(method.parameters) %>); + +<% end -%> +<%# Destructor declarations -%> +<% entity.methods.each do |method| -%> +<% next unless method.name.start_with?('Delete') -%> +JNIEXPORT +void JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method, native_prefix: true) %>(JNIEnv *env, jclass thisClass, jlong handle); + +<% end -%> +<%# Initializer declarations -%> +<% entity.static_methods.each do |method| -%> +<% next unless method.name.start_with?('Init') -%> +JNIEXPORT +jbyteArray JNICALL <%= KotlinJniHelper.function_name(entity: entity, function: method) %>(JNIEnv *env, jclass thisClass<%= KotlinJniHelper.parameters(method.parameters.drop(1)) %>); + +<% end -%> +<%# Static property declarations -%> +<% entity.static_properties.each do |property| -%> +JNIEXPORT +<%= render('kotlin_jni/method_prototype.erb', { method: property }) %>; + +<% end -%> +<%# Static method declarations -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') || method.name.start_with?('Init') -%> +JNIEXPORT +<%= render('kotlin_jni/method_prototype.erb', { method: method }) %>; + +<% end -%> +<%# Property declarations -%> +<% entity.properties.each do |property| -%> +JNIEXPORT +<%= render('kotlin_jni/method_prototype.erb', { method: property }) %>; + +<% end -%> +<%# Method declarations -%> +<% entity.methods.each do |method| -%> +<% next if method.name.start_with?('Delete') -%> +JNIEXPORT +<%= render('kotlin_jni/method_prototype.erb', { method: method }) %>; + +<% end -%> +<% less = entity.static_methods.detect{ |i| i.name == 'Less' } -%> +<% equal = entity.static_methods.detect{ |i| i.name == 'Equal' } -%> +<% if !less.nil? && !equal.nil? -%> +JNIEXPORT +<%= render('kotlin_jni/method_prototype.erb', { method: KotlinJniHelper.compareMethod(entity) }) %>; + +<% end -%> + +TW_EXTERN_C_END + +#endif // JNI_TW_<%= entity.name.upcase %>_H diff --git a/codegen/lib/templates/kotlin_js.erb b/codegen/lib/templates/kotlin_js.erb new file mode 100644 index 00000000000..db9c23dd567 --- /dev/null +++ b/codegen/lib/templates/kotlin_js.erb @@ -0,0 +1,7 @@ +<%- if entity.is_a?(EnumDecl) -%> +<%= render('kotlin/js_enum.erb') -%> +<%- elsif entity.is_struct -%> +<%= render('kotlin/js_struct.erb') -%> +<%- else -%> +<%= render('kotlin/js_class.erb') -%> +<%- end -%> diff --git a/jni/cpp/AnySigner.c b/jni/android/AnySigner.c similarity index 100% rename from jni/cpp/AnySigner.c rename to jni/android/AnySigner.c diff --git a/jni/cpp/AnySigner.h b/jni/android/AnySigner.h similarity index 100% rename from jni/cpp/AnySigner.h rename to jni/android/AnySigner.h diff --git a/jni/cpp/Random.cpp b/jni/cpp/Random.cpp index de97baff225..3e15e28062f 100644 --- a/jni/cpp/Random.cpp +++ b/jni/cpp/Random.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -27,7 +27,7 @@ uint32_t random32() { void random_buffer(uint8_t *buf, size_t len) { JNIEnv *env; - cachedJVM->AttachCurrentThread(&env, NULL); + cachedJVM->AttachCurrentThread(&env, nullptr); // SecureRandom random = new SecureRandom(); jclass secureRandomClass = env->FindClass("java/security/SecureRandom"); diff --git a/jni/cpp/TWJNI.h b/jni/cpp/TWJNI.h index 29bf14ba4df..4fc8d55d71f 100644 --- a/jni/cpp/TWJNI.h +++ b/jni/cpp/TWJNI.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/jni/cpp/TWJNIData.cpp b/jni/cpp/TWJNIData.cpp index c0577f31442..47e294f64b0 100644 --- a/jni/cpp/TWJNIData.cpp +++ b/jni/cpp/TWJNIData.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -10,7 +10,7 @@ #include "TWJNIData.h" jbyteArray TWDataJByteArray(TWData *_Nonnull data, JNIEnv *env) { - jsize dataSize = static_cast(TWDataSize(data)); + auto dataSize = static_cast(TWDataSize(data)); jbyteArray array = env->NewByteArray(dataSize); env->SetByteArrayRegion(array, 0, dataSize, (jbyte *) TWDataBytes(data)); TWDataDelete(data); diff --git a/jni/cpp/TWJNIData.h b/jni/cpp/TWJNIData.h index a7002bffce5..39d3ca47aa9 100644 --- a/jni/cpp/TWJNIData.h +++ b/jni/cpp/TWJNIData.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/jni/cpp/TWJNIString.cpp b/jni/cpp/TWJNIString.cpp index 2bb220fb6fc..95b017fac2e 100644 --- a/jni/cpp/TWJNIString.cpp +++ b/jni/cpp/TWJNIString.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -15,8 +15,8 @@ jstring _Nonnull TWStringJString(TWString *_Nonnull string, JNIEnv *env) { } TWString *_Nonnull TWStringCreateWithJString(JNIEnv *env, jstring _Nonnull string) { - auto chars = env->GetStringUTFChars(string, nullptr); - auto twstring = TWStringCreateWithUTF8Bytes(chars); + const auto *chars = env->GetStringUTFChars(string, nullptr); + const auto *twstring = TWStringCreateWithUTF8Bytes(chars); env->ReleaseStringUTFChars(string, chars); return twstring; } diff --git a/jni/cpp/TWJNIString.h b/jni/cpp/TWJNIString.h index 95f0f967898..e6452df0134 100644 --- a/jni/cpp/TWJNIString.h +++ b/jni/cpp/TWJNIString.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/jni/kotlin/AnySigner.c b/jni/kotlin/AnySigner.c new file mode 100644 index 00000000000..8e0c9f389f8 --- /dev/null +++ b/jni/kotlin/AnySigner.c @@ -0,0 +1,56 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include +#include + +#include "AnySigner.h" +#include "TWJNI.h" + +jbyteArray JNICALL Java_com_trustwallet_core_AnySignerKt_signImpl(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin) { + jclass coinClass = (*env)->GetObjectClass(env, coin); + jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I"); + uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID); + + TWData *inputData = TWDataCreateWithJByteArray(env, input); + TWData *outputData = TWAnySignerSign(inputData, coinValue); + jbyteArray resultData = TWDataJByteArray(outputData, env); + TWDataDelete(inputData); + return resultData; +} + +jboolean JNICALL Java_com_trustwallet_core_AnySignerKt_supportsJsonImpl(JNIEnv *env, jclass thisClass, jobject coin) { + jclass coinClass = (*env)->GetObjectClass(env, coin); + jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I"); + uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID); + return TWAnySignerSupportsJSON(coinValue); +} + +jstring JNICALL Java_com_trustwallet_core_AnySignerKt_signJsonImpl(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jobject coin) { + jclass coinClass = (*env)->GetObjectClass(env, coin); + jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I"); + uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID); + + TWString *jsonString = TWStringCreateWithJString(env, json); + TWData *keyData = TWDataCreateWithJByteArray(env, key); + TWString *result = TWAnySignerSignJSON(jsonString, keyData, coinValue); + TWDataDelete(keyData); + TWStringDelete(jsonString); + return TWStringJString(result, env); +} + +jbyteArray JNICALL Java_com_trustwallet_core_AnySignerKt_planImpl(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin) { + jclass coinClass = (*env)->GetObjectClass(env, coin); + jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I"); + uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID); + + TWData *inputData = TWDataCreateWithJByteArray(env, input); + TWData *outputData = TWAnySignerPlan(inputData, coinValue); + jbyteArray resultData = TWDataJByteArray(outputData, env); + TWDataDelete(inputData); + return resultData; +} diff --git a/jni/kotlin/AnySigner.h b/jni/kotlin/AnySigner.h new file mode 100644 index 00000000000..18f98104f62 --- /dev/null +++ b/jni/kotlin/AnySigner.h @@ -0,0 +1,29 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#ifndef JNI_TW_ANYSIGNER_H +#define JNI_TW_ANYSIGNER_H + +#include +#include + +TW_EXTERN_C_BEGIN + +JNIEXPORT +jbyteArray JNICALL Java_com_trustwallet_core_AnySignerKt_signImpl(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin); + +JNIEXPORT +jboolean JNICALL Java_com_trustwallet_core_AnySignerKt_supportsJsonImpl(JNIEnv *env, jclass thisClass, jobject coin); + +JNIEXPORT +jstring JNICALL Java_com_trustwallet_core_AnySignerKt_signJsonImpl(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jobject coin); + +JNIEXPORT +jbyteArray JNICALL Java_com_trustwallet_core_AnySignerKt_planImpl(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin); + +TW_EXTERN_C_END + +#endif // JNI_TW_ANYSIGNER_H diff --git a/kotlin/.editorconfig b/kotlin/.editorconfig new file mode 100644 index 00000000000..aff6d71fbe4 --- /dev/null +++ b/kotlin/.editorconfig @@ -0,0 +1,19 @@ +root = true + +[*] +indent_style = space +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +max_line_length = 120 + +[*.{kt,kts}] +indent_size = 4 +ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL +ij_kotlin_imports_layout = * +ij_kotlin_allow_trailing_comma = true +ij_kotlin_allow_trailing_comma_on_call_site = true +ij_kotlin_enum_constants_wrap = split_into_lines +ij_kotlin_packages_to_use_import_on_demand = * +ij_kotlin_wrap_first_method_in_call_chain = true diff --git a/kotlin/.gitignore b/kotlin/.gitignore new file mode 100644 index 00000000000..f8ed7018916 --- /dev/null +++ b/kotlin/.gitignore @@ -0,0 +1,2 @@ +.gradle +local.properties diff --git a/kotlin/README.md b/kotlin/README.md new file mode 100644 index 00000000000..42e4cf78a39 --- /dev/null +++ b/kotlin/README.md @@ -0,0 +1,5 @@ +### Tasks: + +- `./gradlew :wallet-core-kotlin:generateProtos` – Generates Kotlin classes for Protos +- `./gradlew :wallet-core-kotlin:generateCinterop` – Generates def file +- `./gradlew :wallet-core-kotlin:generateFiles` – Generates all the above and Kotlin accessors to the library diff --git a/kotlin/build-logic/build.gradle.kts b/kotlin/build-logic/build.gradle.kts new file mode 100644 index 00000000000..d6cda1875d1 --- /dev/null +++ b/kotlin/build-logic/build.gradle.kts @@ -0,0 +1,14 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + `kotlin-dsl` +} + +allprojects { + tasks.withType { + kotlinOptions { + allWarningsAsErrors = true + jvmTarget = JavaVersion.VERSION_11.toString() + } + } +} diff --git a/kotlin/build-logic/settings.gradle.kts b/kotlin/build-logic/settings.gradle.kts new file mode 100644 index 00000000000..5cab7b66872 --- /dev/null +++ b/kotlin/build-logic/settings.gradle.kts @@ -0,0 +1,23 @@ +@file:Suppress("UnstableApiUsage") + +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } + + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} diff --git a/kotlin/build-logic/src/main/kotlin/convention.file-generation.gradle.kts b/kotlin/build-logic/src/main/kotlin/convention.file-generation.gradle.kts new file mode 100644 index 00000000000..028fb3a9c2f --- /dev/null +++ b/kotlin/build-logic/src/main/kotlin/convention.file-generation.gradle.kts @@ -0,0 +1,86 @@ +val libs = extensions.getByType().named("libs") + +val generateCinteropTask = task("generateCinterop") { + doFirst { + val headersDir = rootDir.parentFile.resolve("include/TrustWalletCore") + val headers = headersDir + .listFiles { file -> file.extension == "h" } + .orEmpty() + .sortedBy { it.name } + .joinToString(separator = " ") { it.name } + + val defFile = projectDir.resolve("src/nativeInterop/cinterop/walletCore.def") + defFile.parentFile.mkdirs() + defFile.writeText( + text = + """ + headers = $headers + package = com.trustwallet.core + + """.trimIndent(), + ) + } +} + +val copyProtoTask = task("copyProtos") { + val sourceDir = rootDir.parentFile.resolve("src/proto") + val destinationDir = projectDir.resolve("build/tmp/proto") + + doFirst { + destinationDir.deleteRecursively() + } + + from(sourceDir) { + include("*.proto") + } + into(destinationDir) + + doLast { + destinationDir + .listFiles { file -> file.extension == "proto" } + .orEmpty() + .forEach { file -> + val packageName = file.nameWithoutExtension.toLowerCase() + file + .readText() + .replaceFirst( + oldValue = """option java_package = "wallet.core.jni.proto";""", + newValue = """option java_package = "com.trustwallet.core.$packageName";""", + ) + .let { file.writeText(it) } + } + } +} + +val wire: Configuration by configurations.creating +dependencies { + wire(libs.findLibrary("wire.compiler").get().get()) +} + +val generateProtosTask = task("generateProtos") { + dependsOn(copyProtoTask) + + val sourceDir = projectDir.resolve("build/tmp/proto") + val destinationDir = projectDir.resolve("src/commonMain/proto") + + doFirst { + destinationDir.deleteRecursively() + destinationDir.mkdirs() + } + + mainClass.set("com.squareup.wire.WireCompiler") + classpath = wire + + args( + "--proto_path=$sourceDir", + "--kotlin_out=$destinationDir", + ) +} + +task("generateFiles") { + dependsOn(generateCinteropTask) + dependsOn(generateProtosTask) + + workingDir(rootDir.parentFile) + commandLine("./codegen/bin/codegen") +} diff --git a/kotlin/build-logic/src/main/kotlin/convention.maven-publish.gradle.kts b/kotlin/build-logic/src/main/kotlin/convention.maven-publish.gradle.kts new file mode 100644 index 00000000000..37072540d89 --- /dev/null +++ b/kotlin/build-logic/src/main/kotlin/convention.maven-publish.gradle.kts @@ -0,0 +1,21 @@ +plugins { + `maven-publish` +} + +group = "com.trustwallet" +if (version == Project.DEFAULT_VERSION) { + version = "0.0.0-alpha" +} + +publishing { + repositories { + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/trustwallet/wallet-core") + credentials { + username = System.getenv("GITHUB_USER") + password = System.getenv("GITHUB_TOKEN") + } + } + } +} diff --git a/kotlin/build.gradle.kts b/kotlin/build.gradle.kts new file mode 100644 index 00000000000..87279b47a55 --- /dev/null +++ b/kotlin/build.gradle.kts @@ -0,0 +1,20 @@ +// Workaround https://github.com/gradle/gradle/issues/22797 +@file:Suppress("DSL_SCOPE_VIOLATION") + +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + id("com.android.application") version libs.versions.agp.get() apply false + id("com.android.library") version libs.versions.agp.get() apply false + kotlin("android") version libs.versions.kotlin.get() apply false + kotlin("multiplatform") version libs.versions.kotlin.get() apply false +} + +allprojects { + tasks.withType { + kotlinOptions { + allWarningsAsErrors = true + jvmTarget = JavaVersion.VERSION_11.toString() + } + } +} diff --git a/kotlin/gradle.properties b/kotlin/gradle.properties new file mode 100644 index 00000000000..d1b2beb446c --- /dev/null +++ b/kotlin/gradle.properties @@ -0,0 +1,12 @@ +# Gradle +org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 +org.gradle.parallel=true +# Kotlin +kotlin.code.style=official +kotlin.js.compiler=ir +kotlin.mpp.androidSourceSetLayoutVersion=2 +kotlin.mpp.enableCInteropCommonization=true +# Android +android.useAndroidX=true +android.nonTransitiveRClass=true +android.disableAutomaticComponentCreation=true diff --git a/kotlin/gradle/libs.versions.toml b/kotlin/gradle/libs.versions.toml new file mode 100644 index 00000000000..012e8c6ba34 --- /dev/null +++ b/kotlin/gradle/libs.versions.toml @@ -0,0 +1,14 @@ +[versions] +android-sdk-tools = "33.0.1" +android-sdk-min = "24" +android-sdk-compile = "33" +android-cmake = "3.22.1" +android-ndk = "25.2.9519653" + +kotlin = "1.8.10" +agp = "7.4.1" +wire = "4.4.3" + +[libraries] +wire-runtime = { module = "com.squareup.wire:wire-runtime", version.ref = "wire" } +wire-compiler = { module = "com.squareup.wire:wire-compiler", version.ref = "wire" } diff --git a/kotlin/gradle/wrapper/gradle-wrapper.jar b/kotlin/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..943f0cbfa754578e88a3dae77fce6e3dea56edbf GIT binary patch literal 61574 zcmb6AV{~QRwml9f72CFLyJFk6ZKq;e729@pY}>YNR8p1vbMJH7ubt# zZR`2@zJD1Ad^Oa6Hk1{VlN1wGR-u;_dyt)+kddaNpM#U8qn@6eX;fldWZ6BspQIa= zoRXcQk)#ENJ`XiXJuK3q0$`Ap92QXrW00Yv7NOrc-8ljOOOIcj{J&cR{W`aIGXJ-` z`ez%Mf7qBi8JgIb{-35Oe>Zh^GIVe-b^5nULQhxRDZa)^4+98@`hUJe{J%R>|LYHA z4K3~Hjcp8_owGF{d~lZVKJ;kc48^OQ+`_2migWY?JqgW&))70RgSB6KY9+&wm<*8 z_{<;(c;5H|u}3{Y>y_<0Z59a)MIGK7wRMX0Nvo>feeJs+U?bt-++E8bu7 zh#_cwz0(4#RaT@xy14c7d<92q-Dd}Dt<*RS+$r0a^=LGCM{ny?rMFjhgxIG4>Hc~r zC$L?-FW0FZ((8@dsowXlQq}ja%DM{z&0kia*w7B*PQ`gLvPGS7M}$T&EPl8mew3In z0U$u}+bk?Vei{E$6dAYI8Tsze6A5wah?d(+fyP_5t4ytRXNktK&*JB!hRl07G62m_ zAt1nj(37{1p~L|m(Bsz3vE*usD`78QTgYIk zQ6BF14KLzsJTCqx&E!h>XP4)bya|{*G7&T$^hR0(bOWjUs2p0uw7xEjbz1FNSBCDb@^NIA z$qaq^0it^(#pFEmuGVS4&-r4(7HLmtT%_~Xhr-k8yp0`$N|y>#$Ao#zibzGi*UKzi zhaV#@e1{2@1Vn2iq}4J{1-ox;7K(-;Sk{3G2_EtV-D<)^Pk-G<6-vP{W}Yd>GLL zuOVrmN@KlD4f5sVMTs7c{ATcIGrv4@2umVI$r!xI8a?GN(R;?32n0NS(g@B8S00-=zzLn z%^Agl9eV(q&8UrK^~&$}{S(6-nEXnI8%|hoQ47P?I0Kd=woZ-pH==;jEg+QOfMSq~ zOu>&DkHsc{?o&M5`jyJBWbfoPBv9Y#70qvoHbZXOj*qRM(CQV=uX5KN+b>SQf-~a8 ziZg}@&XHHXkAUqr)Q{y`jNd7`1F8nm6}n}+_She>KO`VNlnu(&??!(i#$mKOpWpi1 z#WfWxi3L)bNRodhPM~~?!5{TrrBY_+nD?CIUupkwAPGz-P;QYc-DcUoCe`w(7)}|S zRvN)9ru8b)MoullmASwsgKQo1U6nsVAvo8iKnbaWydto4y?#-|kP^%e6m@L`88KyDrLH`=EDx*6>?r5~7Iv~I zr__%SximG(izLKSnbTlXa-ksH@R6rvBrBavt4)>o3$dgztLt4W=!3=O(*w7I+pHY2(P0QbTma+g#dXoD7N#?FaXNQ^I0*;jzvjM}%=+km`YtC%O#Alm| zqgORKSqk!#^~6whtLQASqiJ7*nq?38OJ3$u=Tp%Y`x^eYJtOqTzVkJ60b2t>TzdQ{I}!lEBxm}JSy7sy8DpDb zIqdT%PKf&Zy--T^c-;%mbDCxLrMWTVLW}c=DP2>Td74)-mLl|70)8hU??(2)I@Zyo z2i`q5oyA!!(2xV~gahuKl&L(@_3SP012#x(7P!1}6vNFFK5f*A1xF({JwxSFwA|TM z&1z}!*mZKcUA-v4QzLz&5wS$7=5{M@RAlx@RkJaA4nWVqsuuaW(eDh^LNPPkmM~Al zwxCe@*-^4!ky#iNv2NIIU$CS+UW%ziW0q@6HN3{eCYOUe;2P)C*M`Bt{~-mC%T3%# zEaf)lATO1;uF33x>Hr~YD0Ju*Syi!Jz+x3myVvU^-O>C*lFCKS&=Tuz@>&o?68aF& zBv<^ziPywPu#;WSlTkzdZ9`GWe7D8h<1-v0M*R@oYgS5jlPbgHcx)n2*+!+VcGlYh?;9Ngkg% z=MPD+`pXryN1T|%I7c?ZPLb3bqWr7 zU4bfG1y+?!bw)5Iq#8IqWN@G=Ru%Thxf)#=yL>^wZXSCC8we@>$hu=yrU;2=7>h;5 zvj_pYgKg2lKvNggl1ALnsz2IlcvL;q79buN5T3IhXuJvy@^crqWpB-5NOm{7UVfxmPJ>`?;Tn@qHzF+W!5W{8Z&ZAnDOquw6r4$bv*jM#5lc%3v|c~^ zdqo4LuxzkKhK4Q+JTK8tR_|i6O(x#N2N0Fy5)!_trK&cn9odQu#Vlh1K~7q|rE z61#!ZPZ+G&Y7hqmY;`{XeDbQexC2@oFWY)Nzg@lL3GeEVRxWQlx@0?Zt`PcP0iq@6 zLgc)p&s$;*K_;q0L(mQ8mKqOJSrq$aQYO-Hbssf3P=wC6CvTVHudzJH-Jgm&foBSy zx0=qu$w477lIHk);XhaUR!R-tQOZ;tjLXFH6;%0)8^IAc*MO>Q;J={We(0OHaogG0 zE_C@bXic&m?F7slFAB~x|n#>a^@u8lu;=!sqE*?vq zu4`(x!Jb4F#&3+jQ|ygldPjyYn#uCjNWR)%M3(L!?3C`miKT;~iv_)dll>Q6b+I&c zrlB04k&>mSYLR7-k{Od+lARt~3}Bv!LWY4>igJl!L5@;V21H6dNHIGr+qV551e@yL z`*SdKGPE^yF?FJ|`#L)RQ?LJ;8+={+|Cl<$*ZF@j^?$H%V;jqVqt#2B0yVr}Nry5R z5D?S9n+qB_yEqvdy9nFc+8WxK$XME$3ftSceLb+L(_id5MMc*hSrC;E1SaZYow%jh zPgo#1PKjE+1QB`Of|aNmX?}3TP;y6~0iN}TKi3b+yvGk;)X&i3mTnf9M zuv3qvhErosfZ%Pb-Q>|BEm5(j-RV6Zf^$icM=sC-5^6MnAvcE9xzH@FwnDeG0YU{J zi~Fq?=bi0;Ir=hfOJu8PxC)qjYW~cv^+74Hs#GmU%Cw6?3LUUHh|Yab`spoqh8F@_ zm4bCyiXPx-Cp4!JpI~w!ShPfJOXsy>f*|$@P8L8(oeh#~w z-2a4IOeckn6}_TQ+rgl_gLArS3|Ml(i<`*Lqv6rWh$(Z5ycTYD#Z*&-5mpa}a_zHt z6E`Ty-^L9RK-M*mN5AasoBhc|XWZ7=YRQSvG)3$v zgr&U_X`Ny0)IOZtX}e$wNUzTpD%iF7Rgf?nWoG2J@PsS-qK4OD!kJ?UfO+1|F*|Bo z1KU`qDA^;$0*4mUJ#{EPOm7)t#EdX=Yx1R2T&xlzzThfRC7eq@pX&%MO&2AZVO%zw zS;A{HtJiL=rfXDigS=NcWL-s>Rbv|=)7eDoOVnVI>DI_8x>{E>msC$kXsS}z?R6*x zi(yO`$WN)_F1$=18cbA^5|f`pZA+9DG_Zu8uW?rA9IxUXx^QCAp3Gk1MSdq zBZv;_$W>*-zLL)F>Vn`}ti1k!%6{Q=g!g1J*`KONL#)M{ZC*%QzsNRaL|uJcGB7jD zTbUe%T(_x`UtlM!Ntp&-qu!v|mPZGcJw$mdnanY3Uo>5{oiFOjDr!ZznKz}iWT#x& z?*#;H$`M0VC|a~1u_<(}WD>ogx(EvF6A6S8l0%9U<( zH||OBbh8Tnzz*#bV8&$d#AZNF$xF9F2{_B`^(zWNC}af(V~J+EZAbeC2%hjKz3V1C zj#%d%Gf(uyQ@0Y6CcP^CWkq`n+YR^W0`_qkDw333O<0FoO9()vP^!tZ{`0zsNQx~E zb&BcBU>GTP2svE2Tmd;~73mj!_*V8uL?ZLbx}{^l9+yvR5fas+w&0EpA?_g?i9@A$j*?LnmctPDQG|zJ`=EF}Vx8aMD^LrtMvpNIR*|RHA`ctK*sbG= zjN7Q)(|dGpC}$+nt~bupuKSyaiU}Ws{?Tha@$q}cJ;tvH>+MuPih+B4d$Zbq9$Y*U z)iA(-dK?Ov@uCDq48Zm%%t5uw1GrnxDm7*ITGCEF!2UjA`BqPRiUR`yNq^zz|A3wU zG(8DAnY-GW+PR2&7@In{Sla(XnMz5Rk^*5u4UvCiDQs@hvZXoiziv{6*i?fihVI|( zPrY8SOcOIh9-AzyJ*wF4hq%ojB&Abrf;4kX@^-p$mmhr}xxn#fVU?ydmD=21&S)s*v*^3E96(K1}J$6bi8pyUr-IU)p zcwa$&EAF$0Aj?4OYPcOwb-#qB=kCEDIV8%^0oa567_u6`9+XRhKaBup z2gwj*m#(}=5m24fBB#9cC?A$4CCBj7kanaYM&v754(b%Vl!gg&N)ZN_gO0mv(jM0# z>FC|FHi=FGlEt6Hk6H3!Yc|7+q{&t%(>3n#>#yx@*aS+bw)(2!WK#M0AUD~wID>yG z?&{p66jLvP1;!T7^^*_9F322wJB*O%TY2oek=sA%AUQT75VQ_iY9`H;ZNKFQELpZd z$~M`wm^Y>lZ8+F0_WCJ0T2td`bM+b`)h3YOV%&@o{C#|t&7haQfq#uJJP;81|2e+$ z|K#e~YTE87s+e0zCE2X$df`o$`8tQhmO?nqO?lOuTJ%GDv&-m_kP9X<5GCo1=?+LY z?!O^AUrRb~3F!k=H7Aae5W0V1{KlgH379eAPTwq=2+MlNcJ6NM+4ztXFTwI)g+)&Q7G4H%KH_(}1rq%+eIJ*3$?WwnZxPZ;EC=@`QS@|-I zyl+NYh&G>k%}GL}1;ap8buvF>x^yfR*d+4Vkg7S!aQ++_oNx6hLz6kKWi>pjWGO5k zlUZ45MbA=v(xf>Oeqhg8ctl56y{;uDG?A9Ga5aEzZB80BW6vo2Bz&O-}WAq>(PaV;*SX0=xXgI_SJ< zYR&5HyeY%IW}I>yKu^?W2$~S!pw?)wd4(#6;V|dVoa}13Oiz5Hs6zA zgICc;aoUt$>AjDmr0nCzeCReTuvdD1{NzD1wr*q@QqVW*Wi1zn;Yw1dSwLvTUwg#7 zpp~Czra7U~nSZZTjieZxiu~=}!xgV68(!UmQz@#w9#$0Vf@y%!{uN~w^~U_d_Aa&r zt2l>)H8-+gA;3xBk?ZV2Cq!L71;-tb%7A0FWziYwMT|#s_Ze_B>orZQWqDOZuT{|@ zX04D%y&8u@>bur&*<2??1KnaA7M%%gXV@C3YjipS4|cQH68OSYxC`P#ncvtB%gnEI z%fxRuH=d{L70?vHMi>~_lhJ@MC^u#H66=tx?8{HG;G2j$9@}ZDYUuTetwpvuqy}vW)kDmj^a|A%z(xs7yY2mU0#X2$un&MCirr|7 z%m?8+9aekm0x5hvBQ2J+>XeAdel$cy>J<6R3}*O^j{ObSk_Ucv$8a3_WPTd5I4HRT z(PKP5!{l*{lk_19@&{5C>TRV8_D~v*StN~Pm*(qRP+`1N12y{#w_fsXrtSt={0hJw zQ(PyWgA;;tBBDql#^2J(pnuv;fPn(H>^d<6BlI%00ylJZ?Evkh%=j2n+|VqTM~EUh zTx|IY)W;3{%x(O{X|$PS&x0?z#S2q-kW&G}7#D?p7!Q4V&NtA_DbF~v?cz6_l+t8e zoh1`dk;P-%$m(Ud?wnoZn0R=Ka$`tnZ|yQ-FN!?!9Wmb^b(R!s#b)oj9hs3$p%XX9DgQcZJE7B_dz0OEF6C zx|%jlqj0WG5K4`cVw!19doNY+(;SrR_txAlXxf#C`uz5H6#0D>SzG*t9!Fn|^8Z8; z1w$uiQzufUzvPCHXhGma>+O327SitsB1?Rn6|^F198AOx}! zfXg22Lm0x%=gRvXXx%WU2&R!p_{_1H^R`+fRO2LT%;He@yiekCz3%coJ=8+Xbc$mN zJ;J7*ED|yKWDK3CrD?v#VFj|l-cTgtn&lL`@;sMYaM1;d)VUHa1KSB5(I54sBErYp z>~4Jz41?Vt{`o7T`j=Se{-kgJBJG^MTJ}hT00H%U)pY-dy!M|6$v+-d(CkZH5wmo1 zc2RaU`p3_IJ^hf{g&c|^;)k3zXC0kF1>rUljSxd}Af$!@@R1fJWa4g5vF?S?8rg=Z z4_I!$dap>3l+o|fyYy(sX}f@Br4~%&&#Z~bEca!nMKV zgQSCVC!zw^j<61!7#T!RxC6KdoMNONcM5^Q;<#~K!Q?-#6SE16F*dZ;qv=`5 z(kF|n!QIVd*6BqRR8b8H>d~N@ab+1+{3dDVPVAo>{mAB#m&jX{usKkCg^a9Fef`tR z?M79j7hH*;iC$XM)#IVm&tUoDv!(#f=XsTA$)(ZE37!iu3Gkih5~^Vlx#<(M25gr@ zOkSw4{l}6xI(b0Gy#ywglot$GnF)P<FQt~9ge1>qp8Q^k;_Dm1X@Tc^{CwYb4v_ld}k5I$&u}avIDQ-D(_EP zhgdc{)5r_iTFiZ;Q)5Uq=U73lW%uYN=JLo#OS;B0B=;j>APk?|!t{f3grv0nv}Z%` zM%XJk^#R69iNm&*^0SV0s9&>cl1BroIw*t3R0()^ldAsq)kWcI=>~4!6fM#0!K%TS ziZH=H%7-f=#-2G_XmF$~Wl~Um%^9%AeNSk)*`RDl##y+s)$V`oDlnK@{y+#LNUJp1^(e89sed@BB z^W)sHm;A^9*RgQ;f(~MHK~bJRvzezWGr#@jYAlXIrCk_iiUfC_FBWyvKj2mBF=FI;9|?0_~=E<)qnjLg9k*Qd!_ zl}VuSJB%#M>`iZm*1U^SP1}rkkI};91IRpZw%Hb$tKmr6&H5~m?A7?+uFOSnf)j14 zJCYLOYdaRu>zO%5d+VeXa-Ai7{7Z}iTn%yyz7hsmo7E|{ z@+g9cBcI-MT~2f@WrY0dpaC=v{*lDPBDX}OXtJ|niu$xyit;tyX5N&3pgmCxq>7TP zcOb9%(TyvOSxtw%Y2+O&jg39&YuOtgzn`uk{INC}^Na_-V;63b#+*@NOBnU{lG5TS zbC+N-qt)u26lggGPcdrTn@m+m>bcrh?sG4b(BrtdIKq3W<%?WuQtEW0Z)#?c_Lzqj*DlZ zVUpEV3~mG#DN$I#JJp3xc8`9ex)1%Il7xKwrpJt)qtpq}DXqI=5~~N}N?0g*YwETZ z(NKJO5kzh?Os`BQ7HYaTl>sXVr!b8>(Wd&PU*3ivSn{;q`|@n*J~-3tbm;4WK>j3&}AEZ*`_!gJ3F4w~4{{PyLZklDqWo|X}D zbZU_{2E6^VTCg#+6yJt{QUhu}uMITs@sRwH0z5OqM>taO^(_+w1c ztQ?gvVPj<_F_=(ISaB~qML59HT;#c9x(;0vkCi2#Zp`;_r@+8QOV1Ey2RWm6{*J&9 zG(Dt$zF^7qYpo9Ne}ce5re^j|rvDo*DQ&1Be#Fvo#?m4mfFrNZb1#D4f`Lf(t_Fib zwxL3lx(Zp(XVRjo_ocElY#yS$LHb6yl;9;Ycm1|5y_praEcGUZxLhS%7?b&es2skI z9l!O)b%D=cXBa@v9;64f^Q9IV$xOkl;%cG6WLQ`_a7I`woHbEX&?6NJ9Yn&z+#^#! zc8;5=jt~Unn7!cQa$=a7xSp}zuz#Lc#Q3-e7*i`Xk5tx_+^M~!DlyBOwVEq3c(?`@ zZ_3qlTN{eHOwvNTCLOHjwg0%niFYm({LEfAieI+k;U2&uTD4J;Zg#s`k?lxyJN<$mK6>j?J4eOM@T*o?&l@LFG$Gs5f4R*p*V1RkTdCfv9KUfa< z{k;#JfA3XA5NQJziGd%DchDR*Dkld&t;6i9e2t7{hQPIG_uDXN1q0T;IFCmCcua-e z`o#=uS2_en206(TuB4g-!#=rziBTs%(-b1N%(Bl}ea#xKK9zzZGCo@<*i1ZoETjeC zJ)ll{$mpX7Eldxnjb1&cB6S=7v@EDCsmIOBWc$p^W*;C0i^Hc{q(_iaWtE{0qbLjxWlqBe%Y|A z>I|4)(5mx3VtwRBrano|P))JWybOHUyOY67zRst259tx;l(hbY@%Z`v8Pz^0Sw$?= zwSd^HLyL+$l&R+TDnbV_u+h{Z>n$)PMf*YGQ}1Df@Nr{#Gr+@|gKlnv?`s1rm^$1+ zic`WeKSH?{+E}0^#T<&@P;dFf;P5zCbuCOijADb}n^{k=>mBehDD6PtCrn5ZBhh2L zjF$TbzvnwT#AzGEG_Rg>W1NS{PxmL9Mf69*?YDeB*pK!&2PQ7!u6eJEHk5e(H~cnG zZQ?X_rtws!;Tod88j=aMaylLNJbgDoyzlBv0g{2VYRXObL=pn!n8+s1s2uTwtZc

YH!Z*ZaR%>WTVy8-(^h5J^1%NZ$@&_ZQ)3AeHlhL~=X9=fKPzFbZ;~cS**=W-LF1 z5F82SZ zG8QZAet|10U*jK*GVOA(iULStsUDMjhT$g5MRIc4b8)5q_a?ma-G+@xyNDk{pR*YH zjCXynm-fV`*;}%3=+zMj**wlCo6a{}*?;`*j%fU`t+3Korws%dsCXAANKkmVby*eJ z6`2%GB{+&`g2;snG`LM9S~>#^G|nZ|JMnWLgSmJ4!kB->uAEF0sVn6km@s=#_=d)y zzld%;gJY>ypQuE z!wgqqTSPxaUPoG%FQ()1hz(VHN@5sfnE68of>9BgGsQP|9$7j zGqN{nxZx4CD6ICwmXSv6&RD<-etQmbyTHIXn!Q+0{18=!p))>To8df$nCjycnW07Q zsma_}$tY#Xc&?#OK}-N`wPm)+2|&)9=9>YOXQYfaCI*cV1=TUl5({a@1wn#V?y0Yn z(3;3-@(QF|0PA}|w4hBWQbTItc$(^snj$36kz{pOx*f`l7V8`rZK}82pPRuy zxwE=~MlCwOLRC`y%q8SMh>3BUCjxLa;v{pFSdAc7m*7!}dtH`MuMLB)QC4B^Uh2_? zApl6z_VHU}=MAA9*g4v-P=7~3?Lu#ig)cRe90>@B?>})@X*+v&yT6FvUsO=p#n8p{ zFA6xNarPy0qJDO1BPBYk4~~LP0ykPV ztoz$i+QC%Ch%t}|i^(Rb9?$(@ijUc@w=3F1AM}OgFo1b89KzF6qJO~W52U_;R_MsB zfAC29BNUXpl!w&!dT^Zq<__Hr#w6q%qS1CJ#5Wrb*)2P1%h*DmZ?br)*)~$^TExX1 zL&{>xnM*sh=@IY)i?u5@;;k6+MLjx%m(qwDF3?K3p>-4c2fe(cIpKq#Lc~;#I#Wwz zywZ!^&|9#G7PM6tpgwA@3ev@Ev_w`ZZRs#VS4}<^>tfP*(uqLL65uSi9H!Gqd59C&=LSDo{;#@Isg3caF1X+4T}sL2B+Q zK*kO0?4F7%8mx3di$B~b&*t7y|{x%2BUg4kLFXt`FK;Vi(FIJ+!H zW;mjBrfZdNT>&dDfc4m$^f@k)mum{DioeYYJ|XKQynXl-IDs~1c(`w{*ih0-y_=t$ zaMDwAz>^CC;p*Iw+Hm}%6$GN49<(rembdFvb!ZyayLoqR*KBLc^OIA*t8CXur+_e0 z3`|y|!T>7+jdny7x@JHtV0CP1jI^)9){!s#{C>BcNc5#*hioZ>OfDv)&PAM!PTjS+ zy1gRZirf>YoGpgprd?M1k<;=SShCMn406J>>iRVnw9QxsR|_j5U{Ixr;X5n$ih+-=X0fo(Oga zB=uer9jc=mYY=tV-tAe@_d-{aj`oYS%CP@V3m6Y{)mZ5}b1wV<9{~$`qR9 zEzXo|ok?1fS?zneLA@_C(BAjE_Bv7Dl2s?=_?E9zO5R^TBg8Be~fpG?$9I; zDWLH9R9##?>ISN8s2^wj3B?qJxrSSlC6YB}Yee{D3Ex8@QFLZ&zPx-?0>;Cafcb-! zlGLr)wisd=C(F#4-0@~P-C&s%C}GvBhb^tTiL4Y_dsv@O;S56@?@t<)AXpqHx9V;3 zgB!NXwp`=%h9!L9dBn6R0M<~;(g*nvI`A@&K!B`CU3^FpRWvRi@Iom>LK!hEh8VjX z_dSw5nh-f#zIUDkKMq|BL+IO}HYJjMo=#_srx8cRAbu9bvr&WxggWvxbS_Ix|B}DE zk!*;&k#1BcinaD-w#E+PR_k8I_YOYNkoxw5!g&3WKx4{_Y6T&EV>NrnN9W*@OH+niSC0nd z#x*dm=f2Zm?6qhY3}Kurxl@}d(~ z<}?Mw+>%y3T{!i3d1%ig*`oIYK|Vi@8Z~*vxY%Od-N0+xqtJ*KGrqo*9GQ14WluUn z+%c+og=f0s6Mcf%r1Be#e}&>1n!!ZxnWZ`7@F9ymfVkuFL;m6M5t%6OrnK#*lofS{ z=2;WPobvGCu{(gy8|Mn(9}NV99Feps6r*6s&bg(5aNw$eE ztbYsrm0yS`UIJ?Kv-EpZT#76g76*hVNg)L#Hr7Q@L4sqHI;+q5P&H{GBo1$PYkr@z zFeVdcS?N1klRoBt4>fMnygNrDL!3e)k3`TXoa3#F#0SFP(Xx^cc)#e2+&z9F=6{qk z%33-*f6=+W@baq){!d_;ouVthV1PREX^ykCjD|%WUMnNA2GbA#329aEihLk~0!!}k z)SIEXz(;0lemIO{|JdO{6d|-9LePs~$}6vZ>`xYCD(ODG;OuwOe3jeN;|G$~ml%r* z%{@<9qDf8Vsw581v9y+)I4&te!6ZDJMYrQ*g4_xj!~pUu#er`@_bJ34Ioez)^055M$)LfC|i*2*3E zLB<`5*H#&~R*VLYlNMCXl~=9%o0IYJ$bY+|m-0OJ-}6c@3m<~C;;S~#@j-p?DBdr<><3Y92rW-kc2C$zhqwyq09;dc5;BAR#PPpZxqo-@e_s9*O`?w5 zMnLUs(2c-zw9Pl!2c#+9lFpmTR>P;SA#Id;+fo|g{*n&gLi}7`K)(=tcK|?qR4qNT z%aEsSCL0j9DN$j8g(a+{Z-qPMG&O)H0Y9!c*d?aN0tC&GqC+`%(IFY$ll~!_%<2pX zuD`w_l)*LTG%Qq3ZSDE)#dt-xp<+n=3&lPPzo}r2u~>f8)mbcdN6*r)_AaTYq%Scv zEdwzZw&6Ls8S~RTvMEfX{t@L4PtDi{o;|LyG>rc~Um3;x)rOOGL^Bmp0$TbvPgnwE zJEmZ>ktIfiJzdW5i{OSWZuQWd13tz#czek~&*?iZkVlLkgxyiy^M~|JH(?IB-*o6% zZT8+svJzcVjcE0UEkL_5$kNmdrkOl3-`eO#TwpTnj?xB}AlV2`ks_Ua9(sJ+ok|%b z=2n2rgF}hvVRHJLA@9TK4h#pLzw?A8u31&qbr~KA9;CS7aRf$^f1BZ5fsH2W8z}FU zC}Yq76IR%%g|4aNF9BLx6!^RMhv|JYtoZW&!7uOskGSGL+}_>L$@Jg2Vzugq-NJW7 zzD$7QK7cftU1z*Fxd@}wcK$n6mje}=C|W)tm?*V<<{;?8V9hdoi2NRm#~v^#bhwlc z5J5{cSRAUztxc6NH>Nwm4yR{(T>0x9%%VeU&<&n6^vFvZ{>V3RYJ_kC9zN(M(` zp?1PHN>f!-aLgvsbIp*oTZv4yWsXM2Q=C}>t7V(iX*N8{aoWphUJ^(n3k`pncUt&` ze+sYjo)>>=I?>X}1B*ZrxYu`|WD0J&RIb~ zPA_~u)?&`}JPwc1tu=OlKlJ3f!9HXa)KMb|2%^~;)fL>ZtycHQg`j1Vd^nu^XexYkcae@su zOhxk8ws&Eid_KAm_<}65zbgGNzwshR#yv&rQ8Ae<9;S^S}Dsk zubzo?l{0koX8~q*{uA%)wqy*Vqh4>_Os7PPh-maB1|eT-4 zK>*v3q}TBk1QlOF!113XOn(Kzzb5o4Dz@?q3aEb9%X5m{xV6yT{;*rnLCoI~BO&SM zXf=CHLI>kaSsRP2B{z_MgbD;R_yLnd>^1g`l;uXBw7|)+Q_<_rO!!VaU-O+j`u%zO z1>-N8OlHDJlAqi2#z@2yM|Dsc$(nc>%ZpuR&>}r(i^+qO+sKfg(Ggj9vL%hB6 zJ$8an-DbmKBK6u6oG7&-c0&QD#?JuDYKvL5pWXG{ztpq3BWF)e|7aF-(91xvKt047 zvR{G@KVKz$0qPNXK*gt*%qL-boz-*E;7LJXSyj3f$7;%5wj)2p8gvX}9o_u}A*Q|7 z)hjs?k`8EOxv1zahjg2PQDz5pYF3*Cr{%iUW3J+JU3P+l?n%CwV;`noa#3l@vd#6N zc#KD2J;5(Wd1BP)`!IM;L|(d9m*L8QP|M7W#S7SUF3O$GFnWvSZOwC_Aq~5!=1X+s z6;_M++j0F|x;HU6kufX-Ciy|du;T%2@hASD9(Z)OSVMsJg+=7SNTAjV<8MYN-zX5U zVp~|N&{|#Z)c6p?BEBBexg4Q((kcFwE`_U>ZQotiVrS-BAHKQLr87lpmwMCF_Co1M z`tQI{{7xotiN%Q~q{=Mj5*$!{aE4vi6aE$cyHJC@VvmemE4l_v1`b{)H4v7=l5+lm^ ztGs>1gnN(Vl+%VuwB+|4{bvdhCBRxGj3ady^ zLxL@AIA>h@eP|H41@b}u4R`s4yf9a2K!wGcGkzUe?!21Dk)%N6l+#MP&}B0%1Ar*~ zE^88}(mff~iKMPaF+UEp5xn(gavK(^9pvsUQT8V;v!iJt|7@&w+_va`(s_57#t?i6 zh$p!4?BzS9fZm+ui`276|I307lA-rKW$-y^lK#=>N|<-#?WPPNs86Iugsa&n{x%*2 zzL_%$#TmshCw&Yo$Ol?^|hy{=LYEUb|bMMY`n@#(~oegs-nF){0ppwee|b{ca)OXzS~01a%cg&^ zp;}mI0ir3zapNB)5%nF>Sd~gR1dBI!tDL z&m24z9sE%CEv*SZh1PT6+O`%|SG>x74(!d!2xNOt#C5@I6MnY%ij6rK3Y+%d7tr3&<^4XU-Npx{^`_e z9$-|@$t`}A`UqS&T?cd@-+-#V7n7tiZU!)tD8cFo4Sz=u65?f#7Yj}MDFu#RH_GUQ z{_-pKVEMAQ7ljrJ5Wxg4*0;h~vPUI+Ce(?={CTI&(RyX&GVY4XHs>Asxcp%B+Y9rK z5L$q94t+r3=M*~seA3BO$<0%^iaEb2K=c7((dIW$ggxdvnC$_gq~UWy?wljgA0Dwd`ZsyqOC>)UCn-qU5@~!f znAWKSZeKRaq#L$3W21fDCMXS;$X(C*YgL7zi8E|grQg%Jq8>YTqC#2~ys%Wnxu&;ZG<`uZ1L<53jf2yxYR3f0>a;%=$SYI@zUE*g7f)a{QH^<3F?%({Gg)yx^zsdJ3^J2 z#(!C3qmwx77*3#3asBA(jsL`86|OLB)j?`0hQIh>v;c2A@|$Yg>*f+iMatg8w#SmM z<;Y?!$L--h9vH+DL|Wr3lnfggMk*kyGH^8P48or4m%K^H-v~`cBteWvnN9port02u zF;120HE2WUDi@8?&Oha6$sB20(XPd3LhaT~dRR2_+)INDTPUQ9(-370t6a!rLKHkIA`#d-#WUcqK%pMcTs6iS2nD?hln+F-cQPUtTz2bZ zq+K`wtc1;ex_iz9?S4)>Fkb~bj0^VV?|`qe7W02H)BiibE9=_N8=(5hQK7;(`v7E5Mi3o? z>J_)L`z(m(27_&+89P?DU|6f9J*~Ih#6FWawk`HU1bPWfdF?02aY!YSo_!v$`&W znzH~kY)ll^F07=UNo|h;ZG2aJ<5W~o7?*${(XZ9zP0tTCg5h-dNPIM=*x@KO>a|Bk zO13Cbnbn7+_Kj=EEMJh4{DW<))H!3)vcn?_%WgRy=FpIkVW>NuV`knP`VjT78dqzT z>~ay~f!F?`key$EWbp$+w$8gR1RHR}>wA8|l9rl7jsT+>sQLqs{aITUW{US&p{Y)O zRojdm|7yoA_U+`FkQkS?$4$uf&S52kOuUaJT9lP@LEqjKDM)iqp9aKNlkpMyJ76eb zAa%9G{YUTXa4c|UE>?CCv(x1X3ebjXuL&9Dun1WTlw@Wltn3zTareM)uOKs$5>0tR zDA~&tM~J~-YXA<)&H(ud)JyFm+d<97d8WBr+H?6Jn&^Ib0<{6ov- ze@q`#Y%KpD?(k{if5-M(fO3PpK{Wjqh)7h+ojH ztb=h&vmy0tn$eA8_368TlF^DKg>BeFtU%3|k~3lZAp(C$&Qjo9lR<#rK{nVn$)r*y z#58_+t=UJm7tp|@#7}6M*o;vn7wM?8Srtc z3ZFlKRDYc^HqI!O9Z*OZZ8yo-3ie9i8C%KDYCfE?`rjrf(b&xBXub!54yaZY2hFi2w2asEOiO8;Hru4~KsqQZMrs+OhO8WMX zFN0=EvME`WfQ85bmsnPFp|RU;GP^&Ik#HV(iR1B}8apb9W9)Nv#LwpED~%w67o;r! zVzm@zGjsl)loBy6p>F(G+#*b|7BzZbV#E0Pi`02uAC}D%6d12TzOD19-9bhZZT*GS zqY|zxCTWn+8*JlL3QH&eLZ}incJzgX>>i1dhff}DJ=qL{d?yv@k33UhC!}#hC#31H zOTNv5e*ozksj`4q5H+75O70w4PoA3B5Ea*iGSqA=v)}LifPOuD$ss*^W}=9kq4qqd z6dqHmy_IGzq?j;UzFJ*gI5)6qLqdUL;G&E*;lnAS+ZV1nO%OdoXqw(I+*2-nuWjwM-<|XD541^5&!u2 z1XflFJp(`^D|ZUECbaoqT5$#MJ=c23KYpBjGknPZ7boYRxpuaO`!D6C_Al?T$<47T zFd@QT%860pwLnUwer$BspTO9l1H`fknMR|GC?@1Wn`HscOe4mf{KbVio zahne0&hJd0UL#{Xyz=&h@oc>E4r*T|PHuNtK6D279q!2amh%r#@HjaN_LT4j>{&2I z?07K#*aaZ?lNT6<8o85cjZoT~?=J&Xd35I%JJom{P=jj?HQ5yfvIR8bd~#7P^m%B-szS{v<)7i?#at=WA+}?r zwMlc-iZv$GT};AP4k2nL70=Q-(+L_CYUN{V?dnvG-Av+%)JxfwF4-r^Z$BTwbT!Jh zG0YXK4e8t`3~){5Qf6U(Ha0WKCKl^zlqhqHj~F}DoPV#yHqLu+ZWlv2zH29J6}4amZ3+-WZkR7(m{qEG%%57G!Yf&!Gu~FDeSYmNEkhi5nw@#6=Bt& zOKT!UWVY-FFyq1u2c~BJ4F`39K7Vw!1U;aKZw)2U8hAb&7ho|FyEyP~D<31{_L>RrCU>eEk-0)TBt5sS5?;NwAdRzRj5qRSD?J6 ze9ueq%TA*pgwYflmo`=FnGj2r_u2!HkhE5ZbR_Xf=F2QW@QTLD5n4h(?xrbOwNp5` zXMEtm`m52{0^27@=9VLt&GI;nR9S)p(4e+bAO=e4E;qprIhhclMO&7^ThphY9HEko z#WfDFKKCcf%Bi^umN({q(avHrnTyPH{o=sXBOIltHE?Q65y_At<9DsN*xWP|Q=<|R z{JfV?B5dM9gsXTN%%j;xCp{UuHuYF;5=k|>Q=;q zU<3AEYawUG;=%!Igjp!FIAtJvoo!*J^+!oT%VI4{P=XlbYZl;Dc467Nr*3j zJtyn|g{onj!_vl)yv)Xv#}(r)@25OHW#|eN&q7_S4i2xPA<*uY9vU_R7f};uqRgVb zM%<_N3ys%M;#TU_tQa#6I1<+7Bc+f%mqHQ}A@(y^+Up5Q*W~bvS9(21FGQRCosvIX zhmsjD^OyOpae*TKs=O?(_YFjSkO`=CJIb*yJ)Pts1egl@dX6-YI1qb?AqGtIOir&u zyn>qxbJhhJi9SjK+$knTBy-A)$@EfzOj~@>s$M$|cT5V!#+|X`aLR_gGYmNuLMVH4 z(K_Tn;i+fR28M~qv4XWqRg~+18Xb?!sQ=Dy)oRa)Jkl{?pa?66h$YxD)C{F%EfZt| z^qWFB2S_M=Ryrj$a?D<|>-Qa5Y6RzJ$6Yp`FOy6p2lZSjk%$9guVsv$OOT*6V$%TH zMO}a=JR(1*u`MN8jTn|OD!84_h${A)_eFRoH7WTCCue9X73nbD282V`VzTH$ckVaC zalu%ek#pHxAx=0migDNXwcfbK3TwB7@T7wx2 zGV7rS+2g9eIT9>uWfao+lW2Qi9L^EBu#IZSYl0Q~A^KYbQKwNU(YO4Xa1XH_>ml1v z#qS;P!3Lt%2|U^=++T`A!;V-!I%upi?<#h~h!X`p7eP!{+2{7DM0$yxi9gBfm^W?M zD1c)%I7N>CG6250NW54T%HoCo^ud#`;flZg_4ciWuj4a884oWUYV(#VW`zO1T~m(_ zkayymAJI)NU9_0b6tX)GU+pQ3K9x=pZ-&{?07oeb1R7T4RjYYbfG^>3Y>=?dryJq& zw9VpqkvgVB?&aK}4@m78NQhTqZeF=zUtBkJoz8;6LO<4>wP7{UPEs1tP69;v919I5 zzCqXUhfi~FoK5niVU~hQqAksPsD@_|nwH4avOw67#fb@Z5_OS=$eP%*TrPU%HG<-A z`9)Y3*SAdfiqNTJ2eKj8B;ntdqa@U46)B+odlH)jW;U{A*0sg@z>-?;nN}I=z3nEE@Bf3kh1B zdqT{TWJvb#AT&01hNsBz8v(OwBJSu#9}A6Y!lv|`J#Z3uVK1G`0$J&OH{R?3YVfk% z9P3HGpo<1uy~VRCAe&|c4L!SR{~^0*TbVtqej3ARx(Okl5c>m~|H9ZwKVHc_tCe$hsqA`l&h7qPP5xBgtwu!; zzQyUD<6J!M5fsV-9P?C9P49qnXR+iXt#G_AS2N<6!HZ(eS`|-ndb|y!(0Y({2 z4aF~GO8bHM7s+wnhPz>sa!Z%|!qWk*DGr)azB}j6bLe#FQXV4aO>Eo7{v`0x=%5SY zy&{kY+VLXni6pPJYG_Sa*9hLy-s$79$zAhkF)r?9&?UaNGmY9F$uf>iJ~u@Q;sydU zQaN7B>4B*V;rtl^^pa3nFh$q*c&sx^Um}I)Z)R&oLEoWi3;Yv6za?;7m?fZe>#_mS z-EGInS^#UHdOzCaMRSLh7Mr0}&)WCuw$4&K^lx{;O+?Q1p5PD8znQ~srGrygJ?b~Q5hIPt?Wf2)N?&Dae4%GRcRKL(a-2koctrcvxSslXn-k9cYS|<-KJ#+$Wo>}yKKh*3Q zHsK(4-Jv!9R3*FKmN$Z#^aZcACGrlGjOe^#Z&DfPyS-1bT9OIX~-I-5lN6Y>M}dvivbs2BcbPcaNH%25-xMkT$>*soDJ) z27;};8oCYHSLF0VawZFn8^H;hIN=J457@eoI6s2P87QN6O`q8coa;PN$mRZ>2Vv+! zQj1}Tvp8?>yyd_U>dnhx%q~k*JR`HO=43mB?~xKAW9Z}Vh2b0<(T89%eZ z57kGs@{NUHM>|!+QtqI@vE8hp`IIGc`A9Y{p?c;@a!zJFmdaCJ;JmzOJ8)B1x{yZp zi!U{Wh-h+u6vj`2F+(F6gTv*cRX7MR z9@?>is`MSS1L#?PaW6BWEd#EX4+O1x6WdU~LZaQ^Quow~ybz*aAu{ZMrQ;yQ8g)-qh>x z^}@eFu1u7+3C0|hRMD1{MEn(JOmJ|wYHqGyn*xt-Y~J3j@nY56i)sgNjS4n@Q&p@@^>HQjzNaw#C9=TbwzDtiMr2a^}bX< zZE%HU^|CnS`WYVcs}D)+fP#bW0+Q#l#JC+!`OlhffKUCN8M-*CqS;VQX`If78$as0 z=$@^NFcDpTh~45heE63=x5nmP@4hBaFn(rmTY2Yj{S&k;{4W!0Nu9O5pK30}oxM7{ z>l4cKb~9D?N#u_AleD<~8XD@23sY^rt&fN%Q0L=Ti2bV#px`RhM$}h*Yg-iC4A+rI zV~@yY7!1}-@onsZ)@0tUM23cN-rXrZYWF#!V-&>vds8rP+w0t{?~Q zT^LN*lW==+_ifPb+-yMh9JhfcYiXo_zWa`ObRP9_En3P))Qyu0qPJ3*hiFSu>Vt-j z<*HWbiP2#BK@nt<g|pe3 zfBKS@i;ISkorx@cOIx9}p^d8Gis%$)))%ByVYU^KG#eE+j1p;^(Y1ndHnV&YuQZm~ zj;f+mf>0ru!N`)_p@Ls<& z`t+JDx7}R568Q|8`4A}G@t8Wc?SOXunyW5C-AWoB@P>r}uwFY*=?=!K@J(!t@#xOuPXhFS@FTf6-7|%k;nw2%Z+iHl219Ho1!bv(Ee0|ao!Rs%Jl0@3suGrOsb_@VM;(xzrf^Cbd;CK3b%a|ih-fG)`Rd00O74=sQYW~Ve z#fl!*(fo~SIQ5-Sl?1@o7-E*|SK|hoVEKzxeg!$KmQLSTN=5N`rYeh$AH&x}JMR+5dq|~FUy&Oj%QIy;HNr;V*7cQC+ka>LAwdU)?ubI@W z={eg%A&7D**SIj$cu=CN%vN^(_JeIHMUyejCrO%C3MhOcVL~Niu;8WYoN}YVhb+=- zR}M3p|H0`E2Id99y#03r`8$s0t*iD>`^7EPm1~guC)L~uW#O~>I85Q3Nj8(sG<@T| zL^e~XQt9O0AXQ^zkMdgzk5bdYttP~nf-<831zulL>>ghTFii$lg3^80t8Gb*x1w5| zN{kZuv`^8Fj=t(T*46M=S$6xY@0~AvWaGOYOBTl0?}KTkplmGn-*P(X=o-v^48OY} zi11-+Y}y)fdy_tI;*W(>#qzvgQZ52t!nrGsJEy!c86TKIN(n|!&ucCduG$XaIapI z{(Z9gZANsI={A=5Aorgq2H25Dd}H5@-5=j=s{f`%^>6b5qkm_2|3g>r-^amf=B_xV zXg*>aqxXZ6=VUI4$})ypDMy$IKkgJ;V>077T9o#OhpFhKtHP_4mnjS5QCgGe<;~Xe zt<2ZhL7?JL6Mi|U_w?;?@4OD@=4EB2op_s)N-ehm#7`zSU#7itU$#%^ncqjc`9HCG zfj;O1T+*oTkzRi-6NN`oS3w3$7ZB37L>PcN$C$L^qqHfiYO4_>0_qCw0r@FEMj=>}}%q_`d#pUT;c?=gI zqTGpiY4Z;Q(B~#hXIVBFbi#dO=cOdmOqD0|An?7nMdrm2^C>yw*dQ=#lf8)@DvXK; z$MXp}QZgnE!&L73x0LZX_bCdD4lRY$$^?9dt1RwCng{lIpbb%Ej%yOh{@76yEyb}K zXZy%^656Sk3BLKbalcc>Dt5iDzo^tj2!wnDL(X;urJfpkWrab!frFSC6Q7m zuoqN!(t=L&+Ov&~9mz(yEB`MK%RPXS>26Ww5(F;aZ zR@tPAw~=q2ioOiynxgBqE&3-R-@6yCo0*mE;#I^c!=g~HyyjGA6}|<(0EseKDTM4w z94YnCO^VYIUY@}x8kr;;El-cFHVO<$6;-UdmUB|J8R*Wf$a37gVgYT|w5^KkYe=(i zMkA$%7;^a*$V+}e%S~&*^^O;AX9NLt@cIPc*v!lKZ)(zahAsUj%PJot19ErFU=Uk( z9Hw;Lb`V+BzVpMu;TGB9}y~ff)^mbEmF?g{{7_0SR zPgp*n)l{?>7-Ji;eWG{ln$)Bro+UJAQo6W2-23d@SI=HiFV3hR2OUcAq_9q~ye)o@ zq8WZvhg`H(?1AUZ-NM%_Cuj}eb{4wOCnqs^E1G9U4HKjqaw@4dsXWP#$wx^}XPZ0F zywsJ0aJHA>AHc^q#nhQjD3!KDFT6FaDioJ#HsZU7Wo?8WH19TJ%OMDz$XH5J4Cjdt z@crE;#JNG`&1H8ekB(R4?QiiZ55kztsx}pQti}gG0&8`dP=d(8aCLOExd*Sw^WL`Q zHvZ(u`5A58h?+G&GVsA;pQNNPFI)U@O`#~RjaG(6Y<=gKT2?1 z*pCUGU)f??VlyP64P@uT`qh?L03ZQyLOBn?EKwH+IG{XvTh5|NldaSV_n~DK&F1aa znq~C_lCQHMfW6xib%a2m!h&%J)aXb{%-0!HCcW|kzaoSwPMhJ6$KL|F~Sx(tctbwfkgV;#KZlEmJN5&l5XF9eD;Kqb<| z>os)CqC^qF8$be|v;)LY{Gh@c0?a??k7M7&9CH+-B)t&T$xeSzCs30sf8O-+I#rq} z&kZj5&i>UyK9lDjI<*TLZ3USVwwpiE5x8<|{Db z3`HX3+Tt>1hg?+uY{^wC$|Tb7ud@3*Ub?=2xgztgv6OOz0G z-4VRyIChHfegUak^-)-P;VZY@FT64#xyo=+jG<48n2%wcx`ze6yd51(!NclmN=$*kY=#uu#>=yAU-u4I9Bt0n_6ta?&9jN+tM_5_3RH);I zxTN4n$EhvKH%TmOh5mq|?Cx$m>$Ed?H7hUEiRW^lnW+}ZoN#;}aAuy_n189qe1Juk z6;QeZ!gdMAEx4Na;{O*j$3F3e?FLAYuJ2iuMbWf8Ub6(nDo?zI5VNhN@ib6Yw_4P)GY^0M7TJwat z2S*2AcP}e0tibZ@k&htTD&yxT9QRG0CEq$;obfgV^&6YVX9B9|VJf`1aS_#Xk>DFo zwhk?~)>XlP5(u~UW0hP7dWZuCuN4QM24Td&j^7~)WQ6YeCg)njG*ri}tTcG-NxX}p zNB>kcxd5ipW@tN3=6r@Jgm#rgrK*dXA!gxy6fAvP7$)8)Vc~PPQ|`( zPy|bG1sUz958-!zW^j(8ILV%QC@x`~PDFczboZqWjvSU<9O3!TQ&xYi%?Y0AiVBLV z%R?#1L#G&xw*RZPsrwF?)B5+MSM(b$L;GLnRsSU!_$N;6pD97~H}`c>0F`&E_FCNE z_)Q*EA1%mOp`z>+h&aqlLKUD9*w?D>stDeBRdR*AS9)u;ABm7w1}eE|>YH>YtMyBR z^e%rPeZzBx_hj?zhJVNRM_PX(O9N#^ngmIJ0W@A)PRUV7#2D!#3vyd}ADuLry;jdn zSsTsHfQ@6`lH z^GWQf?ANJS>bBO-_obBL$Apvakhr1e5}l3axEgcNWRN$4S6ByH+viK#CnC1|6Xqj& z*_i7cullAJKy9GBAkIxUIzsmN=M|(4*WfBhePPHp?55xfF}yjeBld7+A7cQPX8PE-|Pe_xqboE;2AJb5ifrEfr86k&F0+y!r`-urW}OXSkfz2;E``UTrGSt^B)7&#RSLTQitk=mmPKUKP`uGQ4)vp_^$^U`2Jjq zeul!ptEpa%aJo0S(504oXPGdWM7dAA9=o9s4-{>z*pP zJ31L#|L?YR;^%+>YRJrLrFC=5vc;0{hcxDKF z!ntmgO>rVDaGmRpMI7-+mv(j~;s_LARvcpkXj|{GHu1c<1 zKI)#7RE~Dizu1lG>p-PcY2jX#)!oJlBA$LHnTUWX=lu``E)vhf9h4tYL-juZ`e|Kb z=F?C;Ou)h^cxB;M-8@$ZSH0jkVD>x-XS$ePV1vlU8&CG))4NgU(=XFH=Jb1IB7dBysS+94}Y>sjS(&YcJwhn zifzA|g$D5rW89vkJSv()I+Th4R&C$g-!CB30xkh%aw4po3$@DK2fW>}enE2YPt&{C~j}`>RYICK{ zYAPfZ&%`R}u6MYo<>d`^O#Q(dM{3>T^%J{Vu;lr#Utg4x9!Z9J%iXs(j+dn&SS1_2 zzxGtMnu^`d%K4Xq4Ms-ErG3_7n?c(3T!?rvyW=G<7_XKDv*ox`zN*^BVwUoqh{D7o zdEiq;Zp6}k_mCIAVTUcMdH|fo%L#qkN19X$%b1#Oko|u4!M*oRqdBa3z98{H#g=d%5X&D#NXhLh`nUjxi8@3oo(AgeItdJ zIrt9ieHI1GiwHiU4Cba-*nK@eHI4uj^LVmVIntU@Gwf^t6i3{;SfLMCs#L;s;P4s5oqd^}8Uil!NssP>?!K z07nAH>819U=^4H6l-Dhy`^Q6DV^}B9^aR0B%4AH=D&+dowt9N}zCK+xHnXb-tsKaV6kjf;Wdp#uIZ_QsI4ralE>MWP@%_5eN=MApv92( z09SSB#%eE|2atm9P~X2W2F-zJD+#{q9@1}L2fF|Lzu@1CAJq*d6gA8*Jjb;<+Asih zctE|7hdr5&b-hRhVe}PN z$0G{~;pz1yhkbwuLkfbvnX=<7?b(1PhxAmefKn$VS6Sv)t-UypwhEs3?*E=(pc%Dlul1V~OdWvdf z{WBX?lhfO_g$$X~hm^Bhl@U0t<|beYgT)2L_C(z@B^-63c9Ak2*Aa)iOMylfl|qyNQdO#yoJ?m2FOkhZ1ou@G%+^m z#!#(gTv8nx^34(HddDp|dcFl@&eh+&FFJc@^FL3fV2?u&9Wt|Yp3&MS)e+ez0g~Ys zY7d0n^)+ z0@K^GJTLN?XAV(0F6e>o>HCGJU5(8WsSFErs0FsO=O1u$=T~xx7HYK{7C>-IGB8U+ z&G^Vy>uY}Bq7HX-X`U^nNh+11GjG-)N1l_tG<^4Tu4+4X9KO9IrdH+eXGk|G6Tc(U zU~g7BoO!{elBk>;uN-`rGQP-7qIf9lQhj-=_~0Qyszu>s$s0FrJatSylv!ol&{29~ z7S4fv&-UBOF&cR@xpuW*{x9$R;c_ALt?{+dI&HoBKG-!EY{yE=>aWhlmNhHlCXc(B zuA-zI*?Z9ohO$i8s*SEIHzVvyEF$65b5m=H*fQ)hi*rX8 zKlPqjD*Ix1tPzfR_Z3bO^n32iQ#vhjWDwj6g@4S?_2GyjiGdZZRs3MLM zTfl0_Dsn=CvL`zRey?yi)&4TpF&skAi|)+`N-wrB_%I_Osi~)9`X+`Z^03whrnP7f z?T`*4Id`J@1x#T~L(h5^5z%Cok~U|&g&GpCF%E4sB#i3xAe>6>24%Kuu=)=HRS;Pu2wghgTFa zHqm#sa{7-~{w_039gH0vrOm&KPMiPmuPRpAQTm5fkPTZVT&9eKuu%Riu%-oMQl2X6 z{Bnx`3ro^Z$}rVzvUZsk9T)pX|4%sY+j0i)If_z-9;a^vr1YN>=D(I7PX){_JTJ&T zPS6~9iDT{TFPn}%H=QS!Tc$I9FPgI<0R7?Mu`{FTP~rRq(0ITmP1yrJdy|m;nWmDelF-V^y7*UEVvbxNv0sHR?Q=PVYRuZinR(;RjVAG zm&qlSYvaiIbVEqBwyDaJ8LVmiCi{6ESF4pO?U&7pk&CASm6vuB;n-RauPFzdr!C%1 z8pjdSUts7EbA4Kg(01zK!ZU<-|d zU&jWswHnSLIg&mTR;!=-=~z(#!UsXt%NJR|^teM8kG@8Qg_0^6Jqfn&(eENtP8D7K zvnll3Y%7yh1Ai~0+l6dAG|lEGe~Oa+3hO>K2}{ulO?Vf*R{o2feaRBolc;SJg)HXHn4qtzomq^EM zb)JygZ=_4@I_T=Xu$_;!Q`pv6l)4E%bV%37)RAba{sa4T*cs%C!zK?T8(cPTqE`bJ zrBWY`04q&+On`qH^KrAQT7SD2j@C>aH7E8=9U*VZPN-(x>2a++w7R$!sHH+wlze2X)<<=zC_JJvTdY7h&Jum?s?VRV)JU`T;vjdi7N-V)_QCBzI zcWqZT{RI4(lYU~W0N}tdOY@dYO8Rx5d7DF1Ba5*U7l$_Er$cO)R4dV zE#ss{Dl`s#!*MdLfGP>?q2@GSNboVP!9ZcHBZhQZ>TJ85(=-_i4jdX5A-|^UT}~W{CO^Lt4r;<1ps@s|K7A z90@6x1583&fobrg9-@p&`Gh+*&61N!$v2He2fi9pk9W2?6|)ng7Y~pJT3=g~DjTcYWjY9gtZ5hk*1Qf!y2$ot@0St$@r8|9^GMWEE>iB~etL zXYxn#Rvc`DV&y93@U$Z91md1qVtGY*M(=uCc}@STDOry@58JNx`bUH}EIb(n6I}i? zSYJOZ2>B6&Payu+@V!gxb;)_zh-{~qtgVwQ-V;vK7e0^Ag_$3+g+{xSVudVOY_p-R z$sXhpFSk7je2lk5)7Y2;Z847E1<;5?;z(I)55YFtgF!J;NT|eVi}q^*2sM}zyM{+s zD0phl+J>k1E7cZEGmP?1-3~RE;R$q(I5}m?MX8xi?6@0f#rD8Cjkpv1GmL5HVbTnM zAQ&4-rbkpdaoLp~?ZoW>^+t0t1t%GO2B;ZD4?{qeP+qsjOm{1%!oy1OfmX?_POQJ4 zGwvChl|uE;{zGoO?9B_m{c8p(-;_yq?b^jA({}iQG35?7H7`1cm`BGyfuq7z1s~T| zm88HpS{z54T{jxC=>kZ=Z#8G@uya3tt0$xST5V$-V<;6MA66VFg}`LLU8L=q3DmkU z)P^X8pg`ndMY*>gr{6~ur^Q@Z8LNQf*6wkP03K<|M*+cDc#XKZ`Z0$1FkI-IDRw#| za52W4MyHlDABs~AQu7Duebjgc}02W;1jgBx&I@TMDXU`LJutQ?@r%1z`W zlB8G-U$q37G1ob>Er8j0$q@OU3IwG#8HsvJM#)j=Y%~#zY`jaG%5;!(kY3*a^t>(qf6>I zpAJpF%;FQ?BhDSsVG27tQEG*CmWhl4)Ngp%}D?U0!nb1=)1M==^B)^$8Li$boCY$S4U;G^A!?24nSYHra{< zSNapX#G+0BTac|xh`w&}K!);$sA3ay%^a2f?+^*9Ev8ONilfwYUaDTMvhqz2Ue2<81uuB71 zAl|VEOy%GQ7zxAJ&;V^h6HOrAzF=q!s4x)Mdlmp{WWI=gZRk(;4)saI0cpWJw$2TJcyc2hWG=|v^1CAkKYp;s_QmU?A;Yj!VQ1m-ugzkaJA(wQ_ zah00eSuJg<5Nd#OWWE?|GrmWr+{-PpE_Dbqs&2`BI=<%ggbwK^8VcGiwC-6x`x|ZY z1&{Vj*XIF2$-2Lx?KC3UNRT z&=j7p1B(akO5G)SjxXOjEzujDS{s?%o*k{Ntu4*X z;2D|UsC@9Wwk5%)wzTrR`qJX!c1zDZXG>-Q<3Z)7@=8Y?HAlj_ZgbvOJ4hPlcH#Iw z!M-f`OSHF~R5U`p(3*JY=kgBZ{Gk;0;bqEu%A;P6uvlZ0;BAry`VUoN(*M9NJ z%CU2_w<0(mSOqG;LS4@`p(3*Z7jC|Khm5-i>FcYr87};_J9)XKlE}(|HSfnA(I3)I zfxNYZhs#E6k5W(z9TI2)qGY&++K@Z?bd;H%B@^!>e2Wi@gLk)wC)T93gTxdRPU7uh z)`$-m(G2I5AuK52aj!fMJR|d^H?0X~+4xSpw zqNRtq5r8hic*{eAwUT<=gI5uXLg)o5mg4XnO^T+Rd+{l)<$Aqp{+RxhNYuX^45W0k z5$t%+7R;dX$`s6CYQYcims>5bNt+k&l_t%C9D-6sYVm%Y8SRC#kgRh*%2kqMg2ewb zp_X*$NFU%#$PuQ@ULP>h9Xw`cJ>J-ma8lU`n*9PcWFpE%x0^}(DvOVe2jz@ z0^2QOi0~t!ov?jI{#bw~`Aj5ymQW@eruRg`ZNJ5IT5_5AHbQ?|C>_7rwREf2e2x&L zlV8xdOkp_*+wdaqE?6bmdrFfaGepcj=0AI<+c=Tg^WB9BhFx?SvwoVdTEm&zPy@Vs zPs2mVPiw1n_h?Xi6!+w)ypsFXXuM>gIY(J+1N6r!sJ{+r1%BzRF20!D;bN>L^?O8n z(5|x2p^Q6X`!pm3!MMFET5`nJXn>tK`fFAj5Eo&t6;F>TU_4G93YGyzvF2_fB& zfE8(dq?R@@&Wh8~%G~rDt1+e)96O5)by_%;G~Zv`TpmZ)vY@BkAan*zEy(s`*{-@U z;$WPjoNx~m?`6Z;^O=K3SBL3LrIxfU{&g)edERkPQZK!mVYU-zHuV0ENDq^e<-?^U zGyRcrPDZZw*wxK(1SPUR$0t0Wc^*u_gb*>qEOP102FX|`^U%n*7z=wM@pOmYa6Z=-)T%!{tAFELY2`dTl3$&w! z7sgKXCTU(h3+8)H#Qov19%85Xo+oQh?C-q0zaM_X2twSCz|j_u!te3J2zLV#Ut_q7 zl+5LGx#{I`(9FzE$0==km|?%m?g~HB#BSz2vHynf1x14mEX^~pej*dhzD|6gMgOJ_ z8F_<>&OIz;`NSqrel?HI-K(|ypxwz}NtX!CF3&T(CkuYOnKS&%lUSU44KsgS`L>!w zl{MoT4`t=+p8>@88)Ea%*hOIkxt#b4RfrwRMr91UF_Ic~kV;|+dRW0a8Vl725+gsvtHr5 z>?3fai&9NmU|3;-nAu8OB|<(-2Kfub4MX&1i}dDd=R~Dk=U-Vr=@&lfEIYU~xtHHO z4TKt=wze`qm=69lD)sOOkZ;$9=0B#*g@X6xPM-%zG*rCXkN%eRDEUp$gAaEd29t&T zRTAg##Sk+TAYaa(LyTD__zL3?Z+45^+1o}(&f<~lQ*-z7`Um^>v@PKqOunTE#OyKFY^q&L^fqZgplhXQ>P3?BMaq6%rO5hfsiln7TppJ z>nG9|2MmL|lShn4-yz0qH>+o;Fe`V!-e*R0M|q~31B=EC$(bQZTW^!PrHCPE4i|>e zyAFK!@P}u>@hqwf%<#uv*jen5xEL|v!VQEK!F`SIz_H8emZfn#Hg}}@SuqPv+gJ@- zf3a`DT_Q#)DnHv+XVXX`H}At zmQwW2K`t@(k%ULJrBe6ln9|W8+3B*pJ#-^9P?21%mOk(W1{t#h?|j0ZrRi_dwGh#*eBd?fy(UBXWqAt5I@L3=@QdaiK`B_NQ$ zLXzm{0#6zh2^M zfu>HFK^d`&v|x&xxa&M|pr))A4)gFw<_X@eN`B1X%C^a{$39fq`(mOG!~22h)DYut z(?MONP1>xp4@dIN^rxtMp&a^yeGc8gmcajyuXhgaB;3}vFCQFa!pTDht9ld9`&ql`2&(dwNl5FZqedD^BP zf5K1`(_&i7x-&rD=^zkFD87idQrk(Y?E;-j^DMCht`A8Qa5J-46@G_*Y3J+&l{$}*QCATEc9zuzaQGHR8B;y*>eWuv)E##?Ba3w= zZ|v(l{EB`XzD#|ncVm#Wy?#Nzm3bS1!FJ70e{DGe$EgNDg7<_ic^mJSh&Xc|aTwCrTv;XkW~UlS&G%KyLklCn}F^i(YP(f z{cqH%5q9ND_S;l$HRP$Q@`D=F*_1$CXIA5X@|V&Vir$NQ$vCx!b&LGCR<-2y)m%HI zxeeyQIjiWcf4uD9+FP+EJ`&$oJ%$R(#w~GjqP|aTQj#d(;l#rq$vcM&Y4ZQ_i{Kpx z?k2BtoKb?+1-EVmG^ne-W%8+y?i#J5N5g8f^qpH5(ZZp7$u+?I9GB+&MREX?TmVV$ zA}Ps=^CkD^sD9N;tNtN!a>@D^&940cTETu*DUZlJO*z7BBy`Rl;$-D@8$6PFq@tz0 z=_2JMmq-JRSvx`;!XM|kO!|DENI-5ke8WR*Zj#vy#Nf1;mW-{6>_sCO8?sVWOKDM| zR(iaZrBrzlRatUzp_Y|2nOXnY2G%WLGXCo9*)th_RnXvXV=q;WNAimI98!A54|$&OCCG%$4m{%E&o?S|Qx<4K~YGmM1CS!vZAzLN%d znbZsw6ql=XkiwSbNofNeA42q8#LH6Rk(u@z172O#6K>Sb{#`t#GUgpd{2;D(9@I_9 zwsY(6Go7RmOThs2rM3|Z#Vbs}CHPLgBK6gE8;XkJQDx~p5wJ?XkE(0<^hwnt6;$~R zXCAzMfK@`myzdkkpv*ZbarVwCi&{-O#rswrb-#x4zRkxfVCq;mJLic|*C92T?0CYv z)FCqY$xA(QZmggPocZqQj0Rc?=Afna`@fpSn)&nSqtI}?;cLphqEF3F9^OZfW9@HDunc^2{_H)1D9(O}4e zJMi_4(&$CD{Jf5&u|7#Iq*F~)l!8pAzNrX^<&wfEu~}Ipslzx=g^ff2?B9SnV=!$ zv&K0`hMN6BVIusHNX-lr`#K?OG1S*S4rCQaI3ea(!gCl7YjxJ3YQ)7-b&N*D8k><*x|47s3; z4f~WTWuk|Qd*d*DICV}Vb0YSzFZp5|%s4}@jvtTfm&`|(jNpajge zD}@CMaUBs+b?Yu6&c#18=TxzMCLE76#Dy=DLiq_a_knQX4Uxk$&@3ORoBFK_&a>`QKaWu^)Hzrqz{5)?h3B_`4AOn{fG9k zEwnjQb>8XRq!k?rmCd6E**1cY#b9yczN4mD%GLCeRk}{TmR1*!dTNzY;(f!B0yVuk zSjRyf;9i@2>bdGSZJ=FNrnxOExb075;gB z*7&YR|4ZraFO#45-4h%8z8U}jdt?83AmU3)Ln#m3GT!@hYdzqqDrkeHW zU#R`Z8RHq996HR=mC}SRGtsz07;-C-!n*ALpwwBe~loM)YqMH)Um$sH0RbTTzxFd)h1=-w5Yl3k|3nQ zZG>=_yZ7Lsn=b8_MZI+LSHLGYSSCc?ht~7cv#39>Moz6AS}5 zus?xge0PGdFd2FpXgIscWOyG}oxATgd$yl0Ugf_&J_vwt`)XWx!p*gE_cWU(tUTnz zQS}!bMxJyi3KWh^W9m zxLcy``V@EfJzYjK@$e7Yk=q!kL8cd3E-zpc*wwvGJ62O!V;N zFG7Y?sJ+^a%H1;rdDZRu2JmGn6<&ERKes=Pwx)GG-nt73&M78+>SOy!^#=gvLB)2H zjv!J0O`-zft|0Jv$3k5wScY)XB+9leZgR5%3~HtZA=bCg7=Dn+F}>2lf;!*1+vBtf z9jhmqlH=t5XW{0MC7Y~O7jaju&2`p!ZDLGlgnd~%+EJ%A#pIByi-+EOmoLVoK&ow8 zTDjB%0hxhiRv+O3c2*y00rMA=)s|3-ev7emcbT43#izku7dvaDXy1IMV0ahjB9yzi z9C9fN+I2Mzt1*{`a6B?+PdWHiJ5fH}rb2t>q)~3RfCxmyK^y5jN7Pn(9DFh61GO%p zuBErj=m|bDn_L8SINU)Z&@K*AgGz+SUYO_RUeJt=E0M+eh&kqK;%Y1psBNU<4-s9# ziHFr7QP6Ew=-2CdfA#Bf|EsctH;<&=Hsd>)Ma8NvHB$cpVY@}TV!UN}3?9o@CS5kw zx%nXo%y|r5`YOWoZi#hE(3+rNKLZ2g5^(%Z99nSVt$2TeU2zD%$Q(=$Y;%@QyT5Rq zRI#b><}zztscQaTiFbsu2+%O~sd`L+oKYy5nkF4Co6p88i0pmJN9In`zg*Q;&u#uK zj#>lsuWWH14-2iG z&4w{6QN8h$(MWPNu84w1m{Qg0I31ra?jdyea*I~Xk(+A5bz{x%7+IL}vFDUI-Rf{! zE^&Dau9QxA2~)M98b42(D6Q}2PUum0%g>B?JS?o~VrP+Go2&c-7hIf7(@o1*7k$zS zy@o5MEe8DoX$Ie(%SZByyf9Xf9n8xkoX}s6RiO1sg*kAV^6EAAz$>*x^OmIy!*?1k zG+UQ|aIWDEl%)#;k{>-(w9UE7oKM#2AvQud}sby=D7$l6{$}SE8O9WgHM_+ zJ?tHeu@Pi93{AuwVF^)N(B~0?#V*6z;zY)wtgqF7Nx7?YQdD^s+f8T0_;mFV9r<+C z4^NloIJIir%}ptEpDk!z`l+B z5h(k$0bO$VV(i$E@(ngVG^YAjdieHWwMrz6DvNGM*ydHGU#ZG{HG5YGTT&SIqub@) z=U)hR_)Q@#!jck+V`$X5itp9&PGiENo(yT5>4erS<|Rh#mbCA^aO2rw+~zR&2N6XP z5qAf^((HYO2QQQu2j9fSF)#rRAwpbp+o=X>au|J5^|S@(vqun`du;1_h-jxJU-%v| z_#Q!izX;$3%BBE8Exh3ojXC?$Rr6>dqXlxIGF?_uY^Z#INySnWam=5dV`v_un`=G*{f$51(G`PfGDBJNJfg1NRT2&6E^sG%z8wZyv|Yuj z%#)h~7jGEI^U&-1KvyxIbHt2%zb|fa(H0~Qwk7ED&KqA~VpFtQETD^AmmBo54RUhi z=^Xv>^3L^O8~HO`J_!mg4l1g?lLNL$*oc}}QDeh!w@;zex zHglJ-w>6cqx3_lvZ_R#`^19smw-*WwsavG~LZUP@suUGz;~@Cj9E@nbfdH{iqCg>! zD7hy1?>dr^ynOw|2(VHK-*e%fvU0AoKxsmReM7Uy{qqUVvrYc5Z#FK&Z*XwMNJ$TJ zW1T**U1Vfvq1411ol1R?nE)y%NpR?4lVjqZL`J}EWT0m7r>U{2BYRVVzAQamN#wiT zu*A`FGaD=fz|{ahqurK^jCapFS^2e>!6hSQTh87V=OjzVZ}ShM3vHX+5IY{f^_uFp zIpKBGq)ildb_?#fzJWy)MLn#ov|SvVOA&2|y;{s;Ym4#as?M^K}L_g zDkd`3GR+CuH0_$s*Lm6j)6@N;L7Vo@R=W3~a<#VxAmM&W33LiEioyyVpsrtMBbON+ zX^#%iKHM;ueExK@|t3fX`R+vO(C zucU#Xf>OjSH0Kd%521=Sz%5Y!O(ug(?gRH@K>IUayFU~ntx`Wdm27dB-2s@)J=jf_ zjI-o;hKnjQ|Lg~GKX!*OHB69xvuDU zuG-H48~inKa)^r539a{F)OS`*4GShX>%BR)LU~a-|6+sx&FYsrS1}_b)xSNOzH|Kv zq>+1-cSc0`99EsUz(XWcoRO)|shn>TqKoQBHE)w8i8K`*Xy6(ls%WN_#d}YC^)NJ; zzl8!Zduz^Gg8*f0tCWnLEzw6k5Fv!QWC1x4)3r}+x~@#O8_)0>lP-@3(kFwLl%%Mz(TpATVnL5Pl2Gahw45QXI~>Hrw))CcEs@PP?}4^zkM$ z@(?H6^`Jl?A=(&Ue;W0`*a8&fR7vde@^q^AzX^H#gd~96`Ay^_A%?;?@q@t7l7iGn zWms#2J|To4;o1?3g3L!K_chdtmbEg~>U>$5{WO@Ip~YE&H($(^X6y_OBuNHkd0wu= z4rXGy#-@vZ?>M<_gpE8+W-{#ZJeAfgE#yIDSS?M?K(oY@A|FaS3P;OjMNOG% zGWyZWS(}LJCPaGi9=5b%sq$i!6x@o(G}wwfpI5|yJe24d_V}cT1{^(Qe$KEMZ;>I@ zuE6ee%FLgem>CKEN8SeY)fpK#>*lGcH~71)T4p|9jWT;vwM@N!gL}nCW=Oi6+_>K2 zl4sWXeM1U}RETA~hp=o3tCk+?Zwl#*QA>Wwd|FlUF0)U;rEGPD1s0Syluo zfW9L(F>q9li8YKwKXZrp*t)N9E;?&Hdbm-AZp2BcDTHO6q=tzVkZsozEIXjIH`tm} zo2-UleNm*Lj7zgvhBph_|1IggkSuW~S(9ueZEfao8BuzqlF(a+pRivTv(Zb zXFaHwcuovdM#d+!rjV7F<^VW&@}=5|xj!OUF)s0zh|8yzC)7!9CZB+TLnycoGBsDF z$u&j={5c(4A$iik;x6_S96Krw8--+9pGY+*oSVTIuq;$z8*)W8B~rMX_(U6uM}!Gc`T;WfEKwI84%)-e7j}>NA(O_)3Vn9 zjXxY1Fnx3Fx%CFpUHVu0xjvxgZv}F9@!vC!lD|05#ew3eJ}@!V&urwRKH`1f{0e^o zWvM1S@NbI6pHdzm33pza_q;#?s%J*$4>10uYi4l%5qi|j5qh+D=oqSJR=7QwkQh>>c$|uJ#Z@lK6PMHs@ zyvnnoOSkGQkYz#g>||xN&1fV)aJb*y--Y`UQV~lt!u8yTUG59ns1l7u>CX2F>9fl; zB)zH3z^XHmSU{F_jlvESvaNL&nj^;j)29~1LcTYw>(6}>bt0hiRooqm0@qTj%A&P9 zKmexPwyXG@Rs1i+8>AJ;=?&7RHC7Mn%nO>@+l?Qj~+lD376O2rp)>tlVHn8MKq zwop1KRLhUjZ|+6ecGIAftSPT*3i94=QzYCi_ay+5J&O(%^IsqZ!$w-^bmd7ds$^!q z;AkC;5mTAU>l0S$6NSyG30Ej?KPq@#T)^x#x?@U~fl2m$Ffk)s6u|iPr!)-j0BlA7p3E*A|My8S#KH;8i-IQq7Q*F4*ZVPe<{^SWz_ zr?!6cS+@|C#-P~d#=W1n7acn8_pg#W-lcyf+41zwR+BU6`jUkP^`*wgX)FxEaXzoi z8)?FE*97Yqz|b@fR1(r{QD363t260rQ(F||dt9^xABi+{C*_HL9Zt5T;fq|#*b}=K zo5yj_cZB(oydMAL&X(W6yKf>ui?!%(HhiHJ83EA|#k0hQ!gpVd( zVSqRR&ado+v4BP9mzamKtSsV<|0U-Fe2HP5{{x&K>NxWLIT+D^7md{%>D1Z-5lwS~ z6Q<1`Hfc+0G{4-84o-6dr@)>5;oTt|P6jt9%a43^wGCslQtONH)7QXJEYa!c~39 zWJpTL@bMYhtem1de>svLvOUa*DL7+Ah0(_~2|ng`!Z!qiN}6xL;F}<%M8qWv&52-Y zG*1A&ZKlp~{UFV%Hb_*Re({93f7W*jJZMV-Yn|<+l3SPN+%GuPl=+tSZxxr%?6SEc zntb0~hcK691wwxlQz_jSY+V_h+0o`X!Vm{;qYK$n?6ib1G{q>a%UejzOfk6q<=8oM z6Izkn2%JA2E)aRZbel(M#gI45(Fo^O=F=W26RA8Qb0X;m(IPD{^Wd|Q;#jgBg}e( z+zY(c!4nxoIWAE4H*_ReTm|0crMv8#RLSDwAv<+|fsaqT)3}g=|0_CJgxKZo7MhUiYc8Dy7B~kohCQ$O6~l#1*#v4iWZ=7AoNuXkkVVrnARx?ZW^4-%1I8 zEdG1%?@|KmyQ}tploH>5@&8Cp{`)CxVQOss&x|Z7@gGL3=tCVNDG!N9`&;N$gu^MDk|`rRm=lhnXAJ5v1T)WTz)qvz|Dw zR?{}W4VB(O6#9%o9Z^kFZZV*PDTAWqkQ8TH!rti8QIcR&>zcg3qG}&A( zwH^K8=`1C1lRfhrX{IvNn9R9!$UMC%k(;;VH%`S0h_on|Gh6qDSH&#}*m-u{;p~WB zF$_I~xx!RxVrxNQdr@3T>{F#^D{@N9OYC9LsV62F_Z1KYQ5yk*C5WQ4&q}Kz(I{9UWWf?LIcCZicB1EO_FUH*a9QKS(4IR%#D5DTi_@M}Q_-4)J4d zz@!vR0}5MPAOK(#uL+$7XOcP$5SS#*EK9Rt6XN%}HB7@`8S^gNRk!HLv(CvCjX4o= z>9scPwWbE!F8T=@x9^;s-OF2!eO(!gL9$-AmzUiDnu&QS4If5ea2T070n1-IyNhck z9$J8b!he3@q5qB-cQ;5ymVIXXn46kK0sqKZV+3s3^mac=3~BrCW})WNrrRs1KtMmg zLzwXYC?@_H#s3W4D$W0rh%WL|G<1$$uYdptPbxy0ke!c%v#x9I=2?S)YVkg1X$W^cB!i>B{e9wXlm8AcCT8|verIZQngj>{%W%~W0J%N`Q($h z^u3}p|HyHk?(ls7?R`a&&-q@R<94fI30;ImG3jARzFz<(!K|o9@lqB@Va+on`X2G) zegCM8$vvJ$kUwXlM8df|r^GQXr~2q*Zepf&Mc%kgWGTf;=Wx%7e{&KId-{G}r22lI zmq%L6Y-M*T$xf8 z#kWOBg2TF1cwcd{<$B)AZmD%h-a6>j z%I=|#ir#iEkj3t4UhHy)cRB$3-K12y!qH^1Z%g*-t;RK z6%Mjb*?GGROZSHSRVY1Ip=U_V%(GNfjnUkhk>q%&h!xjFvh69W8Mzg)7?UM=8VHS* zx|)6Ew!>6-`!L+uS+f0xLQC^brt2b(8Y9|5j=2pxHHlbdSN*J1pz(#O%z*W-5WSf# z6EW5Nh&r<;$<3o1b013?U$#Y!jXY)*QiGFt|M58sO45TBGPiHl4PKqZhJ|VRX=AOO zsFz-=3$~g#t4Ji9c;GFS9L~}~bzgCqnYuJ-60AMDdN7HZt8_$~Of{oXaD3HVn9zkH z`>#xQNe=YpWTq_LcOoy}R`L<_4il7w4)QH4rl?AUk%?fH##I>`1_mnp&=$-%SutYT zs}sSNMWo;(a&D()U$~PG0MvZ#1lmsF&^P4l_oN#_NORD-GSmR{h_NbJ^ZdY#R9#qW zKAC%V*?y~}V1Zh#d|-z1Z8sy5A+}*cOq$xk@Pn&{QffzG-9ReyPeEhqF%~Z3@|r(s z3(wA&)dV~fELW*&*=!~l9M=7wq8xE(<@)BjjN8bUiS8@N9E{wi+Dd!V1AtT;Nl}9> zTz`2ge2Jn#Dlg1kC%oFlOe<>?jYC`Asr^%i4hH;S`*qZTPRan2a9Kjj=0aq{iVi2Z z87PZt$d(LAm_{92kl+2Z%k3KGV;~gsp;C>k?gMYZrVIzaI|0D+fka9G_4v>N96*8T zI(C8bj?A7l%V&U?H_IpSeCvf7@y1e?b>G7cN382GVO0qAMQ93(T*<*9c_;%P1}x2l zi8S$s<=e_8ww%DaBAf4oIQ7}U7_48$eYpo}Fb+F|K|43IAPR1y9xbqPPg6er{I7xj|=>-c%pGBRLn1~=5KbAb1mJAx=z(loN!w{49VkEthF>*OX z)=gqXyZB5%5lIWYPWh~{!5pSt43-)-@L@x=pmiuKP-3Cwq8qSxGNwaTT4->BWEjxk zUjr)z7WrBZB5u3iV>Y_>*i~*!vRYL)iAh5hMqNzVq1eeq=&d9Ye!26jks{f~6Ru&c zg$D;^4ui#kC`rSxx`fP!zZ^6&qSneQzZRq0F*V4QvKYKB<9FC%t#)Tik%Zq*G*IOW z3*`2!4d)!3oH>GxVcXlorJDt+JnH)p{~olYBPq|>_V@8=l#(f*diW=L+%>rfWCcPQ z#H^ksQt15Z5Uc4ODq8_JwD5^H&OGqyH6E@MabJQO>s`?bqgA6}J_QpytW{2jH#eCN z8k7y*TFZ2lj2B|1CB(@QZedFfPhX|IQbKMI;$YK>9Zla0fsU7}an6(kP;sXpBWLR` zJ#z_kk!`JJC7h(1J!+G)gL2WB2&0*~Q!%s??}GH?=`hU@03xOwU} z6s7?tGySLz!%(MwxQRiF)2(vR2wQX`YB}u&I-S+RR)LQcyH407#-{*pWLJJR?X|5 zsAl2k{&0N-?JArn@)9YTo-5+gl}R~XkbZM*5AOjPrcikpE3P?p0oN^?H+5+n)}Qxe z*RQ!-eu0RxPyF8B=}xnseNpQMXFU$d^=(G%kUd&|!BHSm7bXoGR$WA+%yjuA{|S>u z?9N6JDhS+ui~rd?wY_t7`p)|qKIMM>6jz%$jv4hc_YUDjF6-%5muq|SNuoji2)|qK zNY5+oWMe+5vu{I*grk6xlVk;(J)uuy13G`VDbj(~Vz9lA)_;$aj?=-cmd#h~N0mn{ z9EIS_d4C=L3H;Pl^;vcpb&-B+)8vt%#?gn5z>#;G{1L&8u8cXJYADMUsm9>%*%)&F zsi&I{Y=VUsV82+)hdNgDWh^M7^hMs|TA0M269^|RIGfdX1MetV2z`Ycb&_Mn4iRI! zeI6O}O9mOhN6pzfs5IfMz#Gxl`C{(111okA8M4gijgb~5s7QTyh84zUiZZ^sr1^ps z1GO`$eOS@k@XP^OVH|8)n}Wx)fKHoGwL&5;W?qEf5Jdsd!3hf7L`%QNwN0gGBm^2= z@WI+qJMJG1w2AS9d@Dt$sj_P$+S2kh7+M72^SfcdBjQEtWQ5?PT&a~G9hOo6CtS>h zoghqoR;sk{X)`ZK-M|lu{M}0>Mrs^ZW@ngC?c$26_vYKDBK^n7sFiod_xV#XcPL!^ zRPyqD{w^9u{oA3y73IW0 zH;%xop$r(Q=bq=JaLT%myEKD_2&?L@s6TzsUwE#g^OkiU6{lN)(7I?%a;_%r5_^@d zS-Z)Q-2o|~?F~f`sHlhNhiZk;!CW;3Ma6{xPlBjJx8PXc!Oq{uTo$p*tyH~ka`g<` z;3?wLhLg5pfL)2bYZTd)jP%f+N7|vIi?c491#Kv57sE3fQh(ScM?+ucH2M>9Rqj?H zY^d!KezBk6rQ|p{^RNn2dRt(9)VN_j#O!3TV`AGl-@jbbBAW$!3S$LXS0xNMr}S%f z%K9x%MRp(D2uO90(0||EOzFc6DaLm((mCe9Hy2 z-59y8V)5(K^{B0>YZUyNaQD5$3q41j-eX))x+REv|TIckJ+g#DstadNn_l~%*RBSss_jV3XS&>yNBc8H2jo(lwcLz-PuYp< z7>)~}zl$Ts0+RFxnYj7-UMpmFcw_H zYrsXM>8icD)@Iauiu_(Y#~Iyl)|pj@kHkWvg2N$kGG(W>Y)nfNn%z2xvTLwk1O2GQ zb^5KAW?c%5;VM4RWBy}`JVCBFOGQWoA9|+bgn7^fY3tSk1MSZccs9&Fy6{8F>_K@? zK(z=zgmq1R#jGE^eGV`<`>SP9SEBx!_-Ao|VZq6)-rUpd^<2GgVN&uHiM{0zA9kI( z<1^1%*uE$?4mXV@?W8}fvnBOpfwCo^?(a0E402!pZi&Kd5pp$oV%2Ofx<}YC-1mynB3X|BzWC_ufrmaH1F&VrU&Gs+5>uixj*OJ*f=gs9VR8k^7HRR$Ns|DYBc*Slz>hGK5B1}U+}#j0{ohGC zE80>WClD5FP+nUS?1qa}ENOPb2`P4ccI<9j;k?hqEe|^#jE4gguHYz-$_BCovNqIb zMUrsU;Fq%n$Ku_wB{Ny>%(B&x9$pr=Anti@#U%DgKX|HzC^=21<5Fn6EKc#~g!Mcj zJrI(gW+aK+3BWVFPWEF*ntHX5;aabHqRgU-Nr2t++%JRPP7-6$XS|M8o&YSgf3a9A zLW*tSJxoe1?#T4EocApa*+1kUIgy7oA%Ig9n@)AdY%)p_FWgF-Kxx{6vta)2X1O5y z#+%KQlxETmcIz@64y`mrSk2Z17~}k1n{=>d#$AVMbp>_60Jc&$ILCg-DTN~kM8)#o$M#Fk~<10{bQ>_@gU2uZE z*eN~mqqQC*wh{CI(!xvRQ^{jyUcvE~8N)S0bMA^SK@v;b7|xUOi63X~3Qc>2UNSD1) z7moi9K3QN_iW5KmKH>1ijU41PO>BvA6f1;kL)6io%^r>?YQ#+bB;)Rzad5;{XAJGeAT#FnDV0$w2>v|JeFIB zZ>8vmz?WVs78PuCDiHfb@D0Yi;2#%){*#?bY4dpta6dSjquGLcOw?Z{nxg98mN^4* zj&^!WMUQ_zFp+}B|G0vcNsk8(2u9(LAPk5ogKt%zgQ4^1#UCd;`-W#X8v{YyQ_m9g z8`jydw>>@1J{Q*q#5^cHVA~xR9LR3Hl@^bx)`IBKmj+Gmye36;xwL0>sS|mV+$~%b zC;2wEm&Ht3#6P|2Y0XQ+5t-aI)jn{o%&ZHWvjzEtSojFgXxNKO^e(RmM`gsJ4GrR8 zKhBtBoRjnH`mD$kT;-8ttq|iw?*`7iTF_AX<^Qe3=h8L^tqz$w$#Z@Z$`C579Jeeu ztr0z~HEazU&htfG@`HW!201!N(70hCd{%~@Wv)G*uKnJZ8>hFx`9LnYs;T>8p!`5T zx#aXXU?}B{QTV_Ux(EMzDhl-a^y^f5tRU;xnOQoN)pThr4M>-HU)As8nQ34-0*sab&z<2ye-D_3m&Q`KJJ|ZEZbaDrE%j>yQ(LM#N845j zNYrP)@)md;&r5|;JA?<~l^<=F1VRGFM93c=6@MJ`tDO_7E7Ru zW{ShCijJ?yHl63Go)-YlOW2n3W*x%w||iw(Cy>@dBJHdQl){bBVg{wmRt{#oXb9kaWqe{bJPmGE$$ z_0=cmD9dVzh<8&oyM8rK9F^bufW$Bj2cFhw&f*oKKyu$H{PI=Aqe^NL6B=dkMEAk& zE3y&F=x;e|!7kMn%(UX>G!OE$Y$@UyME#d;#d+WLmm@W@y!sboiIox^DZPB|EN<>7 z57xm5YWlFUGyF|{<*;b&Cqm+|DC8{rB9R@2EFHGL^NX*l#AcDpw6}bCmhY7!(Gv{s zm^eYNvzyJLQA#GhmL*oSt^Uulb5&ZYBuGJTC>Vm9yGaZ=Vd--pMUoDRaV_^3hE9b*Pby#Ubl65U!VBm7sV}coY)m zn1Ag^jPPLT93J{wpK%>8TnkNp;=a@;`sA7{Q}JmmS1bEK5=d@hQEWl;k$9M-PYX~S zayGm;P(Wwk23}JR7XM~kNqba`6!Z+Wt2|5K>g_j3ajhR>+;HF?88GBN!P; zr6sQ8YYpn%r^gbi8yYK7qx6U5^Tf<|VfcR$jCo`$VMVh_&(9w@O?|o3eRHq*e*#P z8-==G)D?vB3Zo~b-dkx8lg0^=gn`9FUy?ZzAfWQd>>@cyqF!sHQ_S&@$r&tTB~Lxq zAjAZTK~?J{A|L3)8K>S{`Qf%131B>?<~t=w!D{;olQ>#31R#{go`a9DOy+H*q5t+; z^*Ka!r@#8tk?~tQbylaG-$n#wP2VzIm3vjrZjcmTL zl`{6mhBhMKbSWoGqi;g3z1@G0q!ib`(Zz_o8HG_*vr8U5G|vhZn26h`f~bO&)RY0; zw(CWk*a_{ji_=O9U}66lI` zCm32)SEcAo5)5k>{<8DLI@Zz)*R29BB!^wF;WZRF9sAi39BGObmZzg?$lUn6w1rYPHSB^L4^AN zLObEaUh7TXpt6)hWck#6AZV(2`lze<`urGFre|>LUF+j5;9z%=K@&BPXCM)P$>;Xc z!tRA4j0grcS%E!urO^lsH-Ey*XY4m&9lK(;gJOyKk*#l!y7$BaBC)xHc|3i~e^bpR zz5E-=BX_5n8|<6hLj(W67{mWk@Bfc){NGAX z5-O3SP^38wjh6dCEDLB#0((3`g4rl}@I(&E8V2yDB=wYhSxlxB4&!sRy>NTh#cVvv z=HyRrf9dVK&3lyXel+#=R6^hf`;lF$COPUYG)Bq4`#>p z@u%=$28dn8+?|u94l6)-ay7Z!8l*6?m}*!>#KuZ1rF??R@Zd zrRXSfn3}tyD+Z0WOeFnKEZi^!az>x zDgDtgv>Hk-xS~pZRq`cTQD(f=kMx3Mfm2AVxtR(u^#Ndd6xli@n1(c6QUgznNTseV z_AV-qpfQ0#ZIFIccG-|a+&{gSAgtYJ{5g!ane(6mLAs5z?>ajC?=-`a5p8%b*r*mOk}?)zMfus$+W~k z{Tmz9p5$wsX1@q`aNMukq-jREu;;A6?LA(kpRut+jX?Tt?}4HGQr}7>+8z4miohO2 zU4fQ?Y8ggl%cj&>+M+)TTjn8(?^%`~!oAt#ri8gIbzIig$y#d7o##077fM9sCu%N9 zOIsq4vyox6`itu*j{eOD<$gTZd-$JuyM^cM>{?v<8# zS1yN%R0zRy&>+D*Gv-&S80?JF+Y|c^^IJWDnfy06MI2{NFO-x4JXsb@3Qp;EnL!a{ zJwKwV@mO zYVGvNmeJ!;+ce+@j@oo-+`DaPJX|h@7@4BD`QEdP?NKkYzdIa3KrZt%VUSsR+{b+| zk?dSd#9NnVl?&Y$A{-OtZ>wk%mWVF5)bf`)AA2{EFapIS4jil69Xan>*J^6Juou&`oJx|7-&|@8z?$ z2V#jm!UHstCE*qM{OGtqYY8q+x%SL6&aGY!a>@d=_G~^0;+7dY9P`oJ*)67*9Kx*O zKitC5V3g5;&L-fa37?eN=;V_c^L-ph_uKv5)Q`&!Z!RPlDWA2{J%a2q@_*?-cn@bH zIt)+mA@HaJj2RV+-MNc#y#Vji*N~m!ZyrYyg-7UK4PYK4F7Y$3Y%@Lk6iPp=I96N> z!;ih(KtZMB23*v{`5cJ}^4D*P!k1&OfU&1%borv_q|7jfaV7fL+wwx8Zp*b}B_O>NRSeJeM zpvw3M`=vSYjFYQ11kx1xqOnJ@degPh&SyXnWz-l719EiW17Yo?c~Bh~;R$MOl+jzV zM1yTq-1**x-=AVR;p0;IPi`#=E!G5qIT>EFE`Bn<7o*8!aVd7?(CZT=U9^Gi3rmWUQG z0|GaP9s$^4t_oLCs!fInyCoB(d?=tZ%%Bb2Y+X&7gvQ6~C4kU%e$W_H;-%XSM;&*HYYnLI z>%{5x_RtSUC~PI4C0H^>O%FixKYVubA>#72wexd}Cgwuw5ZYTvcN2ywVP(dO=5975 zCjo)mOa2Bo&ucEsaq8wi1{h*brT(H=XrTOy*P>?0%VV1QDr09X+Je!T)JT`02?gjX zT@B8}h|;4lH35Guq2gKZT?ags-~Ts~S=poPnQ_T1*?U|{$jaur_PjQ6WmF_(XLFG)d#|iiBC=&B zp}1eOQvQ!3UpL?K`=8hAzMkv#a^COr`J8i}d!BPX&*xp-LL#qse~mOtxI-}{yPRNV zJNTL1{7A55F~K>0e&Os%MwQ~?n1>QV=j!8o_`^-&*E|Q-L9DNr%#6sw8kQVE3E|*}$aAoO$@27ei1w=+zU%?AA!;mf#!%IV*w_D=u516!Kz1F0-WnyVB`I6F1Pc3r1=0iT<_(pCyk>@22z1$w$@M>7AIuk6+ zRG&MFVQ_7>5DLoR5HeOa$?2SA(v2u!#8;5I(ss%=x9U#R zU62n~&)22RTTsp${}6C&$+l&0skFVX%ACgc$(iQ#DVRRz!`Y+b>E?;ib(TH#6Wa=} zs(q_;SA|fhyEo7Ix%rAY9j=Ul^Rzd`3ABf+yO@~h@Rh=wo`?;8PdHE1AUo34r7izy znAr`;VavQueSu7bD5r^nXTERcW(P-{2SOSfF1x0cW1Nczvj0}@!!upORN1%_-b2bh zGt#zokJz&SveJRzlUK4DruxR(YuHEAmB%F}buU`*pAzJ7Mbgs4sg;H@&6x*wxvGm6 z>KH@ilsvvdl@CGfm4T+$agodrB=md8ygG!|O=r@FY>S_zX%*)mqf?XBX*chhQ9uPP z-(T(24)})vWD*{bQM5_hy3CD8C>anuNtCXMkG7T?Yew^>=PK!~Hlr0{-0h0cNAJ8> zRMzLFz7aJv)Yh)_s)^L&L*nDV@qfeg>_<`z1z(?s}}3tE4h|7_taB> zPfmmOCFZ8%>`gyf1@|7t3;e~mwBRCDDw(Rrt>@O}obs#1?!W((+9>d$b7t!{&wR!P ziQbn0@j=&sw={`s##Uc@uS^(tbShjtsk=qrU1LW0lu}BplIfzv{fwxNsSaG~b|ryo zTQ}YXfp6o?^sSHW>s~m;l@h6wFbIPw{Z(IqO1u){{hEZgrTdF0o$n;hYIm`h5ejym zWt^w~#8p1J)FtfY6LvGmNQ~#n>4#mN4B^ zjrQk)Zt%k}GBRD>l`<~og6N_{6HYKDtsAtd%y?KbXCQR(sW8O(v_)kwYMz|(OW zsFz6A1^abSklOl`wLC-KYI8x=oMD^qZBs}}JVW@YY|3&k&IZ_n2Ia@5WiK>buV!E- zOsYcS4dFPE7vzj%_?5i2!XY`TiPd*jy>#C`i^XG8h?f35`=)s`0EhQBN!+YrXbpt( z-bwg_Jen`w<+6&B`hldU%rr&Xdgtze>rKuJ61AI12ja-eDZZX-+u1H>Sa|7pCine9 z&MEhmT7nq`P!pPK>l?I8cjuPpN<7(hqH~beChC*YMR+p;;@6#0j2k$=onUM`IXW3> z`dtX8`|@P|Ep-_0>)@&7@aLeg$jOd4G`eIW=^dQQ*^cgKeWAsSHOY?WEOsrtnG|^yeQ3lSd`pKAR}kzgIiEk@OvQb>DS*pGidh`E=BHYepHXbV)SV6pE2dx6 zkND~nK}2qjDVX3Z`H;2~lUvar>zT7u%x8LZa&rp7YH@n@GqQ65Cv+pkxI1OU6(g`b z?>)NcE7>j@p>V0mFk-5Rpi`W}oQ!tUU&Yn8m0OWYFj|~`?aVFOx;e`M)Q!YSokY)3 zV6l-;hK6?j=mp2#1e5cCn7P6n_7)n^+MdRw@5pvkOA>|&B8`QZ32|ynqaf}Kcdro= zzQchCYM0^)7$;m2iZnMbE$!}hwk&AVvN`iX3A9mB&`*BDmLV-m`OMvd`sJ?;%U`p~ zmwow{y6sPbcZNQPZ#GQS0&mzy?s%>_p>ZM|sCXVAUlST;rQ-3#Iu!-bpFSV4g7?-l zGfX>Z#hR+i;9B};^CO@7<<#MGFeY)SC&;a{!` zf;yaQo%{bjSa8KT~@?O$cK z(DGnm7w>cG1hH#*J%X}%Y%~+nLT*{aP08@l&Nu}>!-j|!8lSqt_xUNF+Y}SQmupyb zPua2PI;@1YaIsRF*knA^rJv84Tc=7?J2}!1kMfHSO$d$+PK*u?OI%=P7;`PHxMB0k zau~T0Wk)rPEGJ$NiXW~kfPA#m%Sr|7=$tHelF9A6rFLa$^g{6)8GSW*6}#~Zb^qk% zg=pLwC!SkY+&Gne((9`TCy`i`a#eCS{A2yMi>J>p*NS*!V~aAgK;wnSOHPULqzyj- z-q4BPXqXn))iRnMF*WZj17wUYjC!h43tI7uScHLf1|WJfA7^5O9`%lH>ga`cmpiz( zs|I8nTUD4?d{CQ-vwD!2uwGU_Ts&{1_mvqY`@A{j^b?n&WbPhb418NY1*Otz19`1w zc9rn?0e_*En&8?OWii89x+jaqRVzlL!QUCg^qU&+WERycV&1+fcsJ%ExEPjiQWRTU zCJpu*1dXyvrJJcH`+OKn7;q`X#@Gmy3U?5ZAV~mXjQhBJOCMw>o@2kznF>*?qOW;D z6!GTcM)P-OY-R`Yd>FeX%UyL%dY%~#^Yl!c42;**WqdGtGwTfB9{2mf2h@#M8YyY+!Q(4}X^+V#r zcZXYE$-hJyYzq%>$)k8vSQU` zIpxU*yy~naYp=IocRp5no^PeFROluibl( zmaKkWgSWZHn(`V_&?hM{%xl3TBWCcr59WlX6Q{j45)`A^-kUv4!qM=OdcwpsGB)l} z&-_U+8S8bQ!RDc&Y3~?w5NwLNstoUYqPYs(y+lj!HFqIZ7FA>WsxAE7vB=20K zn_&y{2)Uaw4b^NCFNhJXd&XrhA4E~zD7Ue7X^f98=&5!wn_r=6qAwDkd>g#2+*ahd zaV|_P_8e%jiHh7W;cl(d=&-r-C}_Ov?bts8s^rKUWQ|XkuW!ToSwe}Z{4|kl+q&&W zn%iW48c5*ft#*m)+xSps+j(B5bPh&u0&m6=@WgwBf_QfJJzg2Qdz89HwcV`5kZ#5z zw;W&H8>5R(>KRwvd0gh30wJHA>|2N(im;~wy1HTv_}Ue%qb)>5qL^$hIyPvoT(nk_<`7F;#nS8;q!cqKspvBc<%xMsQj*h|>`Z)F6LDxue@to))OIbs2X+zY2L9#2UNrR^)?c8&PFc?j*&Q-r|C%7a$)ZRQ->#|?rEj&M4spQfNt;J^ntwf(d+q;tt)C`d{*|t)czD4x-qw{Chm0vuKp8axqy5`Yz z1756|;JX1q(lEieR=uT;%havqflgv+`5i!Z`R}(JNV~&`x}I9Lmm;aB7Bnc^UC?>W zu)(J7@fs}pL=Y-4aLq&Z*lO$e^0(bOW z3gWbcvb^gjEfhV=6Lgu2aX{(zjq|NH*fSgm&kBj?6dFqD2MWk5@eHt@_&^ZTX$b?o}S<9BGaCZIm6Hz)Qkruacn!qv*>La|#%j*XFp(*;&v3h4 zcjPbZWzv|cOypb@XDnd}g%(@f7A>w2Nseo|{KdeVQu)mN=W=Q`N?ID%J_SXUr0Rl# z3X;tO*^?41^%c!H;ia@hX``kWS3TR|CJ4_9j-?l6RjC=n?}r&sr>m%58&~?$JJV6{ zDq5h#m4S_BPiibQQaPGg6LIHVCc`9w3^3ZVWP$n>p7 z5dIEH-W9e;$Id8>9?wh%WnWf>4^1U<%vn=<4oNFhVl9zVk+jn;WtQUQ)ZeEjKYy8C z3g#tIb28thR1nZdKrN}(r zJdy-Y3Rvr5D3D|msZbmE;FLePbiM0ZjwTIQQHk)8G+sB$iwmEa2kQv&9Vs9m#$_8j zNKz}(x$Wc(M)a9H-Pn?5(Lk-CmOS(&+EVLOfsiq>e3ru6P?Lp>FOwPt>0o=j8UyF^ zO{(vf#MGx^y~WaOKnt%I78s}60(O#jFx0^47^Ikh$QTar(Dg$c=0KR|rRD|6s zz?tEX0_=(Hm0jWl;QOu!-k)mV?^i(Etl=Lg-{ z0G}CBprLX60zgAUz-fS^&m#o;erEC5TU+mn_Wj(zL$zqMo!e`D>s7X&;E zFz}}}puI+c%xq0uTpWS3RBlIS2jH0)W(9FU1>6PLcj|6O>=y)l`*%P`6K4}U2p}a0 zvInj%$AmqzkNLy%azH|_f7x$lYxSG=-;7BViUN(&0HPUobDixM1RVBzWhv8LokKI2 zjDwvWu=S~8We)+K{oMd-_cuXNO&+{eUaA8Ope3MxME0?PD+0a)99N>WZ66*;sn(N++hjPyz5z0RC{- z$pcSs{|)~a_h?w)y}42A6fg|nRnYUjMaBqg=68&_K%h3eboQ=%i083nfIVZZ04qOp%d*)*hNJA_foPjiW z$1r8ZZiRSvJT3zhK>iR@8_+TTJ!tlNLdL`e0=yjzv3Ie80h#wSfS3$>DB!!@JHxNd z0Mvd0Vqq!zfDy$?goY+|h!e(n3{J2;Ag=b)eLq{F0W*O?j&@|882U5?hUVIw_v3aV8tMn`8jPa5pSxzaZe{z}z|}$zM$o=3-mQ0Zgd?ZtaI> zQVHP1W3v1lbw>|?z@2MO(Ex!5KybKQ@+JRAg1>nzpP-!@3!th3rV=o?eiZ~fQRWy_ zfA!U9^bUL+z_$VJI=ic;{epla<&J@W-QMPZm^kTQ8a^2TX^TDpza*^tOu!WZ=T!PT z+0lJ*HuRnNGobNk0PbPT?i;^h{&0u+-fejISNv#9&j~Ep2;dYspntgzwR6<$@0dTQ z!qLe3Ztc=Ozy!btCcx!G$U7FlBRe}-L(E|RpH%_gt4m_LJllX3!iRYJEPvxcJ>C76 zfBy0_zKaYn{3yG6@;}S&+BeJk5X}$Kchp<Ea-=>VDg&zi*8xM0-ya!{ zcDN@>%H#vMwugU&1KN9pqA6-?Q8N@Dz?VlJ3IDfz#i#_RxgQS*>K+|Q@bek+s7#Qk z(5NZ-4xs&$j)X=@(1(hLn)vPj&pP>Nyu)emQ1MW6)g0hqXa5oJ_slh@(5MMS4xnG= z{0aK#F@_p=e}FdAa3tEl!|+j?h8h`t0CvCmNU%dOwEq<+jmm-=n|r|G^7QX4N4o(v zPU!%%w(Cet)Zev3QA?;TMm_aEK!5(~Nc6pJlp|sQP@z%JI}f0_`u+rc`1Df^j0G&s ScNgau(U?ep-K_E5zy1%ZQTdPn literal 0 HcmV?d00001 diff --git a/kotlin/gradle/wrapper/gradle-wrapper.properties b/kotlin/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..2b22d057a07 --- /dev/null +++ b/kotlin/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/kotlin/gradlew b/kotlin/gradlew new file mode 100755 index 00000000000..65dcd68d65c --- /dev/null +++ b/kotlin/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# 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 +# +# https://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. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/kotlin/gradlew.bat b/kotlin/gradlew.bat new file mode 100755 index 00000000000..6689b85beec --- /dev/null +++ b/kotlin/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/kotlin/kotlin-js-store/yarn.lock b/kotlin/kotlin-js-store/yarn.lock new file mode 100644 index 00000000000..537d261cff0 --- /dev/null +++ b/kotlin/kotlin-js-store/yarn.lock @@ -0,0 +1,2020 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.17" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" + integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + +"@socket.io/component-emitter@~3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" + integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== + +"@trustwallet/wallet-core@3.1.10": + version "3.1.10" + resolved "https://registry.yarnpkg.com/@trustwallet/wallet-core/-/wallet-core-3.1.10.tgz#3af4d0021a91f61faea7d3401d4e04197a843a9b" + integrity sha512-4/Du55HQLcNrJsBXWqUlk+5G7TCan1CfaOhRTxfXad1txWMtTj75kkYnbfST5Oi2DaKbuH86FF+yYroSdgoEiw== + dependencies: + protobufjs ">=6.11.3" + +"@types/cookie@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== + +"@types/cors@^2.8.12": + version "2.8.13" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94" + integrity sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA== + dependencies: + "@types/node" "*" + +"@types/eslint-scope@^3.7.3": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" + integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.4.10" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.10.tgz#19731b9685c19ed1552da7052b6f668ed7eb64bb" + integrity sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" + integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== + +"@types/estree@^0.0.51": + version "0.0.51" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" + integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== + +"@types/json-schema@*", "@types/json-schema@^7.0.8": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/node@*", "@types/node@>=10.0.0", "@types/node@>=13.7.0": + version "18.11.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" + integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== + +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== + +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== + +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== + +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== + +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== + +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-wasm-section" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-opt" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wast-printer" "1.11.1" + +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + +"@webassemblyjs/wasm-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5" + integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg== + +"@webpack-cli/info@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.5.0.tgz#6c78c13c5874852d6e2dd17f08a41f3fe4c261b1" + integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ== + dependencies: + envinfo "^7.7.3" + +"@webpack-cli/serve@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1" + integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abab@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + +accepts@~1.3.4: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + +acorn@^8.5.0, acorn@^8.7.1: + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64id@2.0.0, base64id@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" + integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +body-parser@^1.19.0: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserslist@^4.14.5: + version "4.21.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" + integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== + dependencies: + caniuse-lite "^1.0.30001449" + electron-to-chromium "^1.4.284" + node-releases "^2.0.8" + update-browserslist-db "^1.0.10" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001449: + version "1.0.30001449" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001449.tgz#a8d11f6a814c75c9ce9d851dc53eb1d1dfbcd657" + integrity sha512-CPB+UL9XMT/Av+pJxCKGhdx+yg1hzplvFJQlJ2n68PyQGMz9L/E2zCyLdOL8uasbouTUgnPl+y0tccI/se+BEw== + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@3.5.3, chokidar@^3.5.1: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.14: + version "2.0.19" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +connect@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" + integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + dependencies: + debug "2.6.9" + finalhandler "1.1.2" + parseurl "~1.3.3" + utils-merge "1.0.1" + +content-type@~1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie@~0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + +cors@~2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +custom-event@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" + integrity sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg== + +date-format@^4.0.14: + version "4.0.14" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400" + integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4.3.4, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +di@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" + integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA== + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +dom-serialize@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" + integrity sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ== + dependencies: + custom-event "~1.0.0" + ent "~2.2.0" + extend "^3.0.0" + void-elements "^2.0.0" + +dukat@0.5.8-rc.4: + version "0.5.8-rc.4" + resolved "https://registry.yarnpkg.com/dukat/-/dukat-0.5.8-rc.4.tgz#90384dcb50b14c26f0e99dae92b2dea44f5fce21" + integrity sha512-ZnMt6DGBjlVgK2uQamXfd7uP/AxH7RqI0BL9GLrrJb2gKdDxvJChWy+M9AQEaL+7/6TmxzJxFOsRiInY9oGWTA== + dependencies: + google-protobuf "3.12.2" + typescript "3.9.5" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.284: + version "1.4.284" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592" + integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +engine.io-parser@~5.0.3: + version "5.0.6" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.6.tgz#7811244af173e157295dec9b2718dfe42a64ef45" + integrity sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw== + +engine.io@~6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.2.1.tgz#e3f7826ebc4140db9bbaa9021ad6b1efb175878f" + integrity sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA== + dependencies: + "@types/cookie" "^0.4.1" + "@types/cors" "^2.8.12" + "@types/node" ">=10.0.0" + accepts "~1.3.4" + base64id "2.0.0" + cookie "~0.4.1" + cors "~2.8.5" + debug "~4.3.1" + engine.io-parser "~5.0.3" + ws "~8.2.3" + +enhanced-resolve@^5.10.0: + version "5.12.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634" + integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +ent@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA== + +envinfo@^7.7.3: + version "7.8.1" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" + integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== + +es-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +follow-redirects@^1.0.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +format-util@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271" + integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg== + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" + integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3, glob@^7.1.7: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +google-protobuf@3.12.2: + version "3.12.2" + resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53" + integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA== + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +interpret@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" + integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" + integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== + dependencies: + has "^1.0.3" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +isbinaryfile@^4.0.8: + version "4.0.10" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" + integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +karma-chrome-launcher@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz#baca9cc071b1562a1db241827257bfe5cab597ea" + integrity sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ== + dependencies: + which "^1.2.1" + +karma-mocha@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-2.0.1.tgz#4b0254a18dfee71bdbe6188d9a6861bf86b0cd7d" + integrity sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ== + dependencies: + minimist "^1.2.3" + +karma-sourcemap-loader@0.3.8: + version "0.3.8" + resolved "https://registry.yarnpkg.com/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.8.tgz#d4bae72fb7a8397328a62b75013d2df937bdcf9c" + integrity sha512-zorxyAakYZuBcHRJE+vbrK2o2JXLFWK8VVjiT/6P+ltLBUGUvqTEkUiQ119MGdOrK7mrmxXHZF1/pfT6GgIZ6g== + dependencies: + graceful-fs "^4.1.2" + +karma-webpack@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-5.0.0.tgz#2a2c7b80163fe7ffd1010f83f5507f95ef39f840" + integrity sha512-+54i/cd3/piZuP3dr54+NcFeKOPnys5QeM1IY+0SPASwrtHsliXUiCL50iW+K9WWA7RvamC4macvvQ86l3KtaA== + dependencies: + glob "^7.1.3" + minimatch "^3.0.4" + webpack-merge "^4.1.5" + +karma@6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/karma/-/karma-6.4.0.tgz#82652dfecdd853ec227b74ed718a997028a99508" + integrity sha512-s8m7z0IF5g/bS5ONT7wsOavhW4i4aFkzD4u4wgzAQWT4HGUeWI3i21cK2Yz6jndMAeHETp5XuNsRoyGJZXVd4w== + dependencies: + "@colors/colors" "1.5.0" + body-parser "^1.19.0" + braces "^3.0.2" + chokidar "^3.5.1" + connect "^3.7.0" + di "^0.0.1" + dom-serialize "^2.2.1" + glob "^7.1.7" + graceful-fs "^4.2.6" + http-proxy "^1.18.1" + isbinaryfile "^4.0.8" + lodash "^4.17.21" + log4js "^6.4.1" + mime "^2.5.2" + minimatch "^3.0.4" + mkdirp "^0.5.5" + qjobs "^1.2.0" + range-parser "^1.2.1" + rimraf "^3.0.2" + socket.io "^4.4.1" + source-map "^0.6.1" + tmp "^0.2.1" + ua-parser-js "^0.7.30" + yargs "^16.1.1" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash@^4.17.15, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log4js@^6.4.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.7.1.tgz#06e12b1ac915dd1067146ffad8215f666f7d2c51" + integrity sha512-lzbd0Eq1HRdWM2abSD7mk6YIVY0AogGJzb/z+lqzRk+8+XJP+M6L1MS5FUSc3jjGru4dbKjEMJmqlsoYYpuivQ== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + flatted "^3.2.7" + rfdc "^1.3.0" + streamroller "^3.1.3" + +long@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.1.tgz#e27595d0083d103d2fa2c20c7699f8e0c92b897f" + integrity sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@^2.5.2: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.3, minimist@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" + integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== + +mkdirp@^0.5.5: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mocha@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.0.0.tgz#205447d8993ec755335c4b13deba3d3a13c4def9" + integrity sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + nanoid "3.3.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-releases@^2.0.8: + version "2.0.9" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.9.tgz#fe66405285382b0c4ac6bcfbfbe7e8a510650b4d" + integrity sha512-2xfmOrRkGogbTK9R6Leda0DGiXeY3p2NJpy4+gNCffdUvV6mdEJnaDEic1i3Ec2djAo8jWYoJMR5PB0MSMpxUA== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +object-assign@^4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +protobufjs@>=6.11.3: + version "7.2.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.0.tgz#ca6b1ceb9a9efe21186ba96178089ec563011a5e" + integrity sha512-hYCqTDuII4iJ4stZqiuGCSU8xxWl5JeXYpwARGtn/tWcKCAro6h3WQz+xpsNbXW0UYqpmTQFEyFWO0G0Kjt64g== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +qjobs@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" + integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" + integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== + dependencies: + resolve "^1.9.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.9.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +serialize-javascript@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" + integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== + dependencies: + randombytes "^2.1.0" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +socket.io-adapter@~2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6" + integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg== + +socket.io-parser@~4.2.1: + version "4.2.2" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.2.tgz#1dd384019e25b7a3d374877f492ab34f2ad0d206" + integrity sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + +socket.io@^4.4.1: + version "4.5.4" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.4.tgz#a4513f06e87451c17013b8d13fdfaf8da5a86a90" + integrity sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ== + dependencies: + accepts "~1.3.4" + base64id "~2.0.0" + debug "~4.3.2" + engine.io "~6.2.1" + socket.io-adapter "~2.4.0" + socket.io-parser "~4.2.1" + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-loader@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-4.0.0.tgz#bdc6b118bc6c87ee4d8d851f2d4efcc5abdb2ef5" + integrity sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw== + dependencies: + abab "^2.0.6" + iconv-lite "^0.6.3" + source-map-js "^1.0.2" + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +streamroller@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.4.tgz#844a18e795d39c1089a8216e66a1cf1151271df0" + integrity sha512-Ha1Ccw2/N5C/IF8Do6zgNe8F3jQo8MPBnMBGvX0QjNv/I97BcNRzK6/mzOpZHHK7DjMLTI3c7Xw7Y1KvdChkvw== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + fs-extra "^8.1.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@8.1.1, supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.1.3: + version "5.3.6" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz#5590aec31aa3c6f771ce1b1acca60639eab3195c" + integrity sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ== + dependencies: + "@jridgewell/trace-mapping" "^0.3.14" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + terser "^5.14.1" + +terser@^5.14.1: + version "5.16.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.2.tgz#8f495819439e8b5c150e7530fc434a6e70ea18b2" + integrity sha512-JKuM+KvvWVqT7muHVyrwv7FVRPnmHDwF6XwoIxdbF5Witi0vu99RYpxDexpJndXt3jbZZmmWr2/mQa6HvSNdSg== + dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" + commander "^2.20.0" + source-map-support "~0.5.20" + +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@3.9.5: + version "3.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" + integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== + +ua-parser-js@^0.7.30: + version "0.7.33" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532" + integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" + integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +vary@^1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" + integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung== + +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +webpack-cli@4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31" + integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^1.2.0" + "@webpack-cli/info" "^1.5.0" + "@webpack-cli/serve" "^1.7.0" + colorette "^2.0.14" + commander "^7.0.0" + cross-spawn "^7.0.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^2.2.0" + rechoir "^0.7.0" + webpack-merge "^5.7.3" + +webpack-merge@^4.1.5: + version "4.2.2" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" + integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== + dependencies: + lodash "^4.17.15" + +webpack-merge@^5.7.3: + version "5.8.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" + integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@5.74.0: + version "5.74.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.74.0.tgz#02a5dac19a17e0bb47093f2be67c695102a55980" + integrity sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^0.0.51" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.7.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.10.0" + es-module-lexer "^0.9.0" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.4.0" + webpack-sources "^3.2.3" + +which@^1.2.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" + integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== + +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@~8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" + integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0, yargs@^16.1.1: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/kotlin/settings.gradle.kts b/kotlin/settings.gradle.kts new file mode 100644 index 00000000000..481134aa1f2 --- /dev/null +++ b/kotlin/settings.gradle.kts @@ -0,0 +1,27 @@ +@file:Suppress("UnstableApiUsage") + +rootProject.name = "WalletCoreKotlin" + +pluginManagement { + repositories { + google() + mavenCentral() + } +} + +dependencyResolutionManagement { + // Uncomment after https://youtrack.jetbrains.com/issue/KT-55620/ + // repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +includeBuild( + "build-logic", +) + +include( + ":wallet-core-kotlin" +) diff --git a/kotlin/wallet-core-kotlin/.gitignore b/kotlin/wallet-core-kotlin/.gitignore new file mode 100644 index 00000000000..1f22b7e6731 --- /dev/null +++ b/kotlin/wallet-core-kotlin/.gitignore @@ -0,0 +1,3 @@ +/src/**/generated/ +/src/**/proto/ +/src/nativeInterop/ diff --git a/kotlin/wallet-core-kotlin/build.gradle.kts b/kotlin/wallet-core-kotlin/build.gradle.kts new file mode 100644 index 00000000000..08395c50f08 --- /dev/null +++ b/kotlin/wallet-core-kotlin/build.gradle.kts @@ -0,0 +1,130 @@ +@file:Suppress("UnstableApiUsage") + +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput + +plugins { + kotlin("multiplatform") + id("com.android.library") + id("convention.maven-publish") + id("convention.file-generation") +} + +kotlin { + android { + publishLibraryVariants = listOf("release") + } + + val nativeTargets = + listOf( + iosArm64(), + iosSimulatorArm64(), + iosX64(), + ) + + js { + browser { + webpackTask { + output.libraryTarget = KotlinWebpackOutput.Target.COMMONJS2 + } + } + useCommonJs() + } + + sourceSets { + all { + languageSettings { + optIn("kotlin.js.ExperimentalJsExport") + } + } + + val androidMain by getting { + kotlin.srcDir(projectDir.resolve("../../jni/cpp")) + kotlin.srcDir(projectDir.resolve("../../jni/kotlin")) + kotlin.srcDir(projectDir.resolve("src/androidMain/generated")) + } + val commonMain by getting { + kotlin.srcDirs( + projectDir.resolve("src/commonMain/generated"), + projectDir.resolve("src/commonMain/proto"), + ) + + dependencies { + api(libs.wire.runtime) + } + } + val iosArm64Main by getting + val iosSimulatorArm64Main by getting + val iosX64Main by getting + val iosMain by creating { + kotlin.srcDir(projectDir.resolve("src/iosMain/generated")) + + dependsOn(commonMain) + iosArm64Main.dependsOn(this) + iosSimulatorArm64Main.dependsOn(this) + iosX64Main.dependsOn(this) + } + val jsMain by getting { + kotlin.srcDir(projectDir.resolve("src/jsMain/generated")) + + dependencies { + // TODO: Replace with local build + implementation(npm(name = "@trustwallet/wallet-core", version = "3.1.10", generateExternals = false)) + } + } + } + + nativeTargets.forEach { nativeTarget -> + nativeTarget.apply { + val main by compilations.getting + val walletCore by main.cinterops.creating { + includeDirs.allHeaders(rootDir.parentFile.resolve("include/TrustWalletCore")) + } + } + } +} + +android { + namespace = "com.trustwallet.core" + compileSdk = libs.versions.android.sdk.compile.get().toInt() + buildToolsVersion = libs.versions.android.sdk.tools.get() + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + defaultConfig { + minSdk = libs.versions.android.sdk.min.get().toInt() + ndkVersion = libs.versions.android.ndk.get() + + externalNativeBuild { + cmake { + arguments += listOf("-DCMAKE_BUILD_TYPE=Release", "-DKOTLIN=True") + } + } + } + + buildFeatures { + aidl = false + compose = false + buildConfig = false + prefab = false + renderScript = false + resValues = false + shaders = false + viewBinding = false + } + + androidComponents { + beforeVariants { + it.enable = it.name == "release" + } + } + + externalNativeBuild { + cmake { + version = libs.versions.android.cmake.get() + path = rootDir.parentFile.resolve("CMakeLists.txt") + } + } +} diff --git a/kotlin/wallet-core-kotlin/src/androidMain/kotlin/com/trustwallet/core/AnySigner.kt b/kotlin/wallet-core-kotlin/src/androidMain/kotlin/com/trustwallet/core/AnySigner.kt new file mode 100644 index 00000000000..4daa57c663b --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/androidMain/kotlin/com/trustwallet/core/AnySigner.kt @@ -0,0 +1,15 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core + +actual external fun signImpl(input: ByteArray, coin: CoinType): ByteArray + +actual external fun supportsJsonImpl(coin: CoinType): Boolean + +actual external fun signJsonImpl(json: String, key: ByteArray, coin: CoinType): String + +actual external fun planImpl(input: ByteArray, coin: CoinType): ByteArray diff --git a/kotlin/wallet-core-kotlin/src/commonMain/kotlin/com/trustwallet/core/AnySigner.kt b/kotlin/wallet-core-kotlin/src/commonMain/kotlin/com/trustwallet/core/AnySigner.kt new file mode 100644 index 00000000000..df9455e9943 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/commonMain/kotlin/com/trustwallet/core/AnySigner.kt @@ -0,0 +1,32 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core + +import com.squareup.wire.Message +import com.squareup.wire.ProtoAdapter + +object AnySigner { + + fun > sign(input: Message<*, *>, coin: CoinType, adapter: ProtoAdapter): T = + adapter.decode(signImpl(input.encode(), coin)) + + fun supportsJson(coin: CoinType): Boolean = supportsJsonImpl(coin) + + fun signJson(json: String, key: ByteArray, coin: CoinType): String = + signJsonImpl(json, key, coin) + + fun > plan(input: Message<*, *>, coin: CoinType, adapter: ProtoAdapter): T = + adapter.decode(planImpl(input.encode(), coin)) +} + +internal expect fun signImpl(input: ByteArray, coin: CoinType): ByteArray + +internal expect fun supportsJsonImpl(coin: CoinType): Boolean + +internal expect fun signJsonImpl(json: String, key: ByteArray, coin: CoinType): String + +internal expect fun planImpl(input: ByteArray, coin: CoinType): ByteArray diff --git a/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/AnySigner.kt b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/AnySigner.kt new file mode 100644 index 00000000000..ad6aa3e3888 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/AnySigner.kt @@ -0,0 +1,19 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core + +actual fun signImpl(input: ByteArray, coin: CoinType): ByteArray = + TWAnySignerSign(input.toTwData(), coin.value)!!.readTwBytes()!! + +actual fun supportsJsonImpl(coin: CoinType): Boolean = + TWAnySignerSupportsJSON(coin.value) + +actual fun signJsonImpl(json: String, key: ByteArray, coin: CoinType): String = + TWAnySignerSignJSON(json.toTwString(), key.toTwData(), coin.value).fromTwString()!! + +actual fun planImpl(input: ByteArray, coin: CoinType): ByteArray = + TWAnySignerPlan(input.toTwData(), coin.value)?.readTwBytes()!! diff --git a/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/ByteArrayExt.kt b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/ByteArrayExt.kt new file mode 100644 index 00000000000..8498cb26061 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/ByteArrayExt.kt @@ -0,0 +1,18 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core + +import kotlinx.cinterop.COpaquePointer +import kotlinx.cinterop.readBytes +import kotlinx.cinterop.toCValues + +internal fun COpaquePointer?.readTwBytes(): ByteArray? = + TWDataBytes(this)?.readBytes(TWDataSize(this).toInt()) + +@OptIn(ExperimentalUnsignedTypes::class) +internal fun ByteArray?.toTwData(): COpaquePointer? = + TWDataCreateWithBytes(this?.toUByteArray()?.toCValues(), this?.size?.toULong() ?: 0u) diff --git a/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/StringExt.kt b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/StringExt.kt new file mode 100644 index 00000000000..2c23168563d --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/StringExt.kt @@ -0,0 +1,17 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core + +import kotlinx.cinterop.COpaquePointer +import kotlinx.cinterop.CValuesRef +import kotlinx.cinterop.toKString + +internal fun String?.toTwString(): COpaquePointer? = + TWStringCreateWithUTF8Bytes(this) + +internal fun CValuesRef<*>?.fromTwString(): String? = + TWStringUTF8Bytes(this)?.toKString() diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/WalletCore.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/WalletCore.kt new file mode 100644 index 00000000000..61bdabba2bb --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/WalletCore.kt @@ -0,0 +1,27 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import kotlin.js.Promise + +@JsExport +@JsName("WalletCoreKotlin") +object WalletCore { + + internal var Instance: dynamic = null + + fun init(): Promise = + WalletCoreExports.initWasm() + .then { walletCore: dynamic -> + Instance = walletCore + walletCore + } +} + +@JsModule("@trustwallet/wallet-core") +@JsNonModule +internal external object WalletCoreExports { + fun initWasm(): Promise +} diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/AnySigner.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/AnySigner.kt new file mode 100644 index 00000000000..7f4260201c7 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/AnySigner.kt @@ -0,0 +1,25 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core + +import WalletCore + +internal actual fun signImpl(input: ByteArray, coin: CoinType): ByteArray = + WalletCore.Instance.AnySigner.sign(input.toUInt8Array(), coin._value) + .unsafeCast() + .toByteArray() + +internal actual fun supportsJsonImpl(coin: CoinType): Boolean = + WalletCore.Instance.AnySigner.supportsJSON(coin._value) as Boolean + +internal actual fun signJsonImpl(json: String, key: ByteArray, coin: CoinType): String = + TODO() + +internal actual fun planImpl(input: ByteArray, coin: CoinType): ByteArray = + WalletCore.Instance.AnySigner.plan(input.toUInt8Array(), coin._value) + .unsafeCast() + .toByteArray() diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/UInt8Array.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/UInt8Array.kt new file mode 100644 index 00000000000..001d22c0912 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/UInt8Array.kt @@ -0,0 +1,17 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core + +import org.khronos.webgl.get + +internal typealias UInt8Array = org.khronos.webgl.Uint8Array + +internal fun UInt8Array.toByteArray(): ByteArray = + ByteArray(length, ::get) + +internal fun ByteArray.toUInt8Array(): UInt8Array = + UInt8Array(toTypedArray()) diff --git a/tools/install-kotlin-dependencies b/tools/install-kotlin-dependencies new file mode 100755 index 00000000000..e837297f31e --- /dev/null +++ b/tools/install-kotlin-dependencies @@ -0,0 +1,7 @@ +#!/bin/bash + +set -e + +"$ANDROID_HOME"/cmdline-tools/latest/bin/sdkmanager --verbose "cmake;3.22.1" "ndk;25.2.9519653" + +yes | "$ANDROID_HOME"/cmdline-tools/latest/bin/sdkmanager --licenses diff --git a/tools/kotlin-build b/tools/kotlin-build new file mode 100755 index 00000000000..4eb14383f65 --- /dev/null +++ b/tools/kotlin-build @@ -0,0 +1,8 @@ +#!/bin/bash + +set -e + +pushd kotlin +./gradlew :wallet-core-kotlin:generateFiles +./gradlew :wallet-core-kotlin:assemble +popd diff --git a/tools/kotlin-release b/tools/kotlin-release new file mode 100755 index 00000000000..0eadf3fe30c --- /dev/null +++ b/tools/kotlin-release @@ -0,0 +1,17 @@ +#!/bin/bash + +set -e + +source $(dirname $0)/library +version=$(wc_read_version) + +echo "Building $version" + +export ANDROID_HOME="$HOME/Library/Android/sdk" + +pushd kotlin +./gradlew :wallet-core-kotlin:generateFiles +./gradlew :wallet-core-kotlin:assemble :wallet-core-kotlin:publish -Pversion="$version" +popd + +echo "Kotlin build uploaded" From 7e81d2f9483d8699bbd44652715814209968e8b7 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 9 Feb 2023 19:57:43 +0100 Subject: [PATCH 192/497] [CoinType]: Add cointype extension for wasm (#2915) --- wasm/src/CoinTypeExtension.cpp | 114 ++++++++++++++++++++++++++++++++ wasm/src/CoinTypeExtension.d.ts | 22 ++++++ wasm/tests/CoinType.test.ts | 14 +++- 3 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 wasm/src/CoinTypeExtension.cpp create mode 100644 wasm/src/CoinTypeExtension.d.ts diff --git a/wasm/src/CoinTypeExtension.cpp b/wasm/src/CoinTypeExtension.cpp new file mode 100644 index 00000000000..e6e1f0a5e27 --- /dev/null +++ b/wasm/src/CoinTypeExtension.cpp @@ -0,0 +1,114 @@ +#include +#include "WasmString.h" +#include "generated/PrivateKey.h" +#include + +using namespace emscripten; + +namespace TW::Wasm { + class CoinTypeExtension { + public: + TWCoinType mValue; + CoinTypeExtension(TWCoinType value): mValue(value) {} + + auto value() { + return mValue; + } + + auto blockchain() { + return TWCoinTypeBlockchain(mValue); + } + + auto purpose() { + return TWCoinTypePurpose(mValue); + } + + auto curve() { + return TWCoinTypeCurve(mValue); + } + + auto xpubVersion() { + return TWCoinTypeXpubVersion(mValue); + } + + auto xprvVersion() { + return TWCoinTypeXpubVersion(mValue); + } + + auto validate(const std::string& address) { + return TWCoinTypeValidate(mValue, &address); + } + + auto derivationPath() { + return TWStringToStd(TWCoinTypeDerivationPath(mValue)); + } + + auto derivationPathWithDerivation(TWDerivation derivation) { + return TWStringToStd(TWCoinTypeDerivationPathWithDerivation(mValue, derivation)); + } + + auto deriveAddress(WasmPrivateKey* privateKey) { + return TWStringToStd(TWCoinTypeDeriveAddress(mValue, privateKey->instance)); + } + + auto deriveAddressFromPublicKey(WasmPublicKey* publicKey) { + return TWStringToStd(TWCoinTypeDeriveAddressFromPublicKey(mValue, publicKey->instance)); + } + + auto HRP() { + return TWCoinTypeHRP(mValue); + } + + auto P2pkhPrefix() { + return TWCoinTypeP2pkhPrefix(mValue); + } + + auto P2shPrefix() { + return TWCoinTypeP2shPrefix(mValue); + } + + auto staticPrefix() { + return TWCoinTypeStaticPrefix(mValue); + } + + auto chainID() { + return TWStringToStd(TWCoinTypeChainId(mValue)); + } + + auto slip44ID() { + return TWCoinTypeSlip44Id(mValue); + } + + auto SS58Prefix() { + return TWCoinTypeSS58Prefix(mValue); + } + + auto publicKeyType() { + return TWCoinTypePublicKeyType(mValue); + } + }; + + EMSCRIPTEN_BINDINGS(Wasm_CoinTypeExtension) { + class_("CoinTypeExtension") + .constructor() + .function("blockchain", &CoinTypeExtension::blockchain) + .function("purpose", &CoinTypeExtension::purpose) + .function("curve", &CoinTypeExtension::curve) + .function("xpubVersion", &CoinTypeExtension::xpubVersion) + .function("xprvVersion", &CoinTypeExtension::xprvVersion) + .function("validate", &CoinTypeExtension::validate) + .function("derivationPath", &CoinTypeExtension::derivationPath) + .function("derivationPathWithDerivation", &CoinTypeExtension::derivationPathWithDerivation) + .function("deriveAddress", &CoinTypeExtension::deriveAddress, allow_raw_pointers()) + .function("deriveAddressFromPublicKey", &CoinTypeExtension::deriveAddressFromPublicKey, allow_raw_pointers()) + .function("hrp", &CoinTypeExtension::HRP) + .function("P2pkhPrefix", &CoinTypeExtension::P2pkhPrefix) + .function("P2shPrefix", &CoinTypeExtension::P2shPrefix) + .function("staticPrefix", &CoinTypeExtension::staticPrefix) + .function("chainID", &CoinTypeExtension::chainID) + .function("slip44ID", &CoinTypeExtension::slip44ID) + .function("SS58Prefix", &CoinTypeExtension::SS58Prefix) + .function("publicKeyType", &CoinTypeExtension::publicKeyType) + .function("value", &CoinTypeExtension::value); + } +} diff --git a/wasm/src/CoinTypeExtension.d.ts b/wasm/src/CoinTypeExtension.d.ts new file mode 100644 index 00000000000..f0169dffe9e --- /dev/null +++ b/wasm/src/CoinTypeExtension.d.ts @@ -0,0 +1,22 @@ +export class CoinTypeExtension { + constructor(CoinType) + value(): CoinType + blockchain(): Blockchain + purpose(): Purpose + curve(): Curve + xpubVersion(): HDVersion + xprvVersion(): HDVersion + validate(address: string): boolean + derivationPath(): string + derivationPathWithDerivation(derivation: Derivation): string + deriveAddress(privateKey: PrivateKey): string + deriveAddressFromPublicKey(publicKey: PublicKey): string + hrp(): HRP + P2pkhPrefix(): number + P2shPrefix(): number + staticPrefix(): number + chainID(): string + slip44ID(): number + SS58Prefix(): number + publicKeyType(): PublicKeyType +} diff --git a/wasm/tests/CoinType.test.ts b/wasm/tests/CoinType.test.ts index d18fdf4c60e..416949d944c 100644 --- a/wasm/tests/CoinType.test.ts +++ b/wasm/tests/CoinType.test.ts @@ -9,7 +9,7 @@ import { assert } from "chai"; describe("CoinType", () => { it("test raw value", () => { - const { CoinType } = globalThis.core; + const { CoinType, CoinTypeExtension, Blockchain, Purpose, Curve, Derivation, PrivateKey, HexCoding } = globalThis.core; assert.equal(CoinType.bitcoin.value, 0); assert.equal(CoinType.litecoin.value, 2); @@ -18,5 +18,17 @@ describe("CoinType", () => { assert.equal(CoinType.binance.value, 714); assert.equal(CoinType.cosmos.value, 118); assert.equal(CoinType.solana.value, 501); + let val = new CoinTypeExtension(CoinType.solana); + assert.equal(val.blockchain(), Blockchain.solana); + assert.equal(val.value(), CoinType.solana); + assert.equal(val.purpose(), Purpose.bip44); + assert.equal(val.curve(), Curve.ed25519); + assert.isTrue(val.validate("Bxp8yhH9zNwxyE4UqxP7a7hgJ5xTZfxNNft7YJJ2VRjT")) + assert.equal(val.derivationPath(), "m/44'/501'/0'"); + assert.equal(val.derivationPathWithDerivation(Derivation.solanaSolana), "m/44'/501'/0'/0'"); + let data = HexCoding.decode("8778cc93c6596387e751d2dc693bbd93e434bd233bc5b68a826c56131821cb63") + const key = PrivateKey.createWithData(data); + let addr = val.deriveAddress(key); + assert.equal(addr, "7v91N7iZ9mNicL8WfG6cgSCKyRXydQjLh6UYBWwm6y1Q") }); }); From 3d2c86d200ea4402262fdce44032c10a88ec7909 Mon Sep 17 00:00:00 2001 From: Maxim Pestryakov Date: Fri, 10 Feb 2023 18:12:14 +0800 Subject: [PATCH 193/497] [WASM, Kotlin]: Fixed methods and properties in enums (#2919) --- codegen/lib/kotlin_helper.rb | 6 ++ codegen/lib/templates/kotlin/js_enum.erb | 4 +- kotlin/kotlin-js-store/yarn.lock | 103 +------------------ kotlin/wallet-core-kotlin/build.gradle.kts | 5 - wasm/package.json | 4 +- wasm/src/BitcoinSigHashTypeExt.cpp | 29 ++++++ wasm/src/BitcoinSigHashTypeExt.h | 22 ++++ wasm/src/CoinTypeExt.cpp | 97 ++++++++++++++++++ wasm/src/CoinTypeExt.h | 48 +++++++++ wasm/src/CoinTypeExtension.cpp | 114 --------------------- wasm/src/CoinTypeExtension.d.ts | 22 ---- wasm/src/HDVersionExt.cpp | 29 ++++++ wasm/src/HDVersionExt.h | 22 ++++ wasm/src/enum-ext.d.ts | 36 +++++++ wasm/tests/BitcoinSigHashType.test.ts | 30 ++++++ wasm/tests/CoinType.test.ts | 20 ++-- wasm/tests/HDVersion.test.ts | 50 +++++++++ 17 files changed, 383 insertions(+), 258 deletions(-) create mode 100644 wasm/src/BitcoinSigHashTypeExt.cpp create mode 100644 wasm/src/BitcoinSigHashTypeExt.h create mode 100644 wasm/src/CoinTypeExt.cpp create mode 100644 wasm/src/CoinTypeExt.h delete mode 100644 wasm/src/CoinTypeExtension.cpp delete mode 100644 wasm/src/CoinTypeExtension.d.ts create mode 100644 wasm/src/HDVersionExt.cpp create mode 100644 wasm/src/HDVersionExt.h create mode 100644 wasm/src/enum-ext.d.ts create mode 100644 wasm/tests/BitcoinSigHashType.test.ts create mode 100644 wasm/tests/HDVersion.test.ts diff --git a/codegen/lib/kotlin_helper.rb b/codegen/lib/kotlin_helper.rb index bd40ac74d97..0d072ad3637 100644 --- a/codegen/lib/kotlin_helper.rb +++ b/codegen/lib/kotlin_helper.rb @@ -77,6 +77,12 @@ def self.convert_calling_type_js(t) case t.name when :data "#{if t.is_nullable then '?' else '' end}.toUInt8Array()" + when :uint64 + ".toUInt()" + when :int64 + ".toInt()" + when :size + ".toUInt()" else if t.is_enum "#{if t.is_nullable then '?' else '' end}._value" diff --git a/codegen/lib/templates/kotlin/js_enum.erb b/codegen/lib/templates/kotlin/js_enum.erb index d54ffcf6630..4c5895d77ac 100644 --- a/codegen/lib/templates/kotlin/js_enum.erb +++ b/codegen/lib/templates/kotlin/js_enum.erb @@ -12,14 +12,14 @@ actual enum class <%= entity.name %>( <%- entity.properties.each do |property| -%> actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> - get() = <%= KotlinHelper.convert_calling_return_type_js(property.return_type, "_value.#{WasmCppHelper.function_name(entity: entity, function: property)}()") %> + get() = <%= KotlinHelper.convert_calling_return_type_js(property.return_type, "WalletCore.Instance.#{entity.name}Ext.#{WasmCppHelper.function_name(entity: entity, function: property)}(_value)") %> <%- end -%> <%# Method declarations -%> <%- entity.methods.each do |method| -%> <%- next if method.name.start_with?('Delete') -%> actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> = - <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "_value.#{WasmCppHelper.function_name(entity: entity, function: method)}(#{KotlinHelper.calling_parameters_js(method.parameters.drop(1))})") %> + <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "WalletCore.Instance.#{entity.name}Ext.#{WasmCppHelper.function_name(entity: entity, function: method)}(_value#{', ' if not method.parameters.one?}#{KotlinHelper.calling_parameters_js(method.parameters.drop(1))})") %> <%- end -%> <%# Value -%> <% if entity.cases.any? { |e| !e.value.nil? } -%> diff --git a/kotlin/kotlin-js-store/yarn.lock b/kotlin/kotlin-js-store/yarn.lock index 537d261cff0..f2fd767d23d 100644 --- a/kotlin/kotlin-js-store/yarn.lock +++ b/kotlin/kotlin-js-store/yarn.lock @@ -52,71 +52,11 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" - integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== - -"@protobufjs/base64@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" - integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== - -"@protobufjs/codegen@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" - integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== - -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" - integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== - -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" - integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== - dependencies: - "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" - -"@protobufjs/float@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" - integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== - -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" - integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== - -"@protobufjs/path@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" - integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== - -"@protobufjs/pool@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" - integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== - -"@protobufjs/utf8@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" - integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== - "@socket.io/component-emitter@~3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== -"@trustwallet/wallet-core@3.1.10": - version "3.1.10" - resolved "https://registry.yarnpkg.com/@trustwallet/wallet-core/-/wallet-core-3.1.10.tgz#3af4d0021a91f61faea7d3401d4e04197a843a9b" - integrity sha512-4/Du55HQLcNrJsBXWqUlk+5G7TCan1CfaOhRTxfXad1txWMtTj75kkYnbfST5Oi2DaKbuH86FF+yYroSdgoEiw== - dependencies: - protobufjs ">=6.11.3" - "@types/cookie@^0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" @@ -160,7 +100,7 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== -"@types/node@*", "@types/node@>=10.0.0", "@types/node@>=13.7.0": +"@types/node@*", "@types/node@>=10.0.0": version "18.11.18" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== @@ -658,14 +598,6 @@ dom-serialize@^2.2.1: extend "^3.0.0" void-elements "^2.0.0" -dukat@0.5.8-rc.4: - version "0.5.8-rc.4" - resolved "https://registry.yarnpkg.com/dukat/-/dukat-0.5.8-rc.4.tgz#90384dcb50b14c26f0e99dae92b2dea44f5fce21" - integrity sha512-ZnMt6DGBjlVgK2uQamXfd7uP/AxH7RqI0BL9GLrrJb2gKdDxvJChWy+M9AQEaL+7/6TmxzJxFOsRiInY9oGWTA== - dependencies: - google-protobuf "3.12.2" - typescript "3.9.5" - ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -930,11 +862,6 @@ glob@^7.1.3, glob@^7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" -google-protobuf@3.12.2: - version "3.12.2" - resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53" - integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA== - graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -1231,11 +1158,6 @@ log4js@^6.4.1: rfdc "^1.3.0" streamroller "^3.1.3" -long@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/long/-/long-5.2.1.tgz#e27595d0083d103d2fa2c20c7699f8e0c92b897f" - integrity sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A== - media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -1463,24 +1385,6 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -protobufjs@>=6.11.3: - version "7.2.0" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.0.tgz#ca6b1ceb9a9efe21186ba96178089ec563011a5e" - integrity sha512-hYCqTDuII4iJ4stZqiuGCSU8xxWl5JeXYpwARGtn/tWcKCAro6h3WQz+xpsNbXW0UYqpmTQFEyFWO0G0Kjt64g== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/node" ">=13.7.0" - long "^5.0.0" - punycode@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" @@ -1807,11 +1711,6 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typescript@3.9.5: - version "3.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" - integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== - ua-parser-js@^0.7.30: version "0.7.33" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532" diff --git a/kotlin/wallet-core-kotlin/build.gradle.kts b/kotlin/wallet-core-kotlin/build.gradle.kts index 08395c50f08..6ceb9a8cbad 100644 --- a/kotlin/wallet-core-kotlin/build.gradle.kts +++ b/kotlin/wallet-core-kotlin/build.gradle.kts @@ -65,11 +65,6 @@ kotlin { } val jsMain by getting { kotlin.srcDir(projectDir.resolve("src/jsMain/generated")) - - dependencies { - // TODO: Replace with local build - implementation(npm(name = "@trustwallet/wallet-core", version = "3.1.10", generateExternals = false)) - } } } diff --git a/wasm/package.json b/wasm/package.json index eafc3845ed4..996f10ac35e 100644 --- a/wasm/package.json +++ b/wasm/package.json @@ -11,8 +11,8 @@ "codegen:js-browser": "pbjs -t static-module '../src/proto/*.proto' -w closure --no-delimited --force-long -o ../samples/wasm/core_proto.js", "codegen:ts": "pbts -o generated/core_proto.d.ts generated/core_proto.js", "clean": "rm -rf dist generated && mkdir -p dist/generated generated", - "build": "npm run clean && npm run generate && cp -R generated lib dist && tsc && cp src/wallet-core.d.ts dist/src", - "build-and-test": "npm run copy:wasm && npm run build && npm test", + "build": "npm run copy:wasm && npm run clean && npm run generate && cp -R generated lib dist && tsc && cp src/wallet-core.d.ts dist/src", + "build-and-test": "npm run build && npm test", "copy:wasm": "mkdir -p lib && cp ../wasm-build/wasm/wallet-core.* lib", "copy:wasm-sample": "cp ../wasm-build/wasm/wallet-core.* ../samples/wasm/" }, diff --git a/wasm/src/BitcoinSigHashTypeExt.cpp b/wasm/src/BitcoinSigHashTypeExt.cpp new file mode 100644 index 00000000000..c8c1af417cd --- /dev/null +++ b/wasm/src/BitcoinSigHashTypeExt.cpp @@ -0,0 +1,29 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include + +#include + +using namespace emscripten; + +#include "BitcoinSigHashTypeExt.h" + +namespace TW::Wasm { + + auto BitcoinSigHashTypeExt::isSingle(TWBitcoinSigHashType type) { + return TWBitcoinSigHashTypeIsSingle(type); + } + auto BitcoinSigHashTypeExt::isNone(TWBitcoinSigHashType type) { + return TWBitcoinSigHashTypeIsNone(type); + } + + EMSCRIPTEN_BINDINGS(Wasm_BitcoinSigHashTypeExt) { + class_("BitcoinSigHashTypeExt") + .class_function("isSingle", &BitcoinSigHashTypeExt::isSingle) + .class_function("isNone", &BitcoinSigHashTypeExt::isNone); + }; +} diff --git a/wasm/src/BitcoinSigHashTypeExt.h b/wasm/src/BitcoinSigHashTypeExt.h new file mode 100644 index 00000000000..3d4f4c1c547 --- /dev/null +++ b/wasm/src/BitcoinSigHashTypeExt.h @@ -0,0 +1,22 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include + +#include + +using namespace emscripten; + +namespace TW::Wasm { + + class BitcoinSigHashTypeExt { + public: + static auto isSingle(TWBitcoinSigHashType type); + static auto isNone(TWBitcoinSigHashType type); + }; +} diff --git a/wasm/src/CoinTypeExt.cpp b/wasm/src/CoinTypeExt.cpp new file mode 100644 index 00000000000..25b63214826 --- /dev/null +++ b/wasm/src/CoinTypeExt.cpp @@ -0,0 +1,97 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include "WasmString.h" + +#include "generated/PrivateKey.h" +#include "generated/PublicKey.h" + +#include + +using namespace emscripten; + +#include "CoinTypeExt.h" + +namespace TW::Wasm { + + auto CoinTypeExt::blockchain(TWCoinType coin) { + return TWCoinTypeBlockchain(coin); + } + auto CoinTypeExt::purpose(TWCoinType coin) { + return TWCoinTypePurpose(coin); + } + auto CoinTypeExt::curve(TWCoinType coin) { + return TWCoinTypeCurve(coin); + } + auto CoinTypeExt::xpubVersion(TWCoinType coin) { + return TWCoinTypeXpubVersion(coin); + } + auto CoinTypeExt::xprvVersion(TWCoinType coin) { + return TWCoinTypeXprvVersion(coin); + } + auto CoinTypeExt::hrp(TWCoinType coin) { + return TWCoinTypeHRP(coin); + } + auto CoinTypeExt::p2pkhPrefix(TWCoinType coin) { + return TWCoinTypeP2pkhPrefix(coin); + } + auto CoinTypeExt::p2shPrefix(TWCoinType coin) { + return TWCoinTypeP2shPrefix(coin); + } + auto CoinTypeExt::staticPrefix(TWCoinType coin) { + return TWCoinTypeStaticPrefix(coin); + } + auto CoinTypeExt::chainId(TWCoinType coin) { + return TWStringToStd(TWCoinTypeChainId(coin)); + } + auto CoinTypeExt::slip44Id(TWCoinType coin) { + return TWCoinTypeSlip44Id(coin); + } + auto CoinTypeExt::ss58Prefix(TWCoinType coin) { + return TWCoinTypeSS58Prefix(coin); + } + auto CoinTypeExt::publicKeyType(TWCoinType coin) { + return TWCoinTypePublicKeyType(coin); + } + auto CoinTypeExt::validate(TWCoinType coin, const std::string& address) { + return TWCoinTypeValidate(coin, &address); + } + auto CoinTypeExt::derivationPath(TWCoinType coin) { + return TWStringToStd(TWCoinTypeDerivationPath(coin)); + } + auto CoinTypeExt::derivationPathWithDerivation(TWCoinType coin, TWDerivation derivation) { + return TWStringToStd(TWCoinTypeDerivationPathWithDerivation(coin, derivation)); + } + auto CoinTypeExt::deriveAddress(TWCoinType coin, WasmPrivateKey* privateKey) { + return TWStringToStd(TWCoinTypeDeriveAddress(coin, privateKey->instance)); + } + auto CoinTypeExt::deriveAddressFromPublicKey(TWCoinType coin, WasmPublicKey* publicKey) { + return TWStringToStd(TWCoinTypeDeriveAddressFromPublicKey(coin, publicKey->instance)); + } + + EMSCRIPTEN_BINDINGS(Wasm_CoinTypeExt) { + class_("CoinTypeExt") + .class_function("blockchain", &CoinTypeExt::blockchain) + .class_function("purpose", &CoinTypeExt::purpose) + .class_function("curve", &CoinTypeExt::curve) + .class_function("xpubVersion", &CoinTypeExt::xpubVersion) + .class_function("xprvVersion", &CoinTypeExt::xprvVersion) + .class_function("hrp", &CoinTypeExt::hrp) + .class_function("p2pkhPrefix", &CoinTypeExt::p2pkhPrefix) + .class_function("p2shPrefix", &CoinTypeExt::p2shPrefix) + .class_function("staticPrefix", &CoinTypeExt::staticPrefix) + .class_function("chainId", &CoinTypeExt::chainId) + .class_function("slip44Id", &CoinTypeExt::slip44Id) + .class_function("ss58Prefix", &CoinTypeExt::ss58Prefix) + .class_function("publicKeyType", &CoinTypeExt::publicKeyType) + .class_function("validate", &CoinTypeExt::validate) + .class_function("derivationPath", &CoinTypeExt::derivationPath) + .class_function("derivationPathWithDerivation", &CoinTypeExt::derivationPathWithDerivation) + .class_function("deriveAddress", &CoinTypeExt::deriveAddress, allow_raw_pointers()) + .class_function("deriveAddressFromPublicKey", &CoinTypeExt::deriveAddressFromPublicKey, allow_raw_pointers()); + }; +} diff --git a/wasm/src/CoinTypeExt.h b/wasm/src/CoinTypeExt.h new file mode 100644 index 00000000000..66c62410655 --- /dev/null +++ b/wasm/src/CoinTypeExt.h @@ -0,0 +1,48 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include +#include + +#include "generated/PrivateKey.h" +#include "generated/PublicKey.h" + +#include + +using namespace emscripten; + +#include + +#include "WasmString.h" +#include "WasmData.h" + +namespace TW::Wasm { + + class CoinTypeExt { + public: + static auto blockchain(TWCoinType coin); + static auto purpose(TWCoinType coin); + static auto curve(TWCoinType coin); + static auto xpubVersion(TWCoinType coin); + static auto xprvVersion(TWCoinType coin); + static auto hrp(TWCoinType coin); + static auto p2pkhPrefix(TWCoinType coin); + static auto p2shPrefix(TWCoinType coin); + static auto staticPrefix(TWCoinType coin); + static auto chainId(TWCoinType coin); + static auto slip44Id(TWCoinType coin); + static auto ss58Prefix(TWCoinType coin); + static auto publicKeyType(TWCoinType coin); + static auto validate(TWCoinType coin, const std::string& address); + static auto derivationPath(TWCoinType coin); + static auto derivationPathWithDerivation(TWCoinType coin, TWDerivation derivation); + static auto deriveAddress(TWCoinType coin, WasmPrivateKey* privateKey); + static auto deriveAddressFromPublicKey(TWCoinType coin, WasmPublicKey* publicKey); + }; +} diff --git a/wasm/src/CoinTypeExtension.cpp b/wasm/src/CoinTypeExtension.cpp deleted file mode 100644 index e6e1f0a5e27..00000000000 --- a/wasm/src/CoinTypeExtension.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include -#include "WasmString.h" -#include "generated/PrivateKey.h" -#include - -using namespace emscripten; - -namespace TW::Wasm { - class CoinTypeExtension { - public: - TWCoinType mValue; - CoinTypeExtension(TWCoinType value): mValue(value) {} - - auto value() { - return mValue; - } - - auto blockchain() { - return TWCoinTypeBlockchain(mValue); - } - - auto purpose() { - return TWCoinTypePurpose(mValue); - } - - auto curve() { - return TWCoinTypeCurve(mValue); - } - - auto xpubVersion() { - return TWCoinTypeXpubVersion(mValue); - } - - auto xprvVersion() { - return TWCoinTypeXpubVersion(mValue); - } - - auto validate(const std::string& address) { - return TWCoinTypeValidate(mValue, &address); - } - - auto derivationPath() { - return TWStringToStd(TWCoinTypeDerivationPath(mValue)); - } - - auto derivationPathWithDerivation(TWDerivation derivation) { - return TWStringToStd(TWCoinTypeDerivationPathWithDerivation(mValue, derivation)); - } - - auto deriveAddress(WasmPrivateKey* privateKey) { - return TWStringToStd(TWCoinTypeDeriveAddress(mValue, privateKey->instance)); - } - - auto deriveAddressFromPublicKey(WasmPublicKey* publicKey) { - return TWStringToStd(TWCoinTypeDeriveAddressFromPublicKey(mValue, publicKey->instance)); - } - - auto HRP() { - return TWCoinTypeHRP(mValue); - } - - auto P2pkhPrefix() { - return TWCoinTypeP2pkhPrefix(mValue); - } - - auto P2shPrefix() { - return TWCoinTypeP2shPrefix(mValue); - } - - auto staticPrefix() { - return TWCoinTypeStaticPrefix(mValue); - } - - auto chainID() { - return TWStringToStd(TWCoinTypeChainId(mValue)); - } - - auto slip44ID() { - return TWCoinTypeSlip44Id(mValue); - } - - auto SS58Prefix() { - return TWCoinTypeSS58Prefix(mValue); - } - - auto publicKeyType() { - return TWCoinTypePublicKeyType(mValue); - } - }; - - EMSCRIPTEN_BINDINGS(Wasm_CoinTypeExtension) { - class_("CoinTypeExtension") - .constructor() - .function("blockchain", &CoinTypeExtension::blockchain) - .function("purpose", &CoinTypeExtension::purpose) - .function("curve", &CoinTypeExtension::curve) - .function("xpubVersion", &CoinTypeExtension::xpubVersion) - .function("xprvVersion", &CoinTypeExtension::xprvVersion) - .function("validate", &CoinTypeExtension::validate) - .function("derivationPath", &CoinTypeExtension::derivationPath) - .function("derivationPathWithDerivation", &CoinTypeExtension::derivationPathWithDerivation) - .function("deriveAddress", &CoinTypeExtension::deriveAddress, allow_raw_pointers()) - .function("deriveAddressFromPublicKey", &CoinTypeExtension::deriveAddressFromPublicKey, allow_raw_pointers()) - .function("hrp", &CoinTypeExtension::HRP) - .function("P2pkhPrefix", &CoinTypeExtension::P2pkhPrefix) - .function("P2shPrefix", &CoinTypeExtension::P2shPrefix) - .function("staticPrefix", &CoinTypeExtension::staticPrefix) - .function("chainID", &CoinTypeExtension::chainID) - .function("slip44ID", &CoinTypeExtension::slip44ID) - .function("SS58Prefix", &CoinTypeExtension::SS58Prefix) - .function("publicKeyType", &CoinTypeExtension::publicKeyType) - .function("value", &CoinTypeExtension::value); - } -} diff --git a/wasm/src/CoinTypeExtension.d.ts b/wasm/src/CoinTypeExtension.d.ts deleted file mode 100644 index f0169dffe9e..00000000000 --- a/wasm/src/CoinTypeExtension.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -export class CoinTypeExtension { - constructor(CoinType) - value(): CoinType - blockchain(): Blockchain - purpose(): Purpose - curve(): Curve - xpubVersion(): HDVersion - xprvVersion(): HDVersion - validate(address: string): boolean - derivationPath(): string - derivationPathWithDerivation(derivation: Derivation): string - deriveAddress(privateKey: PrivateKey): string - deriveAddressFromPublicKey(publicKey: PublicKey): string - hrp(): HRP - P2pkhPrefix(): number - P2shPrefix(): number - staticPrefix(): number - chainID(): string - slip44ID(): number - SS58Prefix(): number - publicKeyType(): PublicKeyType -} diff --git a/wasm/src/HDVersionExt.cpp b/wasm/src/HDVersionExt.cpp new file mode 100644 index 00000000000..2434ef77f3a --- /dev/null +++ b/wasm/src/HDVersionExt.cpp @@ -0,0 +1,29 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include + +#include + +using namespace emscripten; + +#include "HDVersionExt.h" + +namespace TW::Wasm { + + auto HDVersionExt::isPublic(TWHDVersion version) { + return TWHDVersionIsPublic(version); + } + auto HDVersionExt::isPrivate(TWHDVersion version) { + return TWHDVersionIsPrivate(version); + } + + EMSCRIPTEN_BINDINGS(Wasm_HDVersionExt) { + class_("HDVersionExt") + .class_function("isPublic", &HDVersionExt::isPublic) + .class_function("isPrivate", &HDVersionExt::isPrivate); + }; +} diff --git a/wasm/src/HDVersionExt.h b/wasm/src/HDVersionExt.h new file mode 100644 index 00000000000..18d460f68bd --- /dev/null +++ b/wasm/src/HDVersionExt.h @@ -0,0 +1,22 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include + +#include + +using namespace emscripten; + +namespace TW::Wasm { + + class HDVersionExt { + public: + static auto isPublic(TWHDVersion version); + static auto isPrivate(TWHDVersion version); + }; +} diff --git a/wasm/src/enum-ext.d.ts b/wasm/src/enum-ext.d.ts new file mode 100644 index 00000000000..83c302e540e --- /dev/null +++ b/wasm/src/enum-ext.d.ts @@ -0,0 +1,36 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +export class BitcoinSigHashTypeExt { + static isSingle(type: BitcoinSigHashType): boolean; + static isNone(type: BitcoinSigHashType): boolean; +} + +export class CoinTypeExt { + static blockchain(coin: CoinType): Blockchain; + static purpose(coin: CoinType): Purpose; + static curve(coin: CoinType): Curve; + static xpubVersion(coin: CoinType): HDVersion; + static xprvVersion(coin: CoinType): HDVersion; + static hrp(coin: CoinType): HRP; + static p2pkhPrefix(coin: CoinType): number; + static p2shPrefix(coin: CoinType): number; + static staticPrefix(coin: CoinType): number; + static chainId(coin: CoinType): string; + static slip44Id(coin: CoinType): number; + static ss58Prefix(coin: CoinType): number; + static publicKeyType(coin: CoinType): PublicKeyType; + static validate(coin: CoinType, address: string): boolean; + static derivationPath(coin: CoinType): string; + static derivationPathWithDerivation(coin: CoinType, derivation: Derivation): string; + static deriveAddress(coin: CoinType, privateKey: PrivateKey): string; + static deriveAddressFromPublicKey(coin: CoinType, publicKey: PublicKey): string; +} + +export class HDVersionExt { + static isPublic(version: HDVersion): boolean; + static isPrivate(version: HDVersion): boolean; +} diff --git a/wasm/tests/BitcoinSigHashType.test.ts b/wasm/tests/BitcoinSigHashType.test.ts new file mode 100644 index 00000000000..cfb37e5e2e9 --- /dev/null +++ b/wasm/tests/BitcoinSigHashType.test.ts @@ -0,0 +1,30 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import "mocha"; +import { assert } from "chai"; + +describe("BitcoinSigHashType", () => { + it("test isSingle", () => { + const { BitcoinSigHashType, BitcoinSigHashTypeExt } = globalThis.core; + + assert.isFalse(BitcoinSigHashTypeExt.isSingle(BitcoinSigHashType.all)); + assert.isFalse(BitcoinSigHashTypeExt.isSingle(BitcoinSigHashType.none)); + assert.isTrue(BitcoinSigHashTypeExt.isSingle(BitcoinSigHashType.single)); + assert.isFalse(BitcoinSigHashTypeExt.isSingle(BitcoinSigHashType.fork)); + assert.isFalse(BitcoinSigHashTypeExt.isSingle(BitcoinSigHashType.forkBTG)); + }); + + it("test isNone", () => { + const { BitcoinSigHashType, BitcoinSigHashTypeExt } = globalThis.core; + + assert.isFalse(BitcoinSigHashTypeExt.isNone(BitcoinSigHashType.all)); + assert.isTrue(BitcoinSigHashTypeExt.isNone(BitcoinSigHashType.none)); + assert.isFalse(BitcoinSigHashTypeExt.isNone(BitcoinSigHashType.single)); + assert.isFalse(BitcoinSigHashTypeExt.isNone(BitcoinSigHashType.fork)); + assert.isFalse(BitcoinSigHashTypeExt.isNone(BitcoinSigHashType.forkBTG)); + }); +}); diff --git a/wasm/tests/CoinType.test.ts b/wasm/tests/CoinType.test.ts index 416949d944c..44941975f57 100644 --- a/wasm/tests/CoinType.test.ts +++ b/wasm/tests/CoinType.test.ts @@ -1,4 +1,4 @@ -// Copyright © 2017-2022 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -9,7 +9,7 @@ import { assert } from "chai"; describe("CoinType", () => { it("test raw value", () => { - const { CoinType, CoinTypeExtension, Blockchain, Purpose, Curve, Derivation, PrivateKey, HexCoding } = globalThis.core; + const { CoinType, CoinTypeExt, Blockchain, Purpose, Curve, Derivation, PrivateKey, HexCoding } = globalThis.core; assert.equal(CoinType.bitcoin.value, 0); assert.equal(CoinType.litecoin.value, 2); @@ -18,17 +18,15 @@ describe("CoinType", () => { assert.equal(CoinType.binance.value, 714); assert.equal(CoinType.cosmos.value, 118); assert.equal(CoinType.solana.value, 501); - let val = new CoinTypeExtension(CoinType.solana); - assert.equal(val.blockchain(), Blockchain.solana); - assert.equal(val.value(), CoinType.solana); - assert.equal(val.purpose(), Purpose.bip44); - assert.equal(val.curve(), Curve.ed25519); - assert.isTrue(val.validate("Bxp8yhH9zNwxyE4UqxP7a7hgJ5xTZfxNNft7YJJ2VRjT")) - assert.equal(val.derivationPath(), "m/44'/501'/0'"); - assert.equal(val.derivationPathWithDerivation(Derivation.solanaSolana), "m/44'/501'/0'/0'"); + assert.equal(CoinTypeExt.blockchain(CoinType.solana), Blockchain.solana); + assert.equal(CoinTypeExt.purpose(CoinType.solana), Purpose.bip44); + assert.equal(CoinTypeExt.curve(CoinType.solana), Curve.ed25519); + assert.isTrue(CoinTypeExt.validate(CoinType.solana, "Bxp8yhH9zNwxyE4UqxP7a7hgJ5xTZfxNNft7YJJ2VRjT")) + assert.equal(CoinTypeExt.derivationPath(CoinType.solana), "m/44'/501'/0'"); + assert.equal(CoinTypeExt.derivationPathWithDerivation(CoinType.solana, Derivation.solanaSolana), "m/44'/501'/0'/0'"); let data = HexCoding.decode("8778cc93c6596387e751d2dc693bbd93e434bd233bc5b68a826c56131821cb63") const key = PrivateKey.createWithData(data); - let addr = val.deriveAddress(key); + let addr = CoinTypeExt.deriveAddress(CoinType.solana, key); assert.equal(addr, "7v91N7iZ9mNicL8WfG6cgSCKyRXydQjLh6UYBWwm6y1Q") }); }); diff --git a/wasm/tests/HDVersion.test.ts b/wasm/tests/HDVersion.test.ts new file mode 100644 index 00000000000..3ef5aac2729 --- /dev/null +++ b/wasm/tests/HDVersion.test.ts @@ -0,0 +1,50 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +import "mocha"; +import { assert } from "chai"; + +describe("HDVersion", () => { + it("test isPublic", () => { + const { HDVersion, HDVersionExt } = globalThis.core; + + assert.isFalse(HDVersionExt.isPublic(HDVersion.none)); + assert.isTrue(HDVersionExt.isPublic(HDVersion.xpub)); + assert.isFalse(HDVersionExt.isPublic(HDVersion.xprv)); + assert.isTrue(HDVersionExt.isPublic(HDVersion.ypub)); + assert.isFalse(HDVersionExt.isPublic(HDVersion.yprv)); + assert.isTrue(HDVersionExt.isPublic(HDVersion.zpub)); + assert.isFalse(HDVersionExt.isPublic(HDVersion.zprv)); + assert.isTrue(HDVersionExt.isPublic(HDVersion.ltub)); + assert.isFalse(HDVersionExt.isPublic(HDVersion.ltpv)); + assert.isTrue(HDVersionExt.isPublic(HDVersion.mtub)); + assert.isFalse(HDVersionExt.isPublic(HDVersion.mtpv)); + assert.isTrue(HDVersionExt.isPublic(HDVersion.dpub)); + assert.isFalse(HDVersionExt.isPublic(HDVersion.dprv)); + assert.isTrue(HDVersionExt.isPublic(HDVersion.dgub)); + assert.isFalse(HDVersionExt.isPublic(HDVersion.dgpv)); + }); + + it("test isPrivate", () => { + const { HDVersion, HDVersionExt } = globalThis.core; + + assert.isFalse(HDVersionExt.isPrivate(HDVersion.none)); + assert.isFalse(HDVersionExt.isPrivate(HDVersion.xpub)); + assert.isTrue(HDVersionExt.isPrivate(HDVersion.xprv)); + assert.isFalse(HDVersionExt.isPrivate(HDVersion.ypub)); + assert.isTrue(HDVersionExt.isPrivate(HDVersion.yprv)); + assert.isFalse(HDVersionExt.isPrivate(HDVersion.zpub)); + assert.isTrue(HDVersionExt.isPrivate(HDVersion.zprv)); + assert.isFalse(HDVersionExt.isPrivate(HDVersion.ltub)); + assert.isTrue(HDVersionExt.isPrivate(HDVersion.ltpv)); + assert.isFalse(HDVersionExt.isPrivate(HDVersion.mtub)); + assert.isTrue(HDVersionExt.isPrivate(HDVersion.mtpv)); + assert.isFalse(HDVersionExt.isPrivate(HDVersion.dpub)); + assert.isTrue(HDVersionExt.isPrivate(HDVersion.dprv)); + assert.isFalse(HDVersionExt.isPrivate(HDVersion.dgub)); + assert.isTrue(HDVersionExt.isPrivate(HDVersion.dgpv)); + }); +}); From 06d11f90d9a5f74c8b40a114b1038f66ef4ef00c Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 13 Feb 2023 11:06:52 +0100 Subject: [PATCH 194/497] [Rust]: Hex, Refactor and CI optimizations (#2917) --- .github/workflows/android-ci.yml | 8 +- .github/workflows/ios-ci.yml | 7 + .github/workflows/linux-ci.yml | 7 + CMakeLists.txt | 17 +- android/trustwalletcore/build.gradle | 2 +- kotlin/wallet-core-kotlin/build.gradle.kts | 2 +- rust/Cargo.lock | 174 +++++++++++------- rust/src/encoding/base64.rs | 111 +++++++++++ rust/src/encoding/hex.rs | 99 ++++++++++ rust/src/encoding/mod.rs | 111 +---------- rust/src/memory/mod.rs | 6 + rust/src/starknet/mod.rs | 3 +- samples/cpp/CMakeLists.txt | 11 +- samples/rust/src/build.rs | 1 + src/Aeternity/Address.h | 4 - src/Aion/Address.h | 4 - src/Aion/Entry.cpp | 5 - src/Aion/Entry.h | 1 - src/Algorand/Address.h | 4 - src/Data.h | 15 ++ src/Decred/Signer.cpp | 2 +- src/Everscale/CommonTON/RawAddress.cpp | 1 + src/HexCoding.h | 100 +++++----- src/Icon/Address.cpp | 2 +- src/PrivateKey.h | 7 - src/Tezos/BinaryCoding.cpp | 3 +- tests/chains/Aeternity/AddressTests.cpp | 2 + tests/chains/Aion/AddressTests.cpp | 7 + tests/chains/Binance/SignerTests.cpp | 42 ++--- .../chains/BitcoinGold/TWBitcoinGoldTests.cpp | 2 +- tests/chains/BitcoinGold/TWSignerTests.cpp | 2 +- tests/chains/Cosmos/AddressTests.cpp | 4 +- tests/chains/Decred/SignerTests.cpp | 4 +- tests/chains/Ethereum/AbiTests.cpp | 46 ++--- .../Groestlcoin/TWGroestlcoinSigningTests.cpp | 6 +- tests/chains/IoTeX/SignerTests.cpp | 8 +- tests/chains/Ontology/Oep4Tests.cpp | 14 +- tests/chains/Ontology/ParamsBuilderTests.cpp | 6 +- tests/chains/Tezos/ForgingTests.cpp | 8 +- tests/chains/Tezos/OperationListTests.cpp | 10 +- tests/chains/Tezos/PublicKeyTests.cpp | 2 +- tests/chains/Tezos/SignerTests.cpp | 4 +- .../chains/Zcash/TWZcashTransactionTests.cpp | 6 +- .../Zelcash/TWZelcashTransactionTests.cpp | 6 +- tests/chains/Zilliqa/SignerTests.cpp | 8 +- tests/common/Bech32AddressTests.cpp | 12 +- tools/generate-files | 8 +- tools/rust-bindgen | 45 +++-- 48 files changed, 566 insertions(+), 393 deletions(-) create mode 100644 rust/src/encoding/base64.rs create mode 100644 rust/src/encoding/hex.rs diff --git a/.github/workflows/android-ci.yml b/.github/workflows/android-ci.yml index fc7f61fe874..3a58164c7ac 100644 --- a/.github/workflows/android-ci.yml +++ b/.github/workflows/android-ci.yml @@ -41,8 +41,14 @@ jobs: run: tools/install-dependencies if: steps.internal_cache.outputs.cache-hit != 'true' + - name: Cache Rust + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + rust + - name: Generate files - run: tools/generate-files + run: tools/generate-files android - name: Build Kotlin doc run: tools/kotlin-doc diff --git a/.github/workflows/ios-ci.yml b/.github/workflows/ios-ci.yml index 4490e8a48dd..3fa46ba4a50 100644 --- a/.github/workflows/ios-ci.yml +++ b/.github/workflows/ios-ci.yml @@ -27,6 +27,13 @@ jobs: if: steps.internal_cache.outputs.cache-hit != 'true' - name: Run codegen tests run: tools/codegen-test + + - name: Cache Rust + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + rust + - name: Run iOS tests run: | tools/generate-files diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 84d53924e49..0e290c2e55a 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -28,6 +28,13 @@ jobs: CC: /usr/bin/clang CXX: /usr/bin/clang++ if: steps.internal_cache.outputs.cache-hit != 'true' + + - name: Cache Rust + uses: Swatinem/rust-cache@v2 + with: + workspaces: | + rust + - name: Code generation run: | tools/generate-files diff --git a/CMakeLists.txt b/CMakeLists.txt index f097a622916..64bb0147fb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,17 +24,20 @@ include(cmake/CompilerWarnings.cmake) include(cmake/StaticAnalyzers.cmake) include(cmake/FindHostPackage.cmake) +set(WALLET_CORE_RS_TARGET_DIR ${CMAKE_SOURCE_DIR}/rust/target) add_library(${PROJECT_NAME}_INTERFACE INTERFACE) target_include_directories(${PROJECT_NAME}_INTERFACE INTERFACE ${PREFIX}/include) target_link_directories(${PROJECT_NAME}_INTERFACE INTERFACE ${PREFIX}/lib) +target_link_directories(${PROJECT_NAME}_INTERFACE INTERFACE ${WALLET_CORE_RS_TARGET_DIR}/release) set_project_warnings(${PROJECT_NAME}_INTERFACE) add_subdirectory(trezor-crypto) set(WALLET_CORE_RS_LIB libwallet_core_rs.a) -set(WALLET_CORE_BINDGEN ${PREFIX}/lib/${WALLET_CORE_RS_LIB}) + +set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/release/${WALLET_CORE_RS_LIB}) if (TW_COMPILE_WASM) message(STATUS "Wasm build enabled") - set(WALLET_CORE_BINDGEN ${PREFIX}/wasm32-unknown-emscripten/release/${WALLET_CORE_RS_LIB}) + set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/wasm32-unknown-emscripten/release/${WALLET_CORE_RS_LIB}) add_subdirectory(wasm) endif () @@ -58,13 +61,13 @@ if (${ANDROID}) add_library(TrustWalletCore SHARED ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) find_library(log-lib log) if (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "arm64-v8a") - set(WALLET_CORE_BINDGEN ${PREFIX}/aarch64-linux-android/release/${WALLET_CORE_RS_LIB}) + set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/aarch64-linux-android/release/${WALLET_CORE_RS_LIB}) elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL "x86") - set(WALLET_CORE_BINDGEN ${PREFIX}/i686-linux-android/release/${WALLET_CORE_RS_LIB}) + set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/i686-linux-android/release/${WALLET_CORE_RS_LIB}) elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL "armeabi-v7a") - set(WALLET_CORE_BINDGEN ${PREFIX}/armv7-linux-androideabi/release/${WALLET_CORE_RS_LIB}) + set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/armv7-linux-androideabi/release/${WALLET_CORE_RS_LIB}) elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL "x86_64") - set(WALLET_CORE_BINDGEN ${PREFIX}/x86_64-linux-android/release/${WALLET_CORE_RS_LIB}) + set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/x86_64-linux-android/release/${WALLET_CORE_RS_LIB}) endif() target_link_libraries(TrustWalletCore PUBLIC ${WALLET_CORE_BINDGEN} ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf ${log-lib} Boost::boost) else () @@ -111,7 +114,7 @@ if (TW_ENABLE_CLANG_TIDY) tw_add_clang_tidy_target(TrustWalletCore) endif () -if (NOT ANDROID AND TW_UNITY_BUILD) +if (TW_UNITY_BUILD) set_target_properties(TrustWalletCore PROPERTIES UNITY_BUILD ON) file(GLOB_RECURSE PROTOBUF_SOURCE_FILES CONFIGURE_DEPENDS src/Cosmos/Protobuf/*.pb.cc src/Hedera/Protobuf/*.pb.cc src/proto/*.pb.cc) diff --git a/android/trustwalletcore/build.gradle b/android/trustwalletcore/build.gradle index bf97bfd2412..b4088f99b48 100644 --- a/android/trustwalletcore/build.gradle +++ b/android/trustwalletcore/build.gradle @@ -11,7 +11,7 @@ android { versionName "1.0" externalNativeBuild { cmake { - arguments "-DCMAKE_BUILD_TYPE=Release" + arguments "-DCMAKE_BUILD_TYPE=Release", "-DTW_UNITY_BUILD=ON" } } } diff --git a/kotlin/wallet-core-kotlin/build.gradle.kts b/kotlin/wallet-core-kotlin/build.gradle.kts index 6ceb9a8cbad..4af9f55bf0e 100644 --- a/kotlin/wallet-core-kotlin/build.gradle.kts +++ b/kotlin/wallet-core-kotlin/build.gradle.kts @@ -94,7 +94,7 @@ android { externalNativeBuild { cmake { - arguments += listOf("-DCMAKE_BUILD_TYPE=Release", "-DKOTLIN=True") + arguments += listOf("-DCMAKE_BUILD_TYPE=Release", "-DKOTLIN=True", "-DTW_UNITY_BUILD=ON") } } } diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 3efb0c41ea4..601d9de59d3 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" [[package]] name = "ark-ff" @@ -76,9 +76,9 @@ checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "async-trait" -version = "0.1.59" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" +checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" dependencies = [ "proc-macro2", "quote", @@ -145,9 +145,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byte-slice-cast" @@ -163,9 +163,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cfg-if" @@ -359,6 +359,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hex" version = "0.4.3" @@ -419,17 +425,27 @@ dependencies = [ "syn", ] +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -445,9 +461,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.137" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "log" @@ -458,6 +474,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + [[package]] name = "move-core-types" version = "0.0.4" @@ -473,6 +495,15 @@ dependencies = [ "serde_bytes", ] +[[package]] +name = "nom8" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" +dependencies = [ + "memchr", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -505,9 +536,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "opaque-debug" @@ -543,15 +574,15 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" [[package]] name = "pest" -version = "2.4.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8" +checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660" dependencies = [ "thiserror", "ucd-trie", @@ -578,29 +609,28 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" dependencies = [ "once_cell", - "thiserror", - "toml", + "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -643,18 +673,18 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b15debb4f9d60d767cd8ca9ef7abb2452922f3214671ff052defc7f3502c44" +checksum = "8c78fb8c9293bcd48ef6fce7b4ca950ceaf21210de6e105a883ee280c0f7b9ed" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abfa8511e9e94fd3de6585a3d3cd00e01ed556dc9814829280af0e8dc72a8f36" +checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" dependencies = [ "proc-macro2", "quote", @@ -699,9 +729,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "semver" @@ -723,27 +753,27 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.147" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.7" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" +checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", @@ -752,9 +782,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" dependencies = [ "itoa", "ryu", @@ -889,9 +919,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.103" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -918,18 +948,18 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -946,19 +976,27 @@ dependencies = [ ] [[package]] -name = "toml" -version = "0.5.9" +name = "toml_datetime" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" + +[[package]] +name = "toml_edit" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" dependencies = [ - "serde", + "indexmap", + "nom8", + "toml_datetime", ] [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" @@ -980,9 +1018,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-xid" @@ -1017,9 +1055,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1027,9 +1065,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -1042,9 +1080,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1052,9 +1090,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -1065,9 +1103,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wyz" @@ -1086,9 +1124,9 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ "proc-macro2", "quote", diff --git a/rust/src/encoding/base64.rs b/rust/src/encoding/base64.rs new file mode 100644 index 00000000000..8c848129815 --- /dev/null +++ b/rust/src/encoding/base64.rs @@ -0,0 +1,111 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +use base64::{Engine as _, engine::{general_purpose}}; + +use std::ffi::{CStr, CString}; +use std::os::raw::c_char; +use crate::memory::CByteArray; + +#[no_mangle] +pub extern "C" fn encode_base64(data: *const u8, len: usize, is_url: bool) -> *mut c_char { + let data = unsafe { std::slice::from_raw_parts(data, len) }; + let encoded = if is_url { + general_purpose::URL_SAFE.encode(data) + } else { + general_purpose::STANDARD.encode(data) + }; + CString::new(encoded).unwrap().into_raw() +} + +#[no_mangle] +pub extern "C" fn decode_base64(data: *const c_char, is_url: bool) -> CByteArray { + if data.is_null() { + return CByteArray { data: std::ptr::null_mut(), size: 0 }; + } + let c_str = unsafe { CStr::from_ptr(data) }; + let str_slice = c_str.to_str().unwrap(); + let decoded = if is_url { + general_purpose::URL_SAFE + .decode(str_slice) + } else { + general_purpose::STANDARD + .decode(str_slice) + }; + let decoded = match decoded { + Ok(decoded) => decoded, + Err(_) => return CByteArray { data: std::ptr::null_mut(), size: 0 } + }; + let size = decoded.len(); + let mut decoded_vec = decoded.to_vec(); + let ptr = decoded_vec.as_mut_ptr(); + std::mem::forget(decoded_vec); + CByteArray { data: ptr, size } +} + +#[cfg(test)] +mod tests { + use std::ffi::CString; + use crate::encoding::base64::{decode_base64, encode_base64}; + + #[test] + fn test_encode_base64_ffi() { + let data = b"hello world"; + let encoded = unsafe { + std::ffi::CStr::from_ptr(encode_base64(data.as_ptr(), data.len(), false)) + }; + let expected = "aGVsbG8gd29ybGQ="; + assert_eq!(encoded.to_str().unwrap(), expected); + } + + #[test] + fn test_encode_base64_url_ffi() { + let data = b"+'?ab"; + let encoded = unsafe { + std::ffi::CStr::from_ptr(encode_base64(data.as_ptr(), data.len(), true)) + }; + let expected = "Kyc_YWI="; + assert_eq!(encoded.to_str().unwrap(), expected); + } + + #[test] + fn test_decode_base64_url() { + let encoded = "Kyc_YWI="; + let expected = b"+'?ab"; + + let encoded_c_str = CString::new(encoded).unwrap(); + let encoded_ptr = encoded_c_str.as_ptr(); + + let decoded_ptr = decode_base64(encoded_ptr, true); + let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; + + assert_eq!(decoded_slice, expected); + } + + #[test] + fn test_decode_base64() { + let encoded = "aGVsbG8gd29ybGQh"; + let expected = b"hello world!"; + + let encoded_c_str = CString::new(encoded).unwrap(); + let encoded_ptr = encoded_c_str.as_ptr(); + + let decoded_ptr = decode_base64(encoded_ptr, false); + let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; + + assert_eq!(decoded_slice, expected); + } + + #[test] + fn test_decode_base64_invalid() { + let invalid_encoded = "_This_is_an_invalid_base64_"; + let encoded_c_str = CString::new(invalid_encoded).unwrap(); + let encoded_ptr = encoded_c_str.as_ptr(); + let decoded_ptr = decode_base64(encoded_ptr, false); + assert_eq!(decoded_ptr.data.is_null(), true); + } +} + diff --git a/rust/src/encoding/hex.rs b/rust/src/encoding/hex.rs new file mode 100644 index 00000000000..b1a7869600e --- /dev/null +++ b/rust/src/encoding/hex.rs @@ -0,0 +1,99 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +use std::ffi::{c_char, CStr, CString}; +use crate::memory::CByteArray; +use hex; + +#[no_mangle] +pub extern "C" fn decode_hex(data: *const c_char) -> CByteArray { + if data.is_null() { + return CByteArray { data: std::ptr::null_mut(), size: 0 }; + } + let c_str = unsafe { CStr::from_ptr(data) }; + let hex_string = c_str.to_str().unwrap(); + let hex_string = if hex_string.starts_with("0x") { &hex_string[2..] } else { hex_string }; + + return match hex::decode(hex_string) { + Ok(mut decoded) => { + let size = decoded.len(); + let ptr = decoded.as_mut_ptr(); + std::mem::forget(decoded); + CByteArray { data: ptr, size } + } + Err(_) => { + CByteArray { data: std::ptr::null_mut(), size: 0 } + } + } +} + +#[no_mangle] +pub extern "C" fn encode_hex(data: *const u8, len: usize, prefixed: bool) -> *mut c_char { + let data = unsafe { std::slice::from_raw_parts(data, len) }; + let mut encoded = hex::encode(data); + if prefixed { + encoded = "0x".to_owned() + &encoded; + } + CString::new(encoded).unwrap().into_raw() +} + +#[cfg(test)] +mod tests { + use std::ffi::CString; + use crate::encoding::hex::{encode_hex, decode_hex}; + + #[test] + fn test_encode_hex_without_prefix() { + let data = b"hello world"; + let encoded = unsafe { + std::ffi::CStr::from_ptr(encode_hex(data.as_ptr(), data.len(), false)) + }; + let expected = "68656c6c6f20776f726c64"; + assert_eq!(encoded.to_str().unwrap(), expected); + } + + #[test] + fn test_encode_hex_with_prefix() { + let data = b"hello world"; + let encoded = unsafe { + std::ffi::CStr::from_ptr(encode_hex(data.as_ptr(), data.len(), true)) + }; + let expected = "0x68656c6c6f20776f726c64"; + assert_eq!(encoded.to_str().unwrap(), expected); + } + + #[test] + fn test_vec_encode() { + let v: Vec = vec![45,181,0,172,145,156,221,227,81,172,54,227,113,29,131,44,109,185,118,105]; + assert_eq!(hex::encode(v), "2db500ac919cdde351ac36e3711d832c6db97669"); + } + + #[test] + fn test_decode_hex() { + let encoded = "7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1"; + + let encoded_c_str = CString::new(encoded).unwrap(); + let encoded_ptr = encoded_c_str.as_ptr(); + + let decoded_ptr = decode_hex(encoded_ptr); + let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; + + assert_eq!(decoded_slice.is_empty(), false); + } + + #[test] + fn test_decode_hex_with_prefix() { + let encoded = "0x7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1"; + + let encoded_c_str = CString::new(encoded).unwrap(); + let encoded_ptr = encoded_c_str.as_ptr(); + + let decoded_ptr = decode_hex(encoded_ptr); + let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; + + assert_eq!(decoded_slice.is_empty(), false); + } +} diff --git a/rust/src/encoding/mod.rs b/rust/src/encoding/mod.rs index 82bff00e40b..b1798fbcce7 100644 --- a/rust/src/encoding/mod.rs +++ b/rust/src/encoding/mod.rs @@ -4,112 +4,5 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -use base64::{Engine as _, engine::{general_purpose}}; -use std::ffi::{CStr, CString}; -use std::os::raw::c_char; - -#[no_mangle] -pub extern "C" fn encode_base64(data: *const u8, len: usize, is_url: bool) -> *mut c_char { - let data = unsafe { std::slice::from_raw_parts(data, len) }; - let encoded = if is_url { - general_purpose::URL_SAFE.encode(data) - } else { - general_purpose::STANDARD.encode(data) - }; - CString::new(encoded).unwrap().into_raw() -} - -#[repr(C)] -pub struct CByteArray { - data: *mut u8, - size: usize, -} - -#[no_mangle] -pub extern "C" fn decode_base64(data: *const c_char, is_url: bool) -> CByteArray { - if data.is_null() { - return CByteArray { data: std::ptr::null_mut(), size: 0 }; - } - let c_str = unsafe { CStr::from_ptr(data) }; - let str_slice = c_str.to_str().unwrap(); - let decoded = if is_url { - general_purpose::URL_SAFE - .decode(str_slice) - } else { - general_purpose::STANDARD - .decode(str_slice) - }; - let decoded = match decoded { - Ok(decoded) => decoded, - Err(_) => return CByteArray { data: std::ptr::null_mut(), size: 0 } - }; - let size = decoded.len(); - let mut decoded_vec = decoded.to_vec(); - let ptr = decoded_vec.as_mut_ptr(); - std::mem::forget(decoded_vec); - CByteArray { data: ptr, size } -} - - -#[cfg(test)] -mod tests { - use std::ffi::CString; - use crate::encoding::{decode_base64, encode_base64}; - - #[test] - fn test_encode_base64_ffi() { - let data = b"hello world"; - let encoded = unsafe { - std::ffi::CStr::from_ptr(encode_base64(data.as_ptr(), data.len(), false)) - }; - let expected = "aGVsbG8gd29ybGQ="; - assert_eq!(encoded.to_str().unwrap(), expected); - } - - #[test] - fn test_encode_base64_url_ffi() { - let data = b"+'?ab"; - let encoded = unsafe { - std::ffi::CStr::from_ptr(encode_base64(data.as_ptr(), data.len(), true)) - }; - let expected = "Kyc_YWI="; - assert_eq!(encoded.to_str().unwrap(), expected); - } - - #[test] - fn test_decode_base64_url() { - let encoded = "Kyc_YWI="; - let expected = b"+'?ab"; - - let encoded_c_str = CString::new(encoded).unwrap(); - let encoded_ptr = encoded_c_str.as_ptr(); - - let decoded_ptr = decode_base64(encoded_ptr, true); - let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; - - assert_eq!(decoded_slice, expected); - } - - #[test] - fn test_decode_base64() { - let encoded = "aGVsbG8gd29ybGQh"; - let expected = b"hello world!"; - - let encoded_c_str = CString::new(encoded).unwrap(); - let encoded_ptr = encoded_c_str.as_ptr(); - - let decoded_ptr = decode_base64(encoded_ptr, false); - let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; - - assert_eq!(decoded_slice, expected); - } - - #[test] - fn test_decode_base64_invalid() { - let invalid_encoded = "_This_is_an_invalid_base64_"; - let encoded_c_str = CString::new(invalid_encoded).unwrap(); - let encoded_ptr = encoded_c_str.as_ptr(); - let decoded_ptr = decode_base64(encoded_ptr, false); - assert_eq!(decoded_ptr.data.is_null(), true); - } -} +mod base64; +mod hex; diff --git a/rust/src/memory/mod.rs b/rust/src/memory/mod.rs index 91bb4d4ddf6..a923e03a8c0 100644 --- a/rust/src/memory/mod.rs +++ b/rust/src/memory/mod.rs @@ -6,6 +6,12 @@ use std::ffi::{c_char, CString}; +#[repr(C)] +pub struct CByteArray { + pub data: *mut u8, + pub size: usize, +} + #[no_mangle] pub unsafe extern fn free_string(ptr: *const c_char) { // Take the ownership back to rust and drop the owner diff --git a/rust/src/starknet/mod.rs b/rust/src/starknet/mod.rs index 9da51860024..07d22e32935 100644 --- a/rust/src/starknet/mod.rs +++ b/rust/src/starknet/mod.rs @@ -5,7 +5,8 @@ // file LICENSE at the root of the source code distribution tree. use std::ffi::{c_char, CStr}; -use starknet_crypto::{FieldElement, get_public_key, Signature}; +use starknet_crypto::{get_public_key, Signature}; +use starknet_ff::{FieldElement}; use starknet_signers::{SigningKey, VerifyingKey}; use crate::memory; diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index a7c743f3e81..5fe33b0cd93 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -30,7 +30,7 @@ set (CMAKE_C_STANDARD_REQUIRED ON) # ${WALLET_CORE}/src -- internal TrustWalletCore files, for signer protobuf messages # ${WALLET_CORE}/build/local/include) -- for protobuf includes include_directories (${CMAKE_SOURCE_DIR} ${WALLET_CORE}/include ${WALLET_CORE}/src ${WALLET_CORE}/build/local/include) -link_directories (${WALLET_CORE}/build ${WALLET_CORE}/build/trezor-crypto ${WALLET_CORE}/build/local/lib) +link_directories (${WALLET_CORE}/build ${WALLET_CORE}/build/trezor-crypto ${WALLET_CORE}/build/local/lib ${WALLET_CORE}/rust/target/release) find_library(WALLET_CORE_LIB_FILE TrustWalletCore PATH ${WALLET_CORE}/build) if (NOT WALLET_CORE_LIB_FILE) @@ -39,6 +39,13 @@ else () message ("TrustWalletCore library found here: ${WALLET_CORE_LIB_FILE}") endif () +find_library(WALLET_CORE_RS_LIB_FILE wallet_core_rs PATH ${WALLET_CORE}/rust/target/release) +if (NOT WALLET_CORE_RS_LIB_FILE) + message (FATAL_ERROR "wallet_core_rs library not found. ${SETUP_MESSAGE}") +else () + message ("wallet_core_rs library found here: ${WALLET_CORE_RS_LIB_FILE}") +endif () + # Create all libraries and executables in the root binary dir set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) @@ -71,4 +78,4 @@ SET (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINK_FLAGS}") add_executable (sample sample.cpp) # link with our library, and default platform libraries -target_link_libraries (sample PUBLIC TrustWalletCore wallet_core_rs TrezorCrypto protobuf pthread ${PLATFORM_LIBS}) +target_link_libraries (sample PUBLIC TrustWalletCore ${WALLET_CORE_RS_LIB_FILE} TrezorCrypto protobuf pthread ${PLATFORM_LIBS}) diff --git a/samples/rust/src/build.rs b/samples/rust/src/build.rs index 4f98962f974..e9d0065dfa9 100644 --- a/samples/rust/src/build.rs +++ b/samples/rust/src/build.rs @@ -34,6 +34,7 @@ fn main() { println!("cargo:rustc-link-search=native={}/build", WALLET_CORE_PROJECT_DIR); println!("cargo:rustc-link-search=native={}/build/trezor-crypto", WALLET_CORE_PROJECT_DIR); println!("cargo:rustc-link-search=native={}/build/local/lib", WALLET_CORE_PROJECT_DIR); + println!("cargo:rustc-link-search=native={}/rust/target/release", WALLET_CORE_PROJECT_DIR); // Libraries; order matters for i in 0..LIBS.len() { diff --git a/src/Aeternity/Address.h b/src/Aeternity/Address.h index 3733a44e93d..eddaea8b804 100644 --- a/src/Aeternity/Address.h +++ b/src/Aeternity/Address.h @@ -34,8 +34,4 @@ class Address { static bool checkPayload(const std::string& payload); }; -inline bool operator==(const Address& lhs, const Address& rhs) { - return lhs.bytes == rhs.bytes; -} - } // namespace TW::Aeternity diff --git a/src/Aion/Address.h b/src/Aion/Address.h index 0a1bc7f4d13..580cf684579 100644 --- a/src/Aion/Address.h +++ b/src/Aion/Address.h @@ -43,8 +43,4 @@ class Address { std::string string() const; }; -inline bool operator==(const Address& lhs, const Address& rhs) { - return lhs.bytes == rhs.bytes; -} - } // namespace TW::Aion diff --git a/src/Aion/Entry.cpp b/src/Aion/Entry.cpp index 454fb6cbc05..98f6bfc0f02 100644 --- a/src/Aion/Entry.cpp +++ b/src/Aion/Entry.cpp @@ -24,11 +24,6 @@ string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& p return Address(publicKey).string(); } -Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { - const auto addr = Address(address); - return {addr.bytes.begin(), addr.bytes.end()}; -} - void Entry::sign([[maybe_unused]] TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const { signTemplate(dataIn, dataOut); } diff --git a/src/Aion/Entry.h b/src/Aion/Entry.h index b09f3a4871f..4a3944b39a9 100644 --- a/src/Aion/Entry.h +++ b/src/Aion/Entry.h @@ -16,7 +16,6 @@ class Entry final : public CoinEntry { public: bool validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const; std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TWDerivation derivation, const PrefixVariant& addressPrefix) const; - Data addressToData(TWCoinType coin, const std::string& address) const; void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const; }; diff --git a/src/Algorand/Address.h b/src/Algorand/Address.h index dc4af6666fe..2928186b9bc 100644 --- a/src/Algorand/Address.h +++ b/src/Algorand/Address.h @@ -37,8 +37,4 @@ class Address { std::string string() const; }; -inline bool operator==(const Address& lhs, const Address& rhs) { - return lhs.bytes == rhs.bytes; -} - } // namespace TW::Algorand diff --git a/src/Data.h b/src/Data.h index 6ab74ccaba9..4abfed23abd 100644 --- a/src/Data.h +++ b/src/Data.h @@ -20,6 +20,21 @@ inline void pad_left(Data& data, const uint32_t size) { data.insert(data.begin(), size - data.size(), 0); } +template +inline Data data(It&& begin, It&& end) { + return Data(begin, end); +} + +template +inline Data data_from(const Collection& collection) { + Data out; + out.reserve(collection.size()); + for (auto&& cur : collection) { + out.emplace_back(uint8_t(cur)); + } + return out; +} + inline Data data(const std::string& data) { return Data(data.begin(), data.end()); } diff --git a/src/Decred/Signer.cpp b/src/Decred/Signer.cpp index 5cb610c137e..5cae54cb126 100644 --- a/src/Decred/Signer.cpp +++ b/src/Decred/Signer.cpp @@ -193,7 +193,7 @@ Data Signer::keyForPublicKeyHash(const Data& hash) const { } Data Signer::scriptForScriptHash(const Data& hash) const { - auto hashString = hex(hash.begin(), hash.end()); + auto hashString = hex(hash); auto it = input.scripts().find(hashString); if (it == input.scripts().end()) { // Error: Missing redeem script diff --git a/src/Everscale/CommonTON/RawAddress.cpp b/src/Everscale/CommonTON/RawAddress.cpp index 5aa6199062f..326737c486c 100644 --- a/src/Everscale/CommonTON/RawAddress.cpp +++ b/src/Everscale/CommonTON/RawAddress.cpp @@ -4,6 +4,7 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +#include #include "RawAddress.h" #include "HexCoding.h" diff --git a/src/HexCoding.h b/src/HexCoding.h index f047065a85b..48d1d18661b 100644 --- a/src/HexCoding.h +++ b/src/HexCoding.h @@ -7,14 +7,34 @@ #pragma once #include "Data.h" +#include "rust/bindgen/WalletCoreRSBindgen.h" -#include - +#include #include #include #include #include + +namespace TW::internal { +/// Parses a string of hexadecimal values. +/// +/// \returns the array or parsed bytes or an empty array if the string is not +/// valid hexadecimal. +inline Data parse_hex(const std::string& input) { + if (input.empty()) { + return Data(); + } + auto decoded = decode_hex(input.c_str()); + if (decoded.data == nullptr || decoded.size == 0) { + return Data(); + } + std::vector decoded_vec(&decoded.data[0], &decoded.data[decoded.size]); + std::free(decoded.data); + return decoded_vec; +} +} + namespace TW { inline bool is_hex_encoded(const std::string& s) @@ -26,65 +46,39 @@ inline bool is_hex_encoded(const std::string& s) return with_0x || without_0x; } -std::tuple value(uint8_t c); - -/// Converts a range of bytes to a hexadecimal string representation. -template -inline std::string hex(const Iter begin, const Iter end) { - static constexpr std::array hexmap = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - - std::string result; - result.reserve((end - begin) * 2); - - for (auto it = begin; it < end; ++it) { - auto val = static_cast(*it); - result.push_back(hexmap[val >> 4]); - result.push_back(hexmap[val & 0x0f]); - } - - return result; -} - /// Converts a collection of bytes to a hexadecimal string representation. template -inline std::string hex(const T& collection) { - return hex(std::begin(collection), std::end(collection)); +inline std::string hex(const T& collection, bool prefixed = false) { + auto rust_functor = [prefixed](auto&& collection){ + auto res = encode_hex(collection.data(), collection.size(), prefixed); + std::string encoded_str(res); + free_string(res); + return encoded_str; + }; + if constexpr (std::is_same_v) { + return rust_functor(collection); + } + else if constexpr (std::is_same_v) { + return rust_functor(data(collection)); + } + else { + return rust_functor(data_from(collection)); + } } /// same as hex, with 0x prefix template -inline std::string hexEncoded(const T& collection) { - return hex(std::begin(collection), std::end(collection)).insert(0, "0x"); +inline std::string hexEncoded(T&& collection) { + return hex(std::forward(collection), true); } /// Converts a `uint64_t` value to a hexadecimal string. inline std::string hex(uint64_t value) { - auto bytes = reinterpret_cast(&value); - return hex(std::reverse_iterator(bytes + sizeof(value)), - std::reverse_iterator(bytes)); -} - -/// Parses a string of hexadecimal values. -/// -/// \returns the array or parsed bytes or an empty array if the string is not -/// valid hexadecimal. -template -inline Data parse_hex(const Iter begin, const Iter end) { - auto it = begin; - - // Skip `0x` - if (end - begin >= 2 && *begin == '0' && *(begin + 1) == 'x') { - it += 2; - } - try { - std::string temp; - boost::algorithm::unhex(it, end, std::back_inserter(temp)); - return Data(temp.begin(), temp.end()); - } catch (...) { - return {}; - } + const uint8_t* begin = reinterpret_cast(&value); + const uint8_t* end = begin + sizeof(value); + Data v(begin, end); + std::reverse(v.begin(), v.end()); + return hex(v); } /// Parses a string of hexadecimal values. @@ -98,9 +92,9 @@ inline Data parse_hex(const std::string& string, bool padLeft = false) { temp.erase(0, 2); } temp.insert(0, 1, '0'); - return parse_hex(temp.begin(), temp.end()); + return internal::parse_hex(temp); } - return parse_hex(string.begin(), string.end()); + return internal::parse_hex(string); } inline const char* hex_char_to_bin(char c) { diff --git a/src/Icon/Address.cpp b/src/Icon/Address.cpp index 79a680098d2..b8f799f48a6 100644 --- a/src/Icon/Address.cpp +++ b/src/Icon/Address.cpp @@ -39,7 +39,7 @@ Address::Address(const std::string& string) { throw std::invalid_argument("Invalid address prefix"); } - const auto data = parse_hex(string.begin() + 2, string.end()); + const auto data = parse_hex(string.substr(2)); std::copy(data.begin(), data.end(), bytes.begin()); } diff --git a/src/PrivateKey.h b/src/PrivateKey.h index 32b2877a0ff..50b16b188d0 100644 --- a/src/PrivateKey.h +++ b/src/PrivateKey.h @@ -87,13 +87,6 @@ class PrivateKey { void cleanup(); }; -inline bool operator==(const PrivateKey& lhs, const PrivateKey& rhs) { - return lhs.bytes == rhs.bytes; -} -inline bool operator!=(const PrivateKey& lhs, const PrivateKey& rhs) { - return lhs.bytes != rhs.bytes; -} - } // namespace TW /// Wrapper for C interface. diff --git a/src/Tezos/BinaryCoding.cpp b/src/Tezos/BinaryCoding.cpp index 1f030be4cfd..363ab9ef76b 100644 --- a/src/Tezos/BinaryCoding.cpp +++ b/src/Tezos/BinaryCoding.cpp @@ -20,7 +20,8 @@ std::string base58ToHex(const std::string& string, size_t prefixLength) { if (decoded.size() < prefixLength) { return ""; } - return TW::hex(decoded.data() + prefixLength, decoded.data() + decoded.size()); + Data v(decoded.data() + prefixLength, decoded.data() + decoded.size()); + return TW::hex(v); } PublicKey parsePublicKey(const std::string& publicKey) { diff --git a/tests/chains/Aeternity/AddressTests.cpp b/tests/chains/Aeternity/AddressTests.cpp index c08866c05e7..753e0b39204 100644 --- a/tests/chains/Aeternity/AddressTests.cpp +++ b/tests/chains/Aeternity/AddressTests.cpp @@ -14,11 +14,13 @@ TEST(AeternityAddress, FromPublicKey) { auto publicKey = PublicKey(parse_hex("ee93a4f66f8d16b819bb9beb9ffccdfcdc1412e87fee6a324c2a99a1e0e67148"), TWPublicKeyTypeED25519); auto address = Address(publicKey); ASSERT_EQ(address.string(), "ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw"); + ASSERT_ANY_THROW(Address(PublicKey(parse_hex("03df9a5e4089f89d45913fb2b856de984c7e8bf1344cc6444cc9705899a48c939d"), TWPublicKeyTypeSECP256k1))); } TEST(AeternityAddress, FromString) { auto address = Address("ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw"); ASSERT_EQ(address.string(), "ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw"); + ASSERT_ANY_THROW(Address("invalid")); } } // namespace TW::Aeternity::tests diff --git a/tests/chains/Aion/AddressTests.cpp b/tests/chains/Aion/AddressTests.cpp index 05f37edb64e..d773b092f4d 100644 --- a/tests/chains/Aion/AddressTests.cpp +++ b/tests/chains/Aion/AddressTests.cpp @@ -23,6 +23,13 @@ TEST(AionAddress, FromString) { std::string aionAddress = "0xa0d2312facea71b740679c926d040c9056a65a4bfa2ddd18ec160064f82909e7"; const auto address = Address(aionAddress); ASSERT_EQ(address.string(), aionAddress); + ASSERT_ANY_THROW(Address("0xffff")); +} + +TEST(AionAddress, InvalidFromData) { + ASSERT_ANY_THROW(Address(parse_hex("0xffff"))); + auto aionAddress = parse_hex("0xa0d2312facea71b740679c926d040c9056a65a4bfa2ddd18ec160064f82909e7"); + [[maybe_unused]] auto res = Address(aionAddress); } TEST(AionAddress, isValid) { diff --git a/tests/chains/Binance/SignerTests.cpp b/tests/chains/Binance/SignerTests.cpp index 66e5d88fc91..cba2b1a48a5 100644 --- a/tests/chains/Binance/SignerTests.cpp +++ b/tests/chains/Binance/SignerTests.cpp @@ -44,7 +44,7 @@ TEST(BinanceSigner, Sign) { auto signer = Binance::Signer(std::move(input)); auto signature = signer.sign(); - ASSERT_EQ(hex(signature.begin(), signature.end()), + ASSERT_EQ(hex(signature), "9123cb6906bb20aeb753f4a121d4d88ff0e9750ba75b0c4e10d76caee1e7d2481290fa3b9887a6225d69" "97f5f939ef834ea61d596a314237c48e560da9e17b5a"); } @@ -73,7 +73,7 @@ TEST(BinanceSigner, Build) { auto signer = Binance::Signer(std::move(input)); auto result = signer.build(); - ASSERT_EQ(hex(result.begin(), result.end()), "db01" + ASSERT_EQ(hex(result), "db01" "f0625dee" "0a65" "ce6dc043" @@ -128,13 +128,13 @@ TEST(BinanceSigner, BuildSend) { auto signer = Binance::Signer(std::move(signingInput)); auto signature = signer.sign(); - ASSERT_EQ(hex(signature.begin(), signature.end()), + ASSERT_EQ(hex(signature), "c65a13440f18a155bd971ee40b9e0dd58586f5bf344e12ec4c76c439aebca8c7789bab7bfbfb4ce89aad" "c4a02df225b6b6efc861c13bbeb5f7a3eea2d7ffc80f"); auto result = signer.build(); - ASSERT_EQ(hex(result.begin(), result.end()), "cc01" + ASSERT_EQ(hex(result), "cc01" "f0625dee" "0a4e" "2a2c87fa" @@ -190,7 +190,7 @@ TEST(BinanceSigner, BuildSend2) { *signingInput.mutable_send_order() = sendOrder; const auto data = Signer(std::move(signingInput)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "c601" "f0625dee" "0a52" @@ -243,7 +243,7 @@ TEST(BinanceSigner, BuildHTLT) { htltOrder.set_cross_chain(false); const auto data = Binance::Signer(std::move(signingInput)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "ee01f0625dee0a7ab33f9a240a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e112140153f11d6db7" "e69c7d51e771c697378018fb6c242a20e8eae926261ab77d018202434791a335249b470246a7b02e28c3" "b2fb6ffad8f330e1d1c7eb053a0a0a03424e421080c2d72f42113130303030303030303a4254432d3144" @@ -276,7 +276,7 @@ TEST(BinanceSigner, BuildDepositHTLT) { *depositHTLTOrder.add_amount() = token; const auto data = Binance::Signer(std::move(signingInput)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "c001f0625dee0a4c639864960a140153f11d6db7e69c7d51e771c697378018fb6c24120e0a074254432d" "3144431080c2d72f1a20dd8fd4719741844d35eb35ddbeca9531d5493a8e4667689c55e73c77503dd9e5" "126c0a26eb5ae98721038df6960084e20b2d07d50e1422f94105c6241d9f1482a4eb79ce8bfd460f19e4" @@ -307,7 +307,7 @@ TEST(BinanceSigner, BuildClaimHTLT) { const auto data = Binance::Signer(std::move(signingInput)).build(); ASSERT_EQ( - hex(data.begin(), data.end()), + hex(data), "d401f0625dee0a5ec16653000a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e11220dd8fd4719741844d35" "eb35ddbeca9531d5493a8e4667689c55e73c77503dd9e51a20bda6933c7757d0ca428aa01fb9d0935a231f87bf" "2deeb9b409cea3f2d580a2cc126e0a26eb5ae9872103a9a55c040c8eb8120f3d1b32193250841c08af44ea561a" @@ -334,7 +334,7 @@ TEST(BinanceSigner, BuildRefundHTLT) { refundHTLTOrder.set_swap_id(swapID.data(), swapID.size()); const auto data = Binance::Signer(std::move(signingInput)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "b201f0625dee0a3c3454a27c0a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e11220dd8fd4719741" "844d35eb35ddbeca9531d5493a8e4667689c55e73c77503dd9e5126e0a26eb5ae9872103a9a55c040c8e" "b8120f3d1b32193250841c08af44ea561aac993dbe0f6b6a8fc71240c9f36142534d16ec8ce656f8eb73" @@ -362,7 +362,7 @@ TEST(BinanceSigner, BuildIssueOrder) { issueOrder.set_mintable(true); const auto data = Binance::Signer(std::move(signingInput)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "b601f0625dee0a40" "17efab80" "0a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e1120f" @@ -392,7 +392,7 @@ TEST(BinanceSigner, BuildMintOrder) { mintOrder.set_amount(1000000); const auto data = Binance::Signer(std::move(signingInput)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "a101f0625dee0a2b" "467e0829" "0a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e1120b" @@ -420,7 +420,7 @@ TEST(BinanceSigner, BuildBurnOrder) { burnOrder.set_amount(1000000); const auto data = Binance::Signer(std::move(signingInput)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "a101f0625dee0a2b" "7ed2d2a0" "0a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e1120b" @@ -448,7 +448,7 @@ TEST(BinanceSigner, BuildFreezeOrder) { freezeOrder.set_amount(1000000); const auto data = Binance::Signer(std::move(signingInput)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "a101f0625dee0a2b" "e774b32d" "0a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e1120b" @@ -476,7 +476,7 @@ TEST(BinanceSigner, BuildUnfreezeOrder) { unfreezeOrder.set_amount(1000000); const auto data = Binance::Signer(std::move(signingInput)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "a101f0625dee0a2b" "6515ff0d" "0a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e1120b" @@ -511,7 +511,7 @@ TEST(BinanceSigner, BuildTransferOutOrder) { token.set_amount(100000000); const auto data = Binance::Signer(std::move(input)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "b701f0625dee0a41800819c00a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e1121435552c16704d" "214347f29fa77f77da6d75d7c7521a0a0a03424e421080c2d72f20cec2f105126e0a26eb5ae9872103a9" "a55c040c8eb8120f3d1b32193250841c08af44ea561aac993dbe0f6b6a8fc712407eda148e1167b1be12" @@ -543,7 +543,7 @@ TEST(BinanceSigner, BuildSideChainDelegate) { token.set_amount(200000000); const auto data = Binance::Signer(std::move(input)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "ba01f0625dee0a44e3a07fd20a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e112147cc24a1de524" "5f14a95e457f903bcc8461ac869c1a0a0a03424e42108084af5f220663686170656c126e0a26eb5ae987" "2103a9a55c040c8eb8120f3d1b32193250841c08af44ea561aac993dbe0f6b6a8fc7124039302c9975fb" @@ -578,7 +578,7 @@ TEST(BinanceSigner, BuildSideChainRedelegate) { token.set_amount(100000000); const auto data = Binance::Signer(std::move(input)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "d001f0625dee0a5ae3ced3640a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e11214ce2e3593c138" "d51c38c7447227605d2f444a881e1a140fa0ad646c86d9171e36a68ba47fbc5e0b0dd078220a0a03424e" "421080c2d72f2a0663686170656c126e0a26eb5ae9872103a9a55c040c8eb8120f3d1b32193250841c08" @@ -611,7 +611,7 @@ TEST(BinanceSigner, BuildSideChainUndelegate) { token.set_amount(100000000); const auto data = Binance::Signer(std::move(input)).build(); - ASSERT_EQ(hex(data.begin(), data.end()), + ASSERT_EQ(hex(data), "ba01f0625dee0a44514f7e0e0a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e11214ce2e3593c138" "d51c38c7447227605d2f444a881e1a0a0a03424e421080c2d72f220663686170656c126e0a26eb5ae987" "2103a9a55c040c8eb8120f3d1b32193250841c08af44ea561aac993dbe0f6b6a8fc71240a622b7ca7a28" @@ -641,7 +641,7 @@ TEST(BinanceSigner, BuildTimeLockOrder) { lockOrder.set_lock_time(1600001371); const auto data = Binance::Signer(std::move(signingInput)).build(); - EXPECT_EQ(hex(data.begin(), data.end()), + EXPECT_EQ(hex(data), "bf01f0625dee0a49" "07921531" "0a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e1121c4465736372697074696f6e206c6f636b656420666f72206f666665721a090a03424e4210c0843d20dbaaf8fa05126e0a26eb5ae9872103a9a55c040c8eb8120f3d1b32193250841c08af44ea561aac993dbe0f6b6a8fc71240c270822b9515ba486c6a6b3472d388a5aea872ed960c0b53de0fafdc8682ef473a126f01e7dd2c00f04a0138a601b9540f54b14026846de362f7ab7f9fed948b180f2001" @@ -670,7 +670,7 @@ TEST(BinanceSigner, BuildTimeRelockOrder) { relockOrder.set_lock_time(1600001371); const auto data = Binance::Signer(std::move(signingInput)).build(); - EXPECT_EQ(hex(data.begin(), data.end()), + EXPECT_EQ(hex(data), "c201f0625dee0a4c504711da0a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e110cd021a1c446573" "6372697074696f6e206c6f636b656420666f72206f6666657222090a03424e4210c0843d28dbaaf8fa05" "126e0a26eb5ae9872103a9a55c040c8eb8120f3d1b32193250841c08af44ea561aac993dbe0f6b6a8fc7" @@ -695,7 +695,7 @@ TEST(BinanceSigner, BuildTimeUnlockOrder) { unlockOrder.set_id(333); const auto data = Binance::Signer(std::move(signingInput)).build(); - EXPECT_EQ(hex(data.begin(), data.end()), + EXPECT_EQ(hex(data), "9301f0625dee0a1dc4050c6c0a1408c7c918f6b72c3c0c21b7d08eb6fc66509998e110cd02126e0a26eb" "5ae9872103a9a55c040c8eb8120f3d1b32193250841c08af44ea561aac993dbe0f6b6a8fc71240da777b" "fd2032834f59ec9fe69fd6eaa4aca24242dfbc5ec4ef8c435cb9da7eb05ab78e1b8ca9f109657cb77996" diff --git a/tests/chains/BitcoinGold/TWBitcoinGoldTests.cpp b/tests/chains/BitcoinGold/TWBitcoinGoldTests.cpp index 760cd79b9a6..d0285c3b2c9 100644 --- a/tests/chains/BitcoinGold/TWBitcoinGoldTests.cpp +++ b/tests/chains/BitcoinGold/TWBitcoinGoldTests.cpp @@ -86,7 +86,7 @@ TEST(TWBitcoinGoldTxGeneration, TxGeneration) { auto scriptPub1 = Script(parse_hex("0014db746a75d9aae8995d135b1e19a04d7765242a8f")); auto scriptHash = std::vector(); scriptPub1.matchPayToWitnessPublicKeyHash(scriptHash); - auto scriptHashHex = hex(scriptHash.begin(), scriptHash.end()); + auto scriptHashHex = hex(scriptHash); auto redeemScript = Script::buildPayToPublicKeyHash(scriptHash); auto scriptString = std::string(redeemScript.bytes.begin(), redeemScript.bytes.end()); diff --git a/tests/chains/BitcoinGold/TWSignerTests.cpp b/tests/chains/BitcoinGold/TWSignerTests.cpp index 673e6437912..ad8497ffdf6 100644 --- a/tests/chains/BitcoinGold/TWSignerTests.cpp +++ b/tests/chains/BitcoinGold/TWSignerTests.cpp @@ -40,7 +40,7 @@ TEST(TWBitcoinGoldSigner, SignTransaction) { auto scriptPub1 = Script(parse_hex("0014db746a75d9aae8995d135b1e19a04d7765242a8f")); auto scriptHash = std::vector(); scriptPub1.matchPayToWitnessPublicKeyHash(scriptHash); - auto scriptHashHex = hex(scriptHash.begin(), scriptHash.end()); + auto scriptHashHex = hex(scriptHash); auto redeemScript = Script::buildPayToPublicKeyHash(scriptHash); auto scriptString = std::string(redeemScript.bytes.begin(), redeemScript.bytes.end()); diff --git a/tests/chains/Cosmos/AddressTests.cpp b/tests/chains/Cosmos/AddressTests.cpp index bcb2012b58e..a50d7596730 100644 --- a/tests/chains/Cosmos/AddressTests.cpp +++ b/tests/chains/Cosmos/AddressTests.cpp @@ -25,7 +25,7 @@ TEST(CosmosAddress, Invalid) { TEST(CosmosAddress, Cosmos_FromPublicKey) { auto privateKey = PrivateKey(parse_hex("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005")); auto publicKeyData = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); - ASSERT_EQ(hex(publicKeyData.bytes.begin(), publicKeyData.bytes.end()), "0257286ec3f37d33557bbbaa000b27744ac9023aa9967cae75a181d1ff91fa9dc5"); + ASSERT_EQ(hex(publicKeyData.bytes), "0257286ec3f37d33557bbbaa000b27744ac9023aa9967cae75a181d1ff91fa9dc5"); auto publicKey = PublicKey(publicKeyData); auto address = Address("cosmos", publicKey); @@ -56,7 +56,7 @@ TEST(CosmosAddress, Cosmos_Invalid) { TEST(CosmosAddress, ThorFromPublicKey) { auto privateKey = PrivateKey(parse_hex("7105512f0c020a1dd759e14b865ec0125f59ac31e34d7a2807a228ed50cb343e")); auto publicKeyData = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); - ASSERT_EQ(hex(publicKeyData.bytes.begin(), publicKeyData.bytes.end()), "03ed997e396cf4292f5fce5a42bba41599ccd5d96e313154a7c9ea7049de317c77"); + ASSERT_EQ(hex(publicKeyData.bytes), "03ed997e396cf4292f5fce5a42bba41599ccd5d96e313154a7c9ea7049de317c77"); auto publicKey = PublicKey(publicKeyData); auto address = Address("thor", publicKey); diff --git a/tests/chains/Decred/SignerTests.cpp b/tests/chains/Decred/SignerTests.cpp index 85cf02ea128..94e6a3f9b73 100644 --- a/tests/chains/Decred/SignerTests.cpp +++ b/tests/chains/Decred/SignerTests.cpp @@ -164,7 +164,7 @@ TEST(DecredSigner, SignP2SH) { auto redeemScript = Bitcoin::Script::buildPayToPublicKeyHash(keyhash); auto scriptHash = Hash::ripemd(Hash::sha256(redeemScript.bytes)); auto scriptString = std::string(redeemScript.bytes.begin(), redeemScript.bytes.end()); - (*input.mutable_scripts())[hex(scriptHash.begin(), scriptHash.end())] = scriptString; + (*input.mutable_scripts())[hex(scriptHash)] = scriptString; auto utxo0 = input.add_utxo(); auto utxo0Script = Bitcoin::Script::buildPayToScriptHash(scriptHash); @@ -401,7 +401,7 @@ TEST(DecredSigning, SignP2WPKH_NegativeAddressWrongType) { auto scriptPub1 = Bitcoin::Script(parse_hex("00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1")); auto scriptHash = std::vector(); scriptPub1.matchPayToWitnessPublicKeyHash(scriptHash); - auto scriptHashHex = hex(scriptHash.begin(), scriptHash.end()); + auto scriptHashHex = hex(scriptHash); ASSERT_EQ(scriptHashHex, "1d0f172a0ecb48aee1be1f2687d2963ae33f71a1"); auto redeemScript = Bitcoin::Script::buildPayToPublicKeyHash(scriptHash); diff --git a/tests/chains/Ethereum/AbiTests.cpp b/tests/chains/Ethereum/AbiTests.cpp index 3575dcb0f95..e23289a6446 100644 --- a/tests/chains/Ethereum/AbiTests.cpp +++ b/tests/chains/Ethereum/AbiTests.cpp @@ -1003,9 +1003,9 @@ TEST(EthereumAbi, EncodeSignature) { func.encode(encoded); EXPECT_EQ(encoded.size(), 32 * 2 + 4ul); - EXPECT_EQ(hex(encoded.begin(), encoded.begin() + 4), "72ed38b6"); - EXPECT_EQ(hex(encoded.begin() + 4, encoded.begin() + 36), "0000000000000000000000000000000000000000000000000000000000000045"); - EXPECT_EQ(hex(encoded.begin() + 36, encoded.begin() + 68), "0000000000000000000000000000000000000000000000000000000000000001"); + EXPECT_EQ(hex(data(encoded.begin(), encoded.begin() + 4)), "72ed38b6"); + EXPECT_EQ(hex(data(encoded.begin() + 4, encoded.begin() + 36)), "0000000000000000000000000000000000000000000000000000000000000045"); + EXPECT_EQ(hex(data(encoded.begin() + 36, encoded.begin() + 68)), "0000000000000000000000000000000000000000000000000000000000000001"); } TEST(EthereumAbi, EncodeFunctionWithDynamicArgumentsCase1) { @@ -1025,16 +1025,16 @@ TEST(EthereumAbi, EncodeFunctionWithDynamicArgumentsCase1) { func.encode(encoded); EXPECT_EQ(encoded.size(), 32 * 9 + 4ul); - EXPECT_EQ(hex(encoded.begin() + 0, encoded.begin() + 4), "a5643bf2"); - EXPECT_EQ(hex(encoded.begin() + 4, encoded.begin() + 36), "0000000000000000000000000000000000000000000000000000000000000060"); - EXPECT_EQ(hex(encoded.begin() + 36, encoded.begin() + 68), "0000000000000000000000000000000000000000000000000000000000000001"); - EXPECT_EQ(hex(encoded.begin() + 68, encoded.begin() + 100), "00000000000000000000000000000000000000000000000000000000000000a0"); - EXPECT_EQ(hex(encoded.begin() + 100, encoded.begin() + 132), "0000000000000000000000000000000000000000000000000000000000000004"); - EXPECT_EQ(hex(encoded.begin() + 132, encoded.begin() + 164), "6461766500000000000000000000000000000000000000000000000000000000"); - EXPECT_EQ(hex(encoded.begin() + 164, encoded.begin() + 196), "0000000000000000000000000000000000000000000000000000000000000003"); - EXPECT_EQ(hex(encoded.begin() + 196, encoded.begin() + 228), "0000000000000000000000000000000000000000000000000000000000000001"); - EXPECT_EQ(hex(encoded.begin() + 228, encoded.begin() + 260), "0000000000000000000000000000000000000000000000000000000000000002"); - EXPECT_EQ(hex(encoded.begin() + 260, encoded.begin() + 292), "0000000000000000000000000000000000000000000000000000000000000003"); + EXPECT_EQ(hex(data(encoded.begin() + 0, encoded.begin() + 4)), "a5643bf2"); + EXPECT_EQ(hex(data(encoded.begin() + 4, encoded.begin() + 36)), "0000000000000000000000000000000000000000000000000000000000000060"); + EXPECT_EQ(hex(data(encoded.begin() + 36, encoded.begin() + 68)), "0000000000000000000000000000000000000000000000000000000000000001"); + EXPECT_EQ(hex(data(encoded.begin() + 68, encoded.begin() + 100)), "00000000000000000000000000000000000000000000000000000000000000a0"); + EXPECT_EQ(hex(data(encoded.begin() + 100, encoded.begin() + 132)), "0000000000000000000000000000000000000000000000000000000000000004"); + EXPECT_EQ(hex(data(encoded.begin() + 132, encoded.begin() + 164)), "6461766500000000000000000000000000000000000000000000000000000000"); + EXPECT_EQ(hex(data(encoded.begin() + 164, encoded.begin() + 196)), "0000000000000000000000000000000000000000000000000000000000000003"); + EXPECT_EQ(hex(data(encoded.begin() + 196, encoded.begin() + 228)), "0000000000000000000000000000000000000000000000000000000000000001"); + EXPECT_EQ(hex(data(encoded.begin() + 228, encoded.begin() + 260)), "0000000000000000000000000000000000000000000000000000000000000002"); + EXPECT_EQ(hex(data(encoded.begin() + 260, encoded.begin() + 292)), "0000000000000000000000000000000000000000000000000000000000000003"); } TEST(EthereumAbi, EncodeFunctionWithDynamicArgumentsCase2) { @@ -1053,16 +1053,16 @@ TEST(EthereumAbi, EncodeFunctionWithDynamicArgumentsCase2) { func.encode(encoded); EXPECT_EQ(encoded.size(), 32 * 9 + 4ul); - EXPECT_EQ(hex(encoded.begin() + 0, encoded.begin() + 4), "47b941bf"); - EXPECT_EQ(hex(encoded.begin() + 4, encoded.begin() + 36), "0000000000000000000000000000000000000000000000000000000000000123"); - EXPECT_EQ(hex(encoded.begin() + 36, encoded.begin() + 68), "0000000000000000000000000000000000000000000000000000000000000080"); - EXPECT_EQ(hex(encoded.begin() + 68, encoded.begin() + 100), "3132333435363738393000000000000000000000000000000000000000000000"); - EXPECT_EQ(hex(encoded.begin() + 100, encoded.begin() + 132), "00000000000000000000000000000000000000000000000000000000000000e0"); - EXPECT_EQ(hex(encoded.begin() + 132, encoded.begin() + 164), "0000000000000000000000000000000000000000000000000000000000000002"); - EXPECT_EQ(hex(encoded.begin() + 164, encoded.begin() + 196), "0000000000000000000000000000000000000000000000000000000000000456"); - EXPECT_EQ(hex(encoded.begin() + 196, encoded.begin() + 228), "0000000000000000000000000000000000000000000000000000000000000789"); - EXPECT_EQ(hex(encoded.begin() + 228, encoded.begin() + 260), "000000000000000000000000000000000000000000000000000000000000000d"); - EXPECT_EQ(hex(encoded.begin() + 260, encoded.begin() + 292), "48656c6c6f2c20776f726c642100000000000000000000000000000000000000"); + EXPECT_EQ(hex(data(encoded.begin() + 0, encoded.begin() + 4)), "47b941bf"); + EXPECT_EQ(hex(data(encoded.begin() + 4, encoded.begin() + 36)), "0000000000000000000000000000000000000000000000000000000000000123"); + EXPECT_EQ(hex(data(encoded.begin() + 36, encoded.begin() + 68)), "0000000000000000000000000000000000000000000000000000000000000080"); + EXPECT_EQ(hex(data(encoded.begin() + 68, encoded.begin() + 100)), "3132333435363738393000000000000000000000000000000000000000000000"); + EXPECT_EQ(hex(data(encoded.begin() + 100, encoded.begin() + 132)), "00000000000000000000000000000000000000000000000000000000000000e0"); + EXPECT_EQ(hex(data(encoded.begin() + 132, encoded.begin() + 164)), "0000000000000000000000000000000000000000000000000000000000000002"); + EXPECT_EQ(hex(data(encoded.begin() + 164, encoded.begin() + 196)), "0000000000000000000000000000000000000000000000000000000000000456"); + EXPECT_EQ(hex(data(encoded.begin() + 196, encoded.begin() + 228)), "0000000000000000000000000000000000000000000000000000000000000789"); + EXPECT_EQ(hex(data(encoded.begin() + 228, encoded.begin() + 260)), "000000000000000000000000000000000000000000000000000000000000000d"); + EXPECT_EQ(hex(data(encoded.begin() + 260, encoded.begin() + 292)), "48656c6c6f2c20776f726c642100000000000000000000000000000000000000"); } TEST(EthereumAbi, DecodeFunctionOutputCase1) { diff --git a/tests/chains/Groestlcoin/TWGroestlcoinSigningTests.cpp b/tests/chains/Groestlcoin/TWGroestlcoinSigningTests.cpp index 4134ab277f7..6593cb41c1d 100644 --- a/tests/chains/Groestlcoin/TWGroestlcoinSigningTests.cpp +++ b/tests/chains/Groestlcoin/TWGroestlcoinSigningTests.cpp @@ -120,14 +120,14 @@ TEST(GroestlcoinSigning, SignP2SH_P2WPKH) { auto utxoKey0 = PrivateKey(parse_hex("302fc195a8fc96c5a581471e67e4c1ac2efda252f76ad5c77a53764c70d58f91")); auto pubKey0 = utxoKey0.getPublicKey(TWPublicKeyTypeSECP256k1); auto utxoPubkeyHash = Hash::ripemd(Hash::sha256(pubKey0.bytes)); - EXPECT_EQ(hex(utxoPubkeyHash.begin(), utxoPubkeyHash.end()), "2fc7d70acef142d1f7b5ef2f20b1a9b759797674"); + EXPECT_EQ(hex(utxoPubkeyHash), "2fc7d70acef142d1f7b5ef2f20b1a9b759797674"); input.add_private_key(utxoKey0.bytes.data(), utxoKey0.bytes.size()); auto redeemScript = Script::buildPayToWitnessPublicKeyHash(utxoPubkeyHash); auto scriptHash = Hash::ripemd(Hash::sha256(redeemScript.bytes)); - ASSERT_EQ(hex(scriptHash.begin(), scriptHash.end()), "0055b0c94df477ee6b9f75185dfc9aa8ce2e52e4"); + ASSERT_EQ(hex(scriptHash), "0055b0c94df477ee6b9f75185dfc9aa8ce2e52e4"); auto scriptString = std::string(redeemScript.bytes.begin(), redeemScript.bytes.end()); - (*input.mutable_scripts())[hex(scriptHash.begin(), scriptHash.end())] = scriptString; + (*input.mutable_scripts())[hex(scriptHash)] = scriptString; auto utxo0 = input.add_utxo(); auto utxo0Script = Script(parse_hex("a9140055b0c94df477ee6b9f75185dfc9aa8ce2e52e487")); diff --git a/tests/chains/IoTeX/SignerTests.cpp b/tests/chains/IoTeX/SignerTests.cpp index 43a5c5ee22f..c0c78a5ea99 100644 --- a/tests/chains/IoTeX/SignerTests.cpp +++ b/tests/chains/IoTeX/SignerTests.cpp @@ -30,9 +30,9 @@ TEST(IoTeXSigner, Sign) { auto signer = IoTeX::Signer(std::move(input)); auto h = signer.hash(); - ASSERT_EQ(hex(h.begin(), h.end()), "0f17cd7f43bdbeff73dfe8f5cb0c0045f2990884e5050841de887cf22ca35b50"); + ASSERT_EQ(hex(h), "0f17cd7f43bdbeff73dfe8f5cb0c0045f2990884e5050841de887cf22ca35b50"); auto sig = signer.sign(); - ASSERT_EQ(hex(sig.begin(), sig.end()), "555cc8af4181bf85c044c3201462eeeb95374f78aa48c67b87510ee63d5e502372e53082f03e9a11c1e351de539cedf85d8dff87de9d003cb9f92243541541a000"); + ASSERT_EQ(hex(sig), "555cc8af4181bf85c044c3201462eeeb95374f78aa48c67b87510ee63d5e502372e53082f03e9a11c1e351de539cedf85d8dff87de9d003cb9f92243541541a000"); } TEST(IoTeXSigner, Build) { @@ -52,9 +52,9 @@ TEST(IoTeXSigner, Build) { auto signer = IoTeX::Signer(std::move(input)); auto output = signer.build(); auto encoded = output.encoded(); // signed action's serialized bytes - ASSERT_EQ(hex(encoded.begin(), encoded.end()), "0a4c0801107b18f8062203393939523e0a033435361229696f313837777a703038766e686a6a706b79646e723937716c68386b683064706b6b797466616d386a1a0c68656c6c6f20776f726c64211241044e18306ae9ef4ec9d07bf6e705442d4d1a75e6cdf750330ca2d880f2cc54607c9c33deb9eae9c06e06e04fe9ce3d43962cc67d5aa34fbeb71270d4bad3d648d91a41555cc8af4181bf85c044c3201462eeeb95374f78aa48c67b87510ee63d5e502372e53082f03e9a11c1e351de539cedf85d8dff87de9d003cb9f92243541541a000"); + ASSERT_EQ(hex(encoded), "0a4c0801107b18f8062203393939523e0a033435361229696f313837777a703038766e686a6a706b79646e723937716c68386b683064706b6b797466616d386a1a0c68656c6c6f20776f726c64211241044e18306ae9ef4ec9d07bf6e705442d4d1a75e6cdf750330ca2d880f2cc54607c9c33deb9eae9c06e06e04fe9ce3d43962cc67d5aa34fbeb71270d4bad3d648d91a41555cc8af4181bf85c044c3201462eeeb95374f78aa48c67b87510ee63d5e502372e53082f03e9a11c1e351de539cedf85d8dff87de9d003cb9f92243541541a000"); auto h = output.hash(); // signed action's hash - ASSERT_EQ(hex(h.begin(), h.end()), "6c84ac119058e859a015221f87a4e187c393d0c6ee283959342eac95fad08c33"); + ASSERT_EQ(hex(h), "6c84ac119058e859a015221f87a4e187c393d0c6ee283959342eac95fad08c33"); } } // namespace TW::IoTeX diff --git a/tests/chains/Ontology/Oep4Tests.cpp b/tests/chains/Ontology/Oep4Tests.cpp index be49303bd69..3a2513151ef 100644 --- a/tests/chains/Ontology/Oep4Tests.cpp +++ b/tests/chains/Ontology/Oep4Tests.cpp @@ -15,7 +15,7 @@ namespace TW::Ontology::tests { TEST(OntologyOep4, name) { std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; - auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + auto wing_addr = Address(parse_hex(wing_hex)); Oep4 wing(wing_addr); uint32_t nonce = 0x1234; @@ -26,7 +26,7 @@ TEST(OntologyOep4, name) { TEST(OntologyOep4, symbol) { std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; - auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + auto wing_addr = Address(parse_hex(wing_hex)); Oep4 wing(wing_addr); uint32_t nonce = 0x1234; @@ -37,7 +37,7 @@ TEST(OntologyOep4, symbol) { TEST(OntologyOep4, decimals) { std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; - auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + auto wing_addr = Address(parse_hex(wing_hex)); Oep4 wing(wing_addr); uint32_t nonce = 0x1234; @@ -48,7 +48,7 @@ TEST(OntologyOep4, decimals) { TEST(OntologyOep4, totalSupply) { std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; - auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + auto wing_addr = Address(parse_hex(wing_hex)); Oep4 wing(wing_addr); uint32_t nonce = 0x1234; @@ -59,7 +59,7 @@ TEST(OntologyOep4, totalSupply) { TEST(OntologyOep4, balanceOf) { std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; - auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + auto wing_addr = Address(parse_hex(wing_hex)); Oep4 wing(wing_addr); auto user = Address("AeaThtPwh5kAYnjHavzwmvxPd725nVTvbM"); @@ -101,7 +101,7 @@ TEST(OntologyOep4, transfer) { uint64_t gasLimit = 50000; std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; - auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + auto wing_addr = Address(parse_hex(wing_hex)); Oep4 wing(wing_addr); auto tx = wing.transfer(from, toAddress, amount, payer, gasPrice, gasLimit, nonce); @@ -127,7 +127,7 @@ TEST(OntologyOep4, transferMainnet) { // wing oep4 mainnet address std::string wing_hex{"00c59fcd27a562d6397883eab1f2fff56e58ef80"}; - auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + auto wing_addr = Address(parse_hex(wing_hex)); Oep4 wing(wing_addr); auto tx = wing.transfer(from, toAddress, amount, payer, gasPrice, gasLimit, nonce); diff --git a/tests/chains/Ontology/ParamsBuilderTests.cpp b/tests/chains/Ontology/ParamsBuilderTests.cpp index 0534472852d..c9a4bc02ae5 100644 --- a/tests/chains/Ontology/ParamsBuilderTests.cpp +++ b/tests/chains/Ontology/ParamsBuilderTests.cpp @@ -84,7 +84,7 @@ TEST(ParamsBuilder, transferInvokeCode) { TEST(ParamsBuilder, invokeOep4Code) { std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; - auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + auto wing_addr = Address(parse_hex(wing_hex)); NeoVmParamValue::ParamArray args{}; std::string method{"name"}; @@ -96,7 +96,7 @@ TEST(ParamsBuilder, invokeOep4Code) { TEST(ParamsBuilder, invokeOep4CodeBalanceOf) { std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; - auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + auto wing_addr = Address(parse_hex(wing_hex)); auto user_addr = Address("AeaThtPwh5kAYnjHavzwmvxPd725nVTvbM"); Data d(std::begin(user_addr._data), std::end(user_addr._data)); @@ -110,7 +110,7 @@ TEST(ParamsBuilder, invokeOep4CodeBalanceOf) { TEST(OntologyOep4, invokeOep4CodeTransfer) { std::string wing_hex{"ff31ec74d01f7b7d45ed2add930f5d2239f7de33"}; - auto wing_addr = Address(parse_hex(wing_hex.begin(), wing_hex.end())); + auto wing_addr = Address(parse_hex(wing_hex)); auto from = Address("APniYDGozkhUh8Tk7pe35aah2HGJ4fJfVd"); auto to = Address("AVY6LfvxauVQAVHDV9hC3ZCv7cQqzfDotH"); uint64_t amount = 253; diff --git a/tests/chains/Tezos/ForgingTests.cpp b/tests/chains/Tezos/ForgingTests.cpp index 66187be27d2..ab781bb4558 100644 --- a/tests/chains/Tezos/ForgingTests.cpp +++ b/tests/chains/Tezos/ForgingTests.cpp @@ -151,7 +151,7 @@ TEST(TezosTransaction, forgeTransaction) { auto expected = "6c0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80992f001f44e81020100008fb5cea62d147c696afd9a93dbce962f4c8a9c9100"; auto serialized = forgeOperation(transactionOperation); - ASSERT_EQ(hex(serialized.begin(), serialized.end()), expected); + ASSERT_EQ(hex(serialized), expected); } TEST(TezosTransaction, forgeTransactionFA12) { @@ -222,7 +222,7 @@ TEST(TezosTransaction, forgeReveal) { auto expected = "6b0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80992f001f44e810200429a986c8072a40a1f3a3e2ab5a5819bb1b2fb69993c5004837815b9dc55923e"; auto serialized = forgeOperation(revealOperation); - ASSERT_EQ(hex(serialized.begin(), serialized.end()), expected); + ASSERT_EQ(hex(serialized), expected); } TEST(TezosTransaction, forgeDelegate) { @@ -241,7 +241,7 @@ TEST(TezosTransaction, forgeDelegate) { auto expected = "6e0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80992f001f44e8102ff003e47f837f0467b4acde406ed5842f35e2414b1a8"; auto serialized = forgeOperation(delegateOperation); - ASSERT_EQ(hex(serialized.begin(), serialized.end()), expected); + ASSERT_EQ(hex(serialized), expected); } TEST(TezosTransaction, forgeUndelegate) { @@ -260,7 +260,7 @@ TEST(TezosTransaction, forgeUndelegate) { auto expected = "6e0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80992f001f44e810200"; auto serialized = forgeOperation(delegateOperation); - ASSERT_EQ(hex(serialized.begin(), serialized.end()), expected); + ASSERT_EQ(hex(serialized), expected); } } // namespace TW::Tezos::tests diff --git a/tests/chains/Tezos/OperationListTests.cpp b/tests/chains/Tezos/OperationListTests.cpp index 9fb89d9e8a6..17259ed9f41 100644 --- a/tests/chains/Tezos/OperationListTests.cpp +++ b/tests/chains/Tezos/OperationListTests.cpp @@ -43,7 +43,7 @@ TEST(TezosOperationList, ForgeOperationList_TransactionOnly) { auto expected = "3756ef37b1be849e3114643f0aa5847cabf9a896d3bfe4dd51448de68e91da016c0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80992f001f44e81020100008fb5cea62d147c696afd9a93dbce962f4c8a9c9100"; auto forged = op_list.forge(key); - ASSERT_EQ(hex(forged.begin(), forged.end()), expected); + ASSERT_EQ(hex(forged), expected); } TEST(TezosOperationList, ForgeOperationList_RevealOnly) { @@ -68,7 +68,7 @@ TEST(TezosOperationList, ForgeOperationList_RevealOnly) { auto expected = "3756ef37b1be849e3114643f0aa5847cabf9a896d3bfe4dd51448de68e91da016b0081faa75f741ef614b0e35fcc8c90dfa3b0b95721f80992f001f44e810200429a986c8072a40a1f3a3e2ab5a5819bb1b2fb69993c5004837815b9dc55923e"; auto forged = op_list.forge(key); - ASSERT_EQ(hex(forged.begin(), forged.end()), expected); + ASSERT_EQ(hex(forged), expected); } TEST(TezosOperationList, ForgeOperationList_Delegation_ClearDelegate) { @@ -112,7 +112,7 @@ TEST(TezosOperationList, ForgeOperationList_Delegation_AddDelegate) { op_list.addOperation(delegationOperation); auto expected = "7105102c032807994dd9b5edf219261896a559876ca16cbf9d31dbe3612b89f26e00315b1206ec00b1b1e64cc3b8b93059f58fa2fc39e90944904e00ff00c4650fd609f88c67356e5fe01e37cd3ff654b18c"; auto forged = op_list.forge(key); - ASSERT_EQ(hex(forged.begin(), forged.end()), expected); + ASSERT_EQ(hex(forged), expected); } TEST(TezosOperationList, ForgeOperationList_TransactionAndReveal) { @@ -152,7 +152,7 @@ TEST(TezosOperationList, ForgeOperationList_TransactionAndReveal) { auto expected = "3756ef37b1be849e3114643f0aa5847cabf9a896d3bfe4dd51448de68e91da016b003e47f837f0467b4acde406ed5842f35e2414b1a8f80992f001f44e810200603247bbf52501498293686da89ad8b2aca85f83b90903d4521dd2aba66054eb6c003e47f837f0467b4acde406ed5842f35e2414b1a8f80993f001f44e8102010000e42504da69a7c8d5baeaaeebe157a02db6b22ed800"; auto forged = op_list.forge(key); - ASSERT_EQ(hex(forged.begin(), forged.end()), expected); + ASSERT_EQ(hex(forged), expected); } TEST(TezosOperationList, ForgeOperationList_RevealWithoutPublicKey) { @@ -176,7 +176,7 @@ TEST(TezosOperationList, ForgeOperationList_RevealWithoutPublicKey) { auto expected = "3756ef37b1be849e3114643f0aa5847cabf9a896d3bfe4dd51448de68e91da016b003e47f837f0467b4acde406ed5842f35e2414b1a8f80992f001f44e810200603247bbf52501498293686da89ad8b2aca85f83b90903d4521dd2aba66054eb"; auto forged = op_list.forge(key); - ASSERT_EQ(hex(forged.begin(), forged.end()), expected); + ASSERT_EQ(hex(forged), expected); } } // namespace TW::Tezos::tests diff --git a/tests/chains/Tezos/PublicKeyTests.cpp b/tests/chains/Tezos/PublicKeyTests.cpp index 66c7087dc7e..1048390b6c2 100644 --- a/tests/chains/Tezos/PublicKeyTests.cpp +++ b/tests/chains/Tezos/PublicKeyTests.cpp @@ -18,7 +18,7 @@ TEST(TezosPublicKey, forge) { auto input = parsePublicKey("edpkuAfEJCEatRgFpRGg3gn3FdWniLXBoubARreRwuVZPWufkgDBvR"); auto expected = "00451bde832454ba73e6e0de313fcf5d1565ec51080edc73bb19287b8e0ab2122b"; auto serialized = forgePublicKey(input); - ASSERT_EQ(hex(serialized.begin(), serialized.end()), expected); + ASSERT_EQ(hex(serialized), expected); } TEST(TezosPublicKey, parse) { diff --git a/tests/chains/Tezos/SignerTests.cpp b/tests/chains/Tezos/SignerTests.cpp index 92681344646..eb024a36721 100644 --- a/tests/chains/Tezos/SignerTests.cpp +++ b/tests/chains/Tezos/SignerTests.cpp @@ -86,9 +86,9 @@ TEST(TezosSigner, SignOperationList) { std::string expectedSignedBytes = expectedForgedBytesToSign + expectedSignature; auto signedBytes = Signer().signOperationList(key, op_list); - auto signedBytesHex = hex(signedBytes.begin(), signedBytes.end()); + auto signedBytesHex = hex(signedBytes); - ASSERT_EQ(hex(signedBytes.begin(), signedBytes.end()), expectedSignedBytes); + ASSERT_EQ(hex(signedBytes), expectedSignedBytes); } } // namespace TW::Tezos::tests diff --git a/tests/chains/Zcash/TWZcashTransactionTests.cpp b/tests/chains/Zcash/TWZcashTransactionTests.cpp index b0acaf0f132..aae9fc24cd8 100644 --- a/tests/chains/Zcash/TWZcashTransactionTests.cpp +++ b/tests/chains/Zcash/TWZcashTransactionTests.cpp @@ -42,7 +42,7 @@ TEST(TWZcashTransaction, Encode) { auto unsignedData = Data{}; transaction.encode(unsignedData); - ASSERT_EQ(hex(unsignedData.begin(), unsignedData.end()), + ASSERT_EQ(hex(unsignedData), /* header */ "04000080" /* versionGroupId */ "85202f89" /* vin */ "01""a8c685478265f4c14dada651969c45a65e1aeb8cd6791f2f5bb6a1d9952104d9""01000000""6b483045022100a61e5d557568c2ddc1d9b03a7173c6ce7c996c4daecab007ac8f34bee01e6b9702204d38fdc0bcf2728a69fde78462a10fb45a9baa27873e6a5fc45fb5c76764202a01210365ffea3efa3908918a8b8627724af852fc9b86d7375b103ab0543cf418bcaa7f""feffffff" @@ -58,7 +58,7 @@ TEST(TWZcashTransaction, Encode) { auto scriptCode = Bitcoin::Script(parse_hex("76a914507173527b4c3318a2aecd793bf1cfed705950cf88ac")); auto preImage = transaction.getPreImage(scriptCode, 0, TWBitcoinSigHashTypeAll, 0x02faf080); - ASSERT_EQ(hex(preImage.begin(), preImage.end()), + ASSERT_EQ(hex(preImage), /* header */ "04000080" /* versionGroupId */ "85202f89" /* hashPrevouts */ "fae31b8dec7b0b77e2c8d6b6eb0e7e4e55abc6574c26dd44464d9408a8e33f11" @@ -78,7 +78,7 @@ TEST(TWZcashTransaction, Encode) { ); auto sighash = transaction.getSignatureHash(scriptCode, 0, TWBitcoinSigHashTypeAll, 0x02faf080, Bitcoin::BASE); - ASSERT_EQ(hex(sighash.begin(), sighash.end()), "f3148f80dfab5e573d5edfe7a850f5fd39234f80b5429d3a57edcc11e34c585b"); + ASSERT_EQ(hex(sighash), "f3148f80dfab5e573d5edfe7a850f5fd39234f80b5429d3a57edcc11e34c585b"); } TEST(TWZcashTransaction, SaplingSigning) { diff --git a/tests/chains/Zelcash/TWZelcashTransactionTests.cpp b/tests/chains/Zelcash/TWZelcashTransactionTests.cpp index 74f3413670e..bf90d832ae4 100644 --- a/tests/chains/Zelcash/TWZelcashTransactionTests.cpp +++ b/tests/chains/Zelcash/TWZelcashTransactionTests.cpp @@ -40,7 +40,7 @@ TEST(TWZelcashTransaction, Encode) { auto unsignedData = Data{}; transaction.encode(unsignedData); - ASSERT_EQ(hex(unsignedData.begin(), unsignedData.end()), + ASSERT_EQ(hex(unsignedData), /* header */ "04000080" /* versionGroupId */ "85202f89" /* vin */ "01""a8c685478265f4c14dada651969c45a65e1aeb8cd6791f2f5bb6a1d9952104d9""01000000""6b483045022100a61e5d557568c2ddc1d9b03a7173c6ce7c996c4daecab007ac8f34bee01e6b9702204d38fdc0bcf2728a69fde78462a10fb45a9baa27873e6a5fc45fb5c76764202a01210365ffea3efa3908918a8b8627724af852fc9b86d7375b103ab0543cf418bcaa7f""feffffff" @@ -56,7 +56,7 @@ TEST(TWZelcashTransaction, Encode) { auto scriptCode = Bitcoin::Script(parse_hex("76a914507173527b4c3318a2aecd793bf1cfed705950cf88ac")); auto preImage = transaction.getPreImage(scriptCode, 0, TWBitcoinSigHashTypeAll, 0x02faf080); - ASSERT_EQ(hex(preImage.begin(), preImage.end()), + ASSERT_EQ(hex(preImage), /* header */ "04000080" /* versionGroupId */ "85202f89" /* hashPrevouts */ "fae31b8dec7b0b77e2c8d6b6eb0e7e4e55abc6574c26dd44464d9408a8e33f11" @@ -76,7 +76,7 @@ TEST(TWZelcashTransaction, Encode) { ); auto sighash = transaction.getSignatureHash(scriptCode, 0, TWBitcoinSigHashTypeAll, 0x02faf080, Bitcoin::BASE); - ASSERT_EQ(hex(sighash.begin(), sighash.end()), "f3148f80dfab5e573d5edfe7a850f5fd39234f80b5429d3a57edcc11e34c585b"); + ASSERT_EQ(hex(sighash), "f3148f80dfab5e573d5edfe7a850f5fd39234f80b5429d3a57edcc11e34c585b"); } TEST(TWZelcashTransaction, Signing) { diff --git a/tests/chains/Zilliqa/SignerTests.cpp b/tests/chains/Zilliqa/SignerTests.cpp index 5c49cf46952..5e7ef3accc5 100644 --- a/tests/chains/Zilliqa/SignerTests.cpp +++ b/tests/chains/Zilliqa/SignerTests.cpp @@ -42,7 +42,7 @@ TEST(ZilliqaSigner, PreImage) { auto preImage = Signer::getPreImage(input, address); auto signature = Signer::sign(input).signature(); - ASSERT_EQ(hex(preImage.begin(), preImage.end()), "0881800410041a149ca91eb535fb92fda5094110fdaeb752edb9b03922230a21034ae47910d58b9bde819c3cffa8de4441955508db00aa2540db8e6bf6e99abc1b2a120a10000000000000000000000da475abf00032120a100000000000000000000000003b9aca003801"); + ASSERT_EQ(hex(preImage), "0881800410041a149ca91eb535fb92fda5094110fdaeb752edb9b03922230a21034ae47910d58b9bde819c3cffa8de4441955508db00aa2540db8e6bf6e99abc1b2a120a10000000000000000000000da475abf00032120a100000000000000000000000003b9aca003801"); ASSERT_TRUE(pubKey.verifyZilliqa(Data(signature.begin(), signature.end()), preImage)); } @@ -72,7 +72,7 @@ TEST(ZilliqaSigner, Signing) { auto output = Signer::sign(input); - ASSERT_EQ(hex(output.signature().begin(), output.signature().end()), "001fa4df08c11a4a79e96e69399ee48eeecc78231a78b0355a8ca783c77c139436e37934fecc2252ed8dac00e235e22d18410461fb896685c4270642738ed268"); + ASSERT_EQ(hex(output.signature()), "001fa4df08c11a4a79e96e69399ee48eeecc78231a78b0355a8ca783c77c139436e37934fecc2252ed8dac00e235e22d18410461fb896685c4270642738ed268"); ASSERT_EQ(output.json(), R"({"amount":"1000000000000","code":"","data":"","gasLimit":"1","gasPrice":"1000000000","nonce":2,"pubKey":"03fb30b196ce3e976593ecc2da220dca9cdea8c84d2373770042a930b892ac0f5c","signature":"001fa4df08c11a4a79e96e69399ee48eeecc78231a78b0355a8ca783c77c139436e37934fecc2252ed8dac00e235e22d18410461fb896685c4270642738ed268","toAddr":"7FCcaCf066a5F26Ee3AFfc2ED1FA9810Deaa632C","version":65537})"); } @@ -105,7 +105,7 @@ TEST(ZilliqaSigner, SigningData) { auto output = Signer::sign(input); ASSERT_EQ(output.json(), R"({"amount":"10000000000000","code":"","data":"{\"_tag\":\"DelegateStake\",\"params\":[{\"type\":\"ByStr20\",\"value\":\"0x122219cCeAb410901e96c3A0e55E46231480341b\",\"vname\":\"ssnaddr\"}]}","gasLimit":"5000","gasPrice":"2000000000","nonce":56,"pubKey":"03fb30b196ce3e976593ecc2da220dca9cdea8c84d2373770042a930b892ac0f5c","signature":"437fb5c3ce2c6b01f9d490f670539fae4533c82a21fa7edfe6b23df70d732937e8c578c8d6ed24be9150f5126f7b7c977a467af8947ef92a720908a761a6eb0d","toAddr":"43D459eC504C7432959c086B0ac7F7855E984306","version":65537})"); - ASSERT_EQ(hex(output.signature().begin(), output.signature().end()), "437fb5c3ce2c6b01f9d490f670539fae4533c82a21fa7edfe6b23df70d732937e8c578c8d6ed24be9150f5126f7b7c977a467af8947ef92a720908a761a6eb0d"); + ASSERT_EQ(hex(output.signature()), "437fb5c3ce2c6b01f9d490f670539fae4533c82a21fa7edfe6b23df70d732937e8c578c8d6ed24be9150f5126f7b7c977a467af8947ef92a720908a761a6eb0d"); } -} // namespace TW::Zilliqa::tests \ No newline at end of file +} // namespace TW::Zilliqa::tests diff --git a/tests/common/Bech32AddressTests.cpp b/tests/common/Bech32AddressTests.cpp index 7152fd9ce78..844d8a7276f 100644 --- a/tests/common/Bech32AddressTests.cpp +++ b/tests/common/Bech32AddressTests.cpp @@ -103,14 +103,14 @@ TEST(Bech32Address, FromPublicKey) { { auto privateKey = PrivateKey(parse_hex("95949f757db1f57ca94a5dff23314accbe7abee89597bf6a3c7382c84d7eb832")); auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); - ASSERT_EQ(hex(publicKey.bytes.begin(), publicKey.bytes.end()), "026a35920088d98c3888ca68c53dfc93f4564602606cbb87f0fe5ee533db38e502"); + ASSERT_EQ(hex(publicKey.bytes), "026a35920088d98c3888ca68c53dfc93f4564602606cbb87f0fe5ee533db38e502"); auto address = Bech32Address("bnb", Hash::HasherSha256ripemd, publicKey); ASSERT_EQ("bnb1grpf0955h0ykzq3ar5nmum7y6gdfl6lxfn46h2", address.string()); } { auto privateKey = PrivateKey(parse_hex("80e81ea269e66a0a05b11236df7919fb7fbeedba87452d667489d7403a02f005")); auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); - ASSERT_EQ(hex(publicKey.bytes.begin(), publicKey.bytes.end()), "0257286ec3f37d33557bbbaa000b27744ac9023aa9967cae75a181d1ff91fa9dc5"); + ASSERT_EQ(hex(publicKey.bytes), "0257286ec3f37d33557bbbaa000b27744ac9023aa9967cae75a181d1ff91fa9dc5"); auto address = Bech32Address("cosmos", Hash::HasherSha256ripemd, publicKey); ASSERT_EQ(address.string(), "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02"); } @@ -129,7 +129,7 @@ TEST(Bech32Address, FromPublicKey) { { const auto privateKey = PrivateKey(parse_hex("3382266517e2ebe6df51faf4bfe612236ad46fb8bd59ac982a223b045e080ac6")); auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); - ASSERT_EQ(hex(publicKey.bytes.begin(), publicKey.bytes.end()), "02b65744e8bd0ba7666468abaff2aeb862c88a25ed605e0153100aa8f2661c1c3d"); + ASSERT_EQ(hex(publicKey.bytes), "02b65744e8bd0ba7666468abaff2aeb862c88a25ed605e0153100aa8f2661c1c3d"); const auto address = Bech32Address("zil", Hash::HasherSha256, publicKey); ASSERT_EQ("zil", address.getHrp()); ASSERT_EQ("zil1j8xae6lggm8y63m3y2r7aefu797ze7mhzulnqg", address.string()); @@ -141,7 +141,7 @@ TEST(Bech32Address, Hashes) { const auto privateKey = PrivateKey(parse_hex("3382266517e2ebe6df51faf4bfe612236ad46fb8bd59ac982a223b045e080ac6")); auto publicKey1 = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); - ASSERT_EQ("02b65744e8bd0ba7666468abaff2aeb862c88a25ed605e0153100aa8f2661c1c3d", hex(publicKey1.bytes.begin(), publicKey1.bytes.end())); + ASSERT_EQ("02b65744e8bd0ba7666468abaff2aeb862c88a25ed605e0153100aa8f2661c1c3d", hex(publicKey1.bytes)); const auto address1 = Bech32Address("hrp", Hash::HasherSha256ripemd, publicKey1); ASSERT_EQ("hrp186zwn9h0z9fyvwfqs4jl92cw3kexusm4xw6ptp", address1.string()); @@ -152,7 +152,7 @@ TEST(Bech32Address, Hashes) { auto publicKey2 = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1Extended); ASSERT_EQ( "04b65744e8bd0ba7666468abaff2aeb862c88a25ed605e0153100aa8f2661c1c3d83c307736082c09f1f22328e0fbeab40ddd198cf0f70fcdaa1e5969ca400c098", - hex(publicKey2.bytes.begin(), publicKey2.bytes.end())); + hex(publicKey2.bytes)); const auto address3 = Bech32Address("hrp", Hash::HasherKeccak256, publicKey2); ASSERT_EQ("hrp17hff3s97m5uxpjcdq3nzqxxatt8cmumnsf03su", address3.string()); @@ -163,7 +163,7 @@ TEST(Bech32Address, Prefixes) { const auto privateKey = PrivateKey(parse_hex("3382266517e2ebe6df51faf4bfe612236ad46fb8bd59ac982a223b045e080ac6")); auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeSECP256k1); - ASSERT_EQ("02b65744e8bd0ba7666468abaff2aeb862c88a25ed605e0153100aa8f2661c1c3d", hex(publicKey.bytes.begin(), publicKey.bytes.end())); + ASSERT_EQ("02b65744e8bd0ba7666468abaff2aeb862c88a25ed605e0153100aa8f2661c1c3d", hex(publicKey.bytes)); const auto address1 = Bech32Address("hrpone", Hash::HasherSha256ripemd, publicKey); ASSERT_EQ("hrpone186zwn9h0z9fyvwfqs4jl92cw3kexusm47das6p", address1.string()); diff --git a/tools/generate-files b/tools/generate-files index 70825c15aaa..ee90c777168 100755 --- a/tools/generate-files +++ b/tools/generate-files @@ -53,10 +53,10 @@ codegen/bin/codegen tools/doxygen_convert_comments # Generate rust bindgen -tools/rust-bindgen +tools/rust-bindgen $1 # Generate Java, C++ and Swift Protobuf files -if [ -x "$(command -v protoc-gen-swift)" ]; then +if [ -x "$(command -v protoc-gen-swift)" ] && [ $# -eq 0 ]; then "$PROTOC" -I=$PREFIX/include -I=src/proto --cpp_out=src/proto --java_out=lite:jni/java --swift_out=swift/Sources/Generated/Protobuf --swift_opt=Visibility=Public src/proto/*.proto else "$PROTOC" -I=$PREFIX/include -I=src/proto --cpp_out=src/proto --java_out=lite:jni/java src/proto/*.proto @@ -74,11 +74,13 @@ fi "$PROTOC" -I=$PREFIX/include -I=src/proto --plugin=$PREFIX/bin/protoc-gen-swift-typealias --swift-typealias_out swift/Sources/Generated/Protobuf src/proto/*.proto # Generate Xcode project -if [ -x "$(command -v xcodegen)" ]; then +if [ -x "$(command -v xcodegen)" ] && [ $# -eq 0 ]; then pushd swift xcodegen pod install popd +elif [ "$1" == "android" ]; then + echo -e "\nWARNING: Android detected, skipping xcodegen generation" else echo -e "\nWARNING: Skipped generating Xcode project because the xcodegen tool is not installed." fi diff --git a/tools/rust-bindgen b/tools/rust-bindgen index 044e16faf6a..6c8350cf7f4 100755 --- a/tools/rust-bindgen +++ b/tools/rust-bindgen @@ -4,7 +4,7 @@ set -e TARGET_NAME="libwallet_core_rs.a" TARGET_XCFRAMEWORK_NAME=../swift/WalletCoreRs.xcframework -BUILD_FOLDER=../build/local +BUILD_FOLDER=../rust/target CRATE="wallet-core-rs" HEADER_NAME="WalletCoreRSBindgen.h" @@ -17,36 +17,33 @@ create_xc_framework() { cd rust -echo "Generating Native targets" -CARGO_TARGET_DIR=$BUILD_FOLDER/ cargo build --release -CARGO_TARGET_DIR=$BUILD_FOLDER cargo build --target wasm32-unknown-emscripten --release +if [[ "$1" != "android" ]]; then + echo "Generating Native targets" + cargo build --release + cargo build --target wasm32-unknown-emscripten --release +fi if [[ `uname` == "Darwin" ]]; then echo "Generating Android targets" - CARGO_TARGET_DIR=$BUILD_FOLDER/ cargo build --target aarch64-linux-android --release - CARGO_TARGET_DIR=$BUILD_FOLDER/ cargo build --target armv7-linux-androideabi --release - CARGO_TARGET_DIR=$BUILD_FOLDER/ cargo build --target x86_64-linux-android --release - CARGO_TARGET_DIR=$BUILD_FOLDER/ cargo build --target i686-linux-android --release - echo "Generating iOS targets" - CARGO_TARGET_DIR=$BUILD_FOLDER cargo build --target aarch64-apple-ios --release - CARGO_TARGET_DIR=$BUILD_FOLDER cargo build --target aarch64-apple-ios-sim --release - CARGO_TARGET_DIR=$BUILD_FOLDER cargo build --target x86_64-apple-ios --release - CARGO_TARGET_DIR=$BUILD_FOLDER cargo build --target aarch64-apple-darwin --release - CARGO_TARGET_DIR=$BUILD_FOLDER cargo build --target x86_64-apple-darwin --release - CARGO_TARGET_DIR=$BUILD_FOLDER cargo +nightly build -Z build-std --target aarch64-apple-ios-macabi --release - CARGO_TARGET_DIR=$BUILD_FOLDER cargo +nightly build -Z build-std --target x86_64-apple-ios-macabi --release - lipo $BUILD_FOLDER/x86_64-apple-ios/release/$TARGET_NAME $BUILD_FOLDER/aarch64-apple-ios-sim/release/$TARGET_NAME -create -output $BUILD_FOLDER/$TARGET_NAME - mkdir -p $BUILD_FOLDER/darwin_universal - lipo $BUILD_FOLDER/x86_64-apple-darwin/release/$TARGET_NAME $BUILD_FOLDER/aarch64-apple-darwin/release/$TARGET_NAME -create -output $BUILD_FOLDER/darwin_universal/$TARGET_NAME - mkdir -p $BUILD_FOLDER/catalyst - lipo $BUILD_FOLDER/aarch64-apple-ios-macabi/release/$TARGET_NAME $BUILD_FOLDER/x86_64-apple-ios-macabi/release/$TARGET_NAME -create -output $BUILD_FOLDER/catalyst/$TARGET_NAME + cargo build --target aarch64-linux-android --target armv7-linux-androideabi --target x86_64-linux-android --target i686-linux-android --release + if [[ "$1" != "android" ]]; then + echo "Generating iOS targets" + cargo build --target aarch64-apple-ios --target aarch64-apple-ios-sim --target x86_64-apple-ios --target aarch64-apple-darwin --target x86_64-apple-darwin --release & + cargo +nightly build -Z build-std --target aarch64-apple-ios-macabi --target x86_64-apple-ios-macabi --release & + wait + lipo $BUILD_FOLDER/x86_64-apple-ios/release/$TARGET_NAME $BUILD_FOLDER/aarch64-apple-ios-sim/release/$TARGET_NAME -create -output $BUILD_FOLDER/$TARGET_NAME + mkdir -p $BUILD_FOLDER/darwin_universal + lipo $BUILD_FOLDER/x86_64-apple-darwin/release/$TARGET_NAME $BUILD_FOLDER/aarch64-apple-darwin/release/$TARGET_NAME -create -output $BUILD_FOLDER/darwin_universal/$TARGET_NAME + mkdir -p $BUILD_FOLDER/catalyst + lipo $BUILD_FOLDER/aarch64-apple-ios-macabi/release/$TARGET_NAME $BUILD_FOLDER/x86_64-apple-ios-macabi/release/$TARGET_NAME -create -output $BUILD_FOLDER/catalyst/$TARGET_NAME - create_xc_framework + create_xc_framework + fi fi cbindgen --crate $CRATE --output ../src/rust/bindgen/$HEADER_NAME cd - -cp build/local/release/${TARGET_NAME} build/local/lib/ +[[ -e rust/target/release/${TARGET_NAME} ]] && cp rust/target/release/${TARGET_NAME} build/local/lib/ -if [[ `uname` == "Darwin" ]]; then +if [[ `uname` == "Darwin" ]] && [[ "$1" != "android" ]]; then cd rust cat > $TARGET_XCFRAMEWORK_NAME/Info.plist << EOF From 428290cc05ee035a1944c084317011505127c773 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Tue, 14 Feb 2023 14:13:08 +0100 Subject: [PATCH 195/497] [Rust/Base32]: Encoding/Decoding support (#2923) --- rust/src/encoding/base32.rs | 250 ++++++++++++++++++++++++++++++++++++ rust/src/encoding/mod.rs | 1 + src/Base32.h | 45 +++---- src/Base64.cpp | 2 +- 4 files changed, 267 insertions(+), 31 deletions(-) create mode 100644 rust/src/encoding/base32.rs diff --git a/rust/src/encoding/base32.rs b/rust/src/encoding/base32.rs new file mode 100644 index 00000000000..2d56b74c767 --- /dev/null +++ b/rust/src/encoding/base32.rs @@ -0,0 +1,250 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +use std::ffi::{c_char, CStr, CString}; +use crate::memory::CByteArray; + +const ALPHABET_RFC4648: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + +pub fn get_alphabet(alphabet: *const c_char) -> Option<&'static [u8]> { + let alphabet = match alphabet.is_null() { + false => { + let alphabet = unsafe { CStr::from_ptr(alphabet).to_str().unwrap().as_bytes() }; + Some(alphabet) + } + true => None, + }; + alphabet +} + +fn base32_encode(input: &[u8], alphabet: Option<&[u8]>, padding: bool) -> Result { + let alphabet = alphabet.unwrap_or(ALPHABET_RFC4648); + if alphabet.len() != 32 { + return Err("Invalid alphabet: must contain 32 characters".to_string()); + } + + let mut result = String::new(); + let mut buffer: u32 = 0; + let mut buffer_size = 0; + + for &byte in input { + buffer = (buffer << 8) | u32::from(byte); + buffer_size += 8; + + while buffer_size >= 5 { + result.push(char::from(alphabet[(buffer >> (buffer_size - 5)) as usize & 31])); + buffer_size -= 5; + } + } + + if buffer_size > 0 { + result.push(char::from(alphabet[(buffer << (5 - buffer_size)) as usize & 31])); + } + + if padding { + let padding = 8 - (result.len() % 8); + result.extend(std::iter::repeat('=').take(padding)); + } + + Ok(result) +} + +#[no_mangle] +pub extern "C" fn encode_base32(input: *const u8, input_len: usize, alphabet: *const c_char, padding: bool) -> *mut c_char { + let input = unsafe { std::slice::from_raw_parts(input, input_len) }; + + let alphabet = get_alphabet(alphabet); + + match base32_encode(input, alphabet, padding) { + Ok(result) => CString::new(result).unwrap().into_raw(), + Err(_) => std::ptr::null_mut(), + } +} + +fn base32_decode(input: &str, alphabet: Option<&[u8]>, padding: bool) -> Result, String> { + let alphabet = alphabet.unwrap_or(ALPHABET_RFC4648); + let mut output = Vec::new(); + let mut buffer: u32 = 0; + let mut bits_left = 0; + let alphabet_map: std::collections::HashMap = alphabet.iter().enumerate().map(|(i, &c)| (c, i as u32)).collect(); + let input = if padding { + input.trim_end_matches('=') + } else { + input + }; + + for c in input.bytes() { + let val = match alphabet_map.get(&c) { + Some(val) => *val, + None => return Err("Invalid character in input".to_string()), + }; + buffer = (buffer << 5) | val; + bits_left += 5; + if bits_left >= 8 { + output.push((buffer >> (bits_left - 8)) as u8); + bits_left -= 8; + } + } + + if padding && bits_left >= 5 { + return Err("Invalid padding in input".to_string()); + } + + if output == vec![0] { + return Ok(vec![]) + } + Ok(output) +} + +#[no_mangle] +pub extern "C" fn decode_base32(input: *const c_char, alphabet: *const c_char, padding: bool) -> CByteArray { + let input = unsafe { CStr::from_ptr(input).to_str().unwrap() }; + let alphabet = get_alphabet(alphabet); + + match base32_decode(input, alphabet, padding) { + Ok(decoded) => { + let size = decoded.len(); + let mut decoded_vec = decoded.to_vec(); + let ptr = decoded_vec.as_mut_ptr(); + std::mem::forget(decoded_vec); + CByteArray { data: ptr, size } + }, + Err(_) => { + CByteArray { data: std::ptr::null_mut(), size: 0 } + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_base32_encode() { + let data = b"Hello, world!"; + let expected = "JBSWY3DPFQQHO33SNRSCC"; + + let result = base32_encode(data, None, false).unwrap(); + assert_eq!(result, expected); + } + + #[test] + fn test_base32_encode_padding() { + let data = b"Hello, world!"; + let expected = "JBSWY3DPFQQHO33SNRSCC==="; + + let result = base32_encode(data, None, true).unwrap(); + assert_eq!(result, expected); + } + + #[test] + fn test_base32_encode_filecoin() { + let alphabet = "abcdefghijklmnopqrstuvwxyz234567"; + let data = b"7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"; + let expected = "g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i"; + let result = base32_encode(data, Some(alphabet.as_bytes()), false).unwrap(); + assert_eq!(result, expected); + + let invalid_alphabet = "invalidalphabet"; + let result = base32_encode(data, Some(invalid_alphabet.as_bytes()), false); + assert_eq!(result.is_err(), true); + } + + #[test] + fn test_base32_encode_ffi() { + let data = b"Hello, world!"; + let expected_1 = "JBSWY3DPFQQHO33SNRSCC==="; + let expected_2 = "JBSWY3DPFQQHO33SNRSCC"; + let expected_3 = "jbswy3dpfqqho33snrscc==="; + let expected_4 = "jbswy3dpfqqho33snrscc"; + + let result_ptr = encode_base32(data.as_ptr(), data.len(), std::ptr::null(), true); + let result = unsafe { CString::from_raw(result_ptr) }; + assert_eq!(result.to_str().unwrap(), expected_1); + + let result_ptr = encode_base32(data.as_ptr(), data.len(), std::ptr::null(), false); + let result = unsafe { CString::from_raw(result_ptr) }; + assert_eq!(result.to_str().unwrap(), expected_2); + + let alphabet = CString::new("abcdefghijklmnopqrstuvwxyz234567").unwrap(); + let result_ptr = encode_base32(data.as_ptr(), data.len(), alphabet.as_ptr(), true); + let result = unsafe { CString::from_raw(result_ptr) }; + assert_eq!(result.to_str().unwrap(), expected_3); + + let result_ptr = encode_base32(data.as_ptr(), data.len(), alphabet.as_ptr(), false); + let result = unsafe { CString::from_raw(result_ptr) }; + assert_eq!(result.to_str().unwrap(), expected_4); + } + + #[test] + fn test_base32_decode() { + let data = "JBSWY3DPFQQHO33SNRSCC"; + let expected = b"Hello, world!"; + + let result = base32_decode(data, None, false).unwrap(); + assert_eq!(result.as_slice(), expected); + } + + #[test] + fn test_base32_decode_abc() { + let data = "ABC"; + let expected = b""; + + let result = base32_decode(data, None, false).unwrap(); + assert_eq!(result.as_slice(), expected); + } + + #[test] + fn test_base32_decode_padding() { + let data = "JBSWY3DPFQQHO33SNRSCC==="; + let expected = b"Hello, world!"; + + let result = base32_decode(data, None, true).unwrap(); + assert_eq!(result.as_slice(), expected); + } + + #[test] + fn test_base32_decode_filecoin() { + let alphabet = "abcdefghijklmnopqrstuvwxyz234567"; + let data = "g52w64jworydimrxov5hmn3gpj2gwyttnzxdmndjo5xxiztsojuxg5dxobzhs6i"; + let expected = b"7uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"; + + let result = base32_decode(data, Some(alphabet.as_bytes()), false).unwrap(); + assert_eq!(result.as_slice(), expected); + } + + #[test] + fn test_base32_decode_ffi() { + let input_1 = "JBSWY3DPFQQHO33SNRSCC==="; + let input_2 = "JBSWY3DPFQQHO33SNRSCC"; + let input_3 = "jbswy3dpfqqho33snrscc==="; + let input_4 = "jbswy3dpfqqho33snrscc"; + let expected = b"Hello, world!"; + + + let input_1 = CString::new(input_1).unwrap(); + let decoded_ptr = decode_base32(input_1.as_ptr(), std::ptr::null(), true); + let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; + assert_eq!(decoded_slice, expected); + + let input_2 = CString::new(input_2).unwrap(); + let decoded_ptr = decode_base32(input_2.as_ptr(), std::ptr::null(), false); + let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; + assert_eq!(decoded_slice, expected); + + + let alphabet = CString::new("abcdefghijklmnopqrstuvwxyz234567").unwrap(); + let input_3 = CString::new(input_3).unwrap(); + let decoded_ptr = decode_base32(input_3.as_ptr(), alphabet.as_ptr(), true); + let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; + assert_eq!(decoded_slice, expected); + + let input_4 = CString::new(input_4).unwrap(); + let decoded_ptr = decode_base32(input_4.as_ptr(), alphabet.as_ptr(), false); + let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; + assert_eq!(decoded_slice, expected); + } +} diff --git a/rust/src/encoding/mod.rs b/rust/src/encoding/mod.rs index b1798fbcce7..f0648e99e5a 100644 --- a/rust/src/encoding/mod.rs +++ b/rust/src/encoding/mod.rs @@ -4,5 +4,6 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +mod base32; mod base64; mod hex; diff --git a/src/Base32.h b/src/Base32.h index 7119a9944be..bf4508f37ec 100644 --- a/src/Base32.h +++ b/src/Base32.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -7,8 +7,7 @@ #pragma once #include "Data.h" - -#include +#include "rust/bindgen/WalletCoreRSBindgen.h" #include @@ -17,41 +16,27 @@ namespace TW::Base32 { /// Decode Base32 string, return bytes as Data /// alphabet: Optional alphabet, if missing, default ALPHABET_RFC4648 inline bool decode(const std::string& encoded_in, Data& decoded_out, const char* alphabet_in = nullptr) { - size_t inLen = encoded_in.size(); - // obtain output length first - size_t outLen = base32_decoded_length(inLen); - uint8_t buf[outLen]; - if (alphabet_in == nullptr) { - alphabet_in = BASE32_ALPHABET_RFC4648; + if (encoded_in.empty()) { + return true; } - // perform the base32 decode - uint8_t* retval = base32_decode(encoded_in.data(), inLen, buf, outLen, alphabet_in); - if (retval == nullptr) { + auto decoded = decode_base32(encoded_in.c_str(), alphabet_in, false); + if (decoded.data == nullptr || decoded.size == 0) { return false; } - decoded_out.assign(buf, buf + outLen); + Data decoded_vec(&decoded.data[0], &decoded.data[decoded.size]); + std::free(decoded.data); + decoded_out = decoded_vec; return true; } + /// Encode bytes in Data to Base32 string /// alphabet: Optional alphabet, if missing, default ALPHABET_RFC4648 -inline std::string encode(const Data& val, const char* alphabet = nullptr) { - size_t inLen = val.size(); - // obtain output length first, reserve for terminator - size_t outLen = base32_encoded_length(inLen) + 1; - char buf[outLen]; - if (alphabet == nullptr) { - alphabet = BASE32_ALPHABET_RFC4648; - } - // perform the base32 encode - char* retval = base32_encode(val.data(), inLen, buf, outLen, alphabet); - if (retval == nullptr) { - // return empty string if failed - return std::string(); - } - // make sure there is a terminator ath the end - buf[outLen - 1] = '\0'; - return std::string(buf); +inline std::string encode(const Data& val, const char* alphabet = nullptr, bool padding = false) { + auto* encoded = encode_base32(val.data(), val.size(), alphabet, padding); + std::string encoded_str(encoded); + free_string(encoded); + return encoded_str; } } // namespace TW::Base32 diff --git a/src/Base64.cpp b/src/Base64.cpp index a09f399e3c7..140ca2d4a76 100644 --- a/src/Base64.cpp +++ b/src/Base64.cpp @@ -21,7 +21,7 @@ Data decode(const std::string& val, bool is_url) { return Data(); } auto decoded = decode_base64(val.c_str(), is_url); - if (decoded.data == nullptr) { + if (decoded.data == nullptr || decoded.size == 0) { return Data(); } std::vector decoded_vec(&decoded.data[0], &decoded.data[decoded.size]); From 9998a8a48ee20d964c4fe8d81821547ae5a04d32 Mon Sep 17 00:00:00 2001 From: Maxim Pestryakov Date: Tue, 14 Feb 2023 21:29:51 +0800 Subject: [PATCH 196/497] [Kotlin] Fix CMakeLists for Android (#2929) --- CMakeLists.txt | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 64bb0147fb9..5828285dc27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,22 +53,27 @@ if (${ANDROID}) message("Configuring for JNI") file(GLOB_RECURSE core_sources src/*.c src/*.cc src/*.cpp src/*.h jni/cpp/*.c jni/cpp/*.cpp jni/cpp/*.h) if (${KOTLIN}) - file(GLOB_RECURSE specific_sources jni/kotlin/*.h jni/kotlin/*.c) + file(GLOB_RECURSE specific_sources + jni/kotlin/*.h + jni/kotlin/*.c + kotlin/wallet-core-kotlin/src/androidMain/cpp/generated/*.h + kotlin/wallet-core-kotlin/src/androidMain/cpp/generated/*.c + ) else () file(GLOB_RECURSE specific_sources jni/android/*.h jni/android/*.c) - endif() + endif () set(sources ${core_sources} ${specific_sources}) add_library(TrustWalletCore SHARED ${sources} ${PROTO_SRCS} ${PROTO_HDRS}) find_library(log-lib log) if (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "arm64-v8a") set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/aarch64-linux-android/release/${WALLET_CORE_RS_LIB}) - elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL "x86") + elseif (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "x86") set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/i686-linux-android/release/${WALLET_CORE_RS_LIB}) - elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL "armeabi-v7a") + elseif (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "armeabi-v7a") set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/armv7-linux-androideabi/release/${WALLET_CORE_RS_LIB}) - elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL "x86_64") + elseif (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "x86_64") set(WALLET_CORE_BINDGEN ${WALLET_CORE_RS_TARGET_DIR}/x86_64-linux-android/release/${WALLET_CORE_RS_LIB}) - endif() + endif () target_link_libraries(TrustWalletCore PUBLIC ${WALLET_CORE_BINDGEN} ${PROJECT_NAME}_INTERFACE PRIVATE TrezorCrypto protobuf ${log-lib} Boost::boost) else () message("Configuring standalone") @@ -118,11 +123,11 @@ if (TW_UNITY_BUILD) set_target_properties(TrustWalletCore PROPERTIES UNITY_BUILD ON) file(GLOB_RECURSE PROTOBUF_SOURCE_FILES CONFIGURE_DEPENDS src/Cosmos/Protobuf/*.pb.cc src/Hedera/Protobuf/*.pb.cc src/proto/*.pb.cc) - foreach(file ${PROTOBUF_SOURCE_FILES}) + foreach (file ${PROTOBUF_SOURCE_FILES}) set_property(SOURCE ${file} PROPERTY SKIP_UNITY_BUILD_INCLUSION ON) - endforeach() + endforeach () message(STATUS "Unity build activated") -endif() +endif () configure_file(${CMAKE_CURRENT_SOURCE_DIR}/swift/cpp.xcconfig.in ${CMAKE_CURRENT_SOURCE_DIR}/swift/cpp.xcconfig @ONLY) From 732566902f5fe33e7b52e1b3f48bad1251da9c0d Mon Sep 17 00:00:00 2001 From: Maxim Pestryakov Date: Wed, 15 Feb 2023 18:22:42 +0800 Subject: [PATCH 197/497] [Kotlin] Removed :generateCinterop task (#2934) --- kotlin/README.md | 2 -- ...=> convention.proto-generation.gradle.kts} | 30 ------------------- kotlin/wallet-core-kotlin/.gitignore | 1 - kotlin/wallet-core-kotlin/build.gradle.kts | 7 +++-- .../src/nativeInterop/cinterop/WalletCore.def | 0 tools/kotlin-build | 2 +- tools/kotlin-release | 2 +- 7 files changed, 6 insertions(+), 38 deletions(-) rename kotlin/build-logic/src/main/kotlin/{convention.file-generation.gradle.kts => convention.proto-generation.gradle.kts} (65%) create mode 100644 kotlin/wallet-core-kotlin/src/nativeInterop/cinterop/WalletCore.def diff --git a/kotlin/README.md b/kotlin/README.md index 42e4cf78a39..d80405f6046 100644 --- a/kotlin/README.md +++ b/kotlin/README.md @@ -1,5 +1,3 @@ ### Tasks: - `./gradlew :wallet-core-kotlin:generateProtos` – Generates Kotlin classes for Protos -- `./gradlew :wallet-core-kotlin:generateCinterop` – Generates def file -- `./gradlew :wallet-core-kotlin:generateFiles` – Generates all the above and Kotlin accessors to the library diff --git a/kotlin/build-logic/src/main/kotlin/convention.file-generation.gradle.kts b/kotlin/build-logic/src/main/kotlin/convention.proto-generation.gradle.kts similarity index 65% rename from kotlin/build-logic/src/main/kotlin/convention.file-generation.gradle.kts rename to kotlin/build-logic/src/main/kotlin/convention.proto-generation.gradle.kts index 028fb3a9c2f..7775d61e4ed 100644 --- a/kotlin/build-logic/src/main/kotlin/convention.file-generation.gradle.kts +++ b/kotlin/build-logic/src/main/kotlin/convention.proto-generation.gradle.kts @@ -1,27 +1,5 @@ val libs = extensions.getByType().named("libs") -val generateCinteropTask = task("generateCinterop") { - doFirst { - val headersDir = rootDir.parentFile.resolve("include/TrustWalletCore") - val headers = headersDir - .listFiles { file -> file.extension == "h" } - .orEmpty() - .sortedBy { it.name } - .joinToString(separator = " ") { it.name } - - val defFile = projectDir.resolve("src/nativeInterop/cinterop/walletCore.def") - defFile.parentFile.mkdirs() - defFile.writeText( - text = - """ - headers = $headers - package = com.trustwallet.core - - """.trimIndent(), - ) - } -} - val copyProtoTask = task("copyProtos") { val sourceDir = rootDir.parentFile.resolve("src/proto") val destinationDir = projectDir.resolve("build/tmp/proto") @@ -76,11 +54,3 @@ val generateProtosTask = task("generateProtos") { "--kotlin_out=$destinationDir", ) } - -task("generateFiles") { - dependsOn(generateCinteropTask) - dependsOn(generateProtosTask) - - workingDir(rootDir.parentFile) - commandLine("./codegen/bin/codegen") -} diff --git a/kotlin/wallet-core-kotlin/.gitignore b/kotlin/wallet-core-kotlin/.gitignore index 1f22b7e6731..a9e76bfd475 100644 --- a/kotlin/wallet-core-kotlin/.gitignore +++ b/kotlin/wallet-core-kotlin/.gitignore @@ -1,3 +1,2 @@ /src/**/generated/ /src/**/proto/ -/src/nativeInterop/ diff --git a/kotlin/wallet-core-kotlin/build.gradle.kts b/kotlin/wallet-core-kotlin/build.gradle.kts index 4af9f55bf0e..780048b49fa 100644 --- a/kotlin/wallet-core-kotlin/build.gradle.kts +++ b/kotlin/wallet-core-kotlin/build.gradle.kts @@ -6,7 +6,7 @@ plugins { kotlin("multiplatform") id("com.android.library") id("convention.maven-publish") - id("convention.file-generation") + id("convention.proto-generation") } kotlin { @@ -71,8 +71,9 @@ kotlin { nativeTargets.forEach { nativeTarget -> nativeTarget.apply { val main by compilations.getting - val walletCore by main.cinterops.creating { - includeDirs.allHeaders(rootDir.parentFile.resolve("include/TrustWalletCore")) + main.cinterops.create("WalletCore") { + packageName = "com.trustwallet.core" + headers(rootDir.parentFile.resolve("include/TrustWalletCore").listFiles()!!) } } } diff --git a/kotlin/wallet-core-kotlin/src/nativeInterop/cinterop/WalletCore.def b/kotlin/wallet-core-kotlin/src/nativeInterop/cinterop/WalletCore.def new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tools/kotlin-build b/tools/kotlin-build index 4eb14383f65..a64537b101f 100755 --- a/tools/kotlin-build +++ b/tools/kotlin-build @@ -3,6 +3,6 @@ set -e pushd kotlin -./gradlew :wallet-core-kotlin:generateFiles +./gradlew :wallet-core-kotlin:generateProtos ./gradlew :wallet-core-kotlin:assemble popd diff --git a/tools/kotlin-release b/tools/kotlin-release index 0eadf3fe30c..ce934855911 100755 --- a/tools/kotlin-release +++ b/tools/kotlin-release @@ -10,7 +10,7 @@ echo "Building $version" export ANDROID_HOME="$HOME/Library/Android/sdk" pushd kotlin -./gradlew :wallet-core-kotlin:generateFiles +./gradlew :wallet-core-kotlin:generateProtos ./gradlew :wallet-core-kotlin:assemble :wallet-core-kotlin:publish -Pversion="$version" popd From a118655786c3f204a46797ad36d223d1d933f97d Mon Sep 17 00:00:00 2001 From: Vladimir Miloserdov Date: Fri, 17 Feb 2023 10:14:20 +0000 Subject: [PATCH 198/497] [ZkSync]: Add support for ZkSync Era mainnet (#2768) --- docs/registry.md | 2 +- registry.json | 12 ++++++------ tests/chains/ZkSyncV2/TWCoinTypeTests.cpp | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/registry.md b/docs/registry.md index 65da87087a0..e1a73222d10 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -87,9 +87,9 @@ This list is generated from [./registry.json](../registry.json) | 10000118 | Osmosis | OSMO | | | | 10000145 | Smart Bitcoin Cash | BCH | | | | 10000250 | Fantom | FTM | | | -| 10000280 | zkSync v2 | ETH | | | | 10000288 | Boba | BOBAETH | | | | 10000321 | KuCoin Community Chain | KCS | | | +| 10000324 | zkSync Era | ETH | | | | 10000330 | Terra | LUNA | | | | 10000553 | Huobi ECO Chain | HT | | | | 10001088 | Metis | METIS | | | diff --git a/registry.json b/registry.json index 869c99c92bc..24f21c446ac 100644 --- a/registry.json +++ b/registry.json @@ -2126,8 +2126,8 @@ { "id": "zksync", "name": "Zksync", - "displayName": "zkSync v2", - "coinId": 10000280, + "displayName": "zkSync Era", + "coinId": 10000324, "slip44": 60, "symbol": "ETH", "decimals": 18, @@ -2139,18 +2139,18 @@ ], "curve": "secp256k1", "publicKeyType": "secp256k1Extended", - "chainId": "280", + "chainId": "324", "addressHasher": "keccak256", "explorer": { - "url": "https://zksync2-testnet.zkscan.io", + "url": "https://explorer.zksync.io", "txPath": "/tx/", "accountPath": "/address/" }, "info": { "url": "https://portal.zksync.io/", "source": "https://github.com/matter-labs/zksync", - "rpc": "https://zksync2-testnet.zksync.dev", - "documentation": "https://v2-docs.zksync.io" + "rpc": "https://zksync2-mainnet.zksync.io", + "documentation": "https://era.zksync.io/docs" } }, { diff --git a/tests/chains/ZkSyncV2/TWCoinTypeTests.cpp b/tests/chains/ZkSyncV2/TWCoinTypeTests.cpp index 95b4854e53e..64b719a3f54 100644 --- a/tests/chains/ZkSyncV2/TWCoinTypeTests.cpp +++ b/tests/chains/ZkSyncV2/TWCoinTypeTests.cpp @@ -16,21 +16,21 @@ TEST(TWZksyncCoinType, TWCoinType) { const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); const auto chainId = WRAPS(TWCoinTypeChainId(coin)); - const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("0xb526861291c0335435e3c976e672a464b70762e54d7167409fb4f66e374ed708")); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("0xae38d3ede1104d088b474da261d0eb4847952c3db24c21e820502f4c1b0c01f5")); const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); - const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0x970978989a51790ee591b2a54f92c7cd9cdc2f88")); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0xeF86b2c8740518548ae449c4C3892B4be0475d8c")); const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); assertStringsEqual(id, "zksync"); - assertStringsEqual(name, "zkSync v2"); + assertStringsEqual(name, "zkSync Era"); assertStringsEqual(symbol, "ETH"); ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 18); ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainEthereum); ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); - assertStringsEqual(chainId, "280"); - assertStringsEqual(txUrl, "https://zksync2-testnet.zkscan.io/tx/0xb526861291c0335435e3c976e672a464b70762e54d7167409fb4f66e374ed708"); - assertStringsEqual(accUrl, "https://zksync2-testnet.zkscan.io/address/0x970978989a51790ee591b2a54f92c7cd9cdc2f88"); + assertStringsEqual(chainId, "324"); + assertStringsEqual(txUrl, "https://explorer.zksync.io/tx/0xae38d3ede1104d088b474da261d0eb4847952c3db24c21e820502f4c1b0c01f5"); + assertStringsEqual(accUrl, "https://explorer.zksync.io/address/0xeF86b2c8740518548ae449c4C3892B4be0475d8c"); } } // namespace TW::TWZksync::tests From 37d5c1cdbe1c30cdc36d0e16fc188fb66bf1bf07 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Mon, 20 Feb 2023 10:19:49 +0100 Subject: [PATCH 199/497] [Solana]: Versioned Tx (#2935) --- coverage.stats | 2 +- src/Solana/AccountMeta.h | 20 + src/Solana/Address.h | 2 +- src/Solana/AddressLookupTable.h | 20 + src/Solana/CompiledInstruction.cpp | 22 ++ src/Solana/CompiledInstruction.h | 38 ++ src/Solana/Constants.h | 27 ++ src/Solana/Encoding.h | 31 ++ src/Solana/Instruction.h | 136 +++++++ src/Solana/LegacyMessage.cpp | 99 +++++ src/Solana/LegacyMessage.h | 253 ++++++++++++ src/Solana/MessageHeader.h | 22 ++ src/Solana/Program.cpp | 4 +- src/Solana/Program.h | 2 +- src/Solana/Signature.cpp | 13 + src/Solana/Signature.h | 30 ++ src/Solana/Signer.cpp | 36 +- src/Solana/Signer.h | 8 +- src/Solana/Transaction.cpp | 107 +---- src/Solana/Transaction.h | 478 +---------------------- src/Solana/V0Message.h | 19 + src/Solana/VersionedMessage.cpp | 67 ++++ src/Solana/VersionedMessage.h | 21 + src/Solana/VersionedTransaction.cpp | 37 ++ src/Solana/VersionedTransaction.h | 46 +++ src/proto/Solana.proto | 20 +- tests/chains/Solana/ProgramTests.cpp | 4 +- tests/chains/Solana/SignerTests.cpp | 52 +-- tests/chains/Solana/TWAnySignerTests.cpp | 18 + tests/chains/Solana/TransactionTests.cpp | 26 +- 30 files changed, 1012 insertions(+), 648 deletions(-) create mode 100644 src/Solana/AccountMeta.h create mode 100644 src/Solana/AddressLookupTable.h create mode 100644 src/Solana/CompiledInstruction.cpp create mode 100644 src/Solana/CompiledInstruction.h create mode 100644 src/Solana/Constants.h create mode 100644 src/Solana/Encoding.h create mode 100644 src/Solana/Instruction.h create mode 100644 src/Solana/LegacyMessage.cpp create mode 100644 src/Solana/LegacyMessage.h create mode 100644 src/Solana/MessageHeader.h create mode 100644 src/Solana/Signature.cpp create mode 100644 src/Solana/Signature.h create mode 100644 src/Solana/V0Message.h create mode 100644 src/Solana/VersionedMessage.cpp create mode 100644 src/Solana/VersionedMessage.h create mode 100644 src/Solana/VersionedTransaction.cpp create mode 100644 src/Solana/VersionedTransaction.h diff --git a/coverage.stats b/coverage.stats index b99dacf6dff..717ab40a58e 100644 --- a/coverage.stats +++ b/coverage.stats @@ -1 +1 @@ -95.0 \ No newline at end of file +95.0 diff --git a/src/Solana/AccountMeta.h b/src/Solana/AccountMeta.h new file mode 100644 index 00000000000..c5545603fde --- /dev/null +++ b/src/Solana/AccountMeta.h @@ -0,0 +1,20 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Solana/Address.h" + +namespace TW::Solana { + +struct AccountMeta { + Address account; + bool isSigner; + bool isReadOnly; + AccountMeta(const Address& address, bool isSigner, bool isReadOnly): account(address), isSigner(isSigner), isReadOnly(isReadOnly) {} +}; + +} diff --git a/src/Solana/Address.h b/src/Solana/Address.h index eef248645d8..97b90f3dfd0 100644 --- a/src/Solana/Address.h +++ b/src/Solana/Address.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Solana/AddressLookupTable.h b/src/Solana/AddressLookupTable.h new file mode 100644 index 00000000000..2330781f6a9 --- /dev/null +++ b/src/Solana/AddressLookupTable.h @@ -0,0 +1,20 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include + +namespace TW::Solana { + +struct AddressLookupTable { + Solana::Address key; + std::vector addresses; +}; + +using MessageAddressTableLookup = std::vector; + +} diff --git a/src/Solana/CompiledInstruction.cpp b/src/Solana/CompiledInstruction.cpp new file mode 100644 index 00000000000..f2e368edd1a --- /dev/null +++ b/src/Solana/CompiledInstruction.cpp @@ -0,0 +1,22 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Solana/CompiledInstruction.h" + +namespace TW::Solana { + +uint8_t CompiledInstruction::findAccount(const Address& address) { + auto it = std::find(addresses.begin(), addresses.end(), address); + if (it == addresses.end()) { + throw std::invalid_argument("address not found"); + } + assert(it != addresses.end()); + auto dist = std::distance(addresses.begin(), it); + assert(dist < 256); + return (uint8_t)dist; +} + +} diff --git a/src/Solana/CompiledInstruction.h b/src/Solana/CompiledInstruction.h new file mode 100644 index 00000000000..1507886f185 --- /dev/null +++ b/src/Solana/CompiledInstruction.h @@ -0,0 +1,38 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Solana/Instruction.h" + +namespace TW::Solana { + +// A compiled instruction +struct CompiledInstruction { + // Index into the transaction keys array indicating the program account that executes this instruction + uint8_t programIdIndex; + // Ordered indices into the transaction keys array indicating which accounts + // to pass to the program + std::vector accounts; + // The program input data + Data data; + + // Reference to the address vector + const std::vector

& addresses; + + /// Supplied address vector is expected to contain all addresses and programId from the instruction; they are replaced by index into the address vector. + CompiledInstruction(const Instruction& instruction, const std::vector
& addresses): addresses(addresses) { + programIdIndex = findAccount(instruction.programId); + for (auto& account: instruction.accounts) { + accounts.push_back(findAccount(account.account)); + } + data = instruction.data; + } + + uint8_t findAccount(const Address& address); +}; + +} diff --git a/src/Solana/Constants.h b/src/Solana/Constants.h new file mode 100644 index 00000000000..588be1ec89e --- /dev/null +++ b/src/Solana/Constants.h @@ -0,0 +1,27 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include + +namespace TW::Solana { +// https://docs.solana.com/developing/programming-model/transactions + +static const std::string SYSTEM_PROGRAM_ID_ADDRESS = "11111111111111111111111111111111"; +static const std::string STAKE_PROGRAM_ID_ADDRESS = "Stake11111111111111111111111111111111111111"; +static const std::string TOKEN_PROGRAM_ID_ADDRESS = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; +static const std::string ASSOCIATED_TOKEN_PROGRAM_ID_ADDRESS = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"; +static const std::string SYSVAR_RENT_ID_ADDRESS = "SysvarRent111111111111111111111111111111111"; +static const std::string SYSVAR_CLOCK_ID_ADDRESS = "SysvarC1ock11111111111111111111111111111111"; +static const std::string STAKE_CONFIG_ID_ADDRESS = "StakeConfig11111111111111111111111111111111"; +static const std::string NULL_ID_ADDRESS = "11111111111111111111111111111111"; +static const std::string SYSVAR_STAKE_HISTORY_ID_ADDRESS = "SysvarStakeHistory1111111111111111111111111"; +static const std::string MEMO_PROGRAM_ID_ADDRESS = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"; +// https://github.com/solana-labs/solana/blob/master/sdk/program/src/message/versions/mod.rs#L24 +static const std::uint8_t MESSAGE_VERSION_PREFIX{0x80}; + +} diff --git a/src/Solana/Encoding.h b/src/Solana/Encoding.h new file mode 100644 index 00000000000..feb2f6fa391 --- /dev/null +++ b/src/Solana/Encoding.h @@ -0,0 +1,31 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Data.h" + +namespace TW::Solana { + +template +Data shortVecLength(std::vector vec) { + auto bytes = Data(); + auto remLen = vec.size(); + while (true) { + uint8_t elem = remLen & 0x7f; + remLen >>= 7; + if (remLen == 0) { + bytes.push_back(elem); + break; + } else { + elem |= 0x80; + bytes.push_back(elem); + } + } + return bytes; +} + +} diff --git a/src/Solana/Instruction.h b/src/Solana/Instruction.h new file mode 100644 index 00000000000..7c9dd24cc05 --- /dev/null +++ b/src/Solana/Instruction.h @@ -0,0 +1,136 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "BinaryCoding.h" +#include "Solana/Address.h" +#include "Solana/AccountMeta.h" +#include "Solana/Constants.h" + +namespace TW::Solana { + +// System instruction types +enum SystemInstruction { + CreateAccount, + Assign, + Transfer, + CreateAccountWithSeed +}; + +// Stake instruction types +enum StakeInstruction { + Initialize = 0, + DelegateStake = 2, + Withdraw = 4, + Deactivate = 5, +}; + +// Token instruction types +enum TokenInstruction { + CreateTokenAccount = 1, + //SetAuthority = 6, + TokenTransfer = 12, +}; + +// An instruction to execute a program +struct Instruction { + // Index into the transaction keys array indicating the program account that + // executes this instruction + Address programId; + // Ordered indices into the transaction keys array indicating which accounts + // to pass to the program + std::vector accounts; + // The program input data + Data data; + + Instruction(const Address& programId, const std::vector& accounts, const Data& data) + : programId(programId), accounts(accounts), data(data) {} + + // This creator creates a default System Transfer instruction + static Instruction createTransfer(const std::vector& accounts, uint64_t value) { + const SystemInstruction type = Transfer; + auto data = Data(); + encode32LE(static_cast(type), data); + encode64LE(static_cast(value), data); + + return Instruction(Address(SYSTEM_PROGRAM_ID_ADDRESS), accounts, data); + } + + static Instruction createAccountWithSeed(const std::vector& accounts, uint64_t value, uint64_t space, const Address& programId, + const Address& voteAddress, uint64_t seedLength, const Address& signer) { + const SystemInstruction type = CreateAccountWithSeed; + auto data = Data(); + std::string seed = voteAddress.string(); + Data vecSeed(seed.begin(), seed.end()); + vecSeed.resize(static_cast(seedLength)); + encode32LE(static_cast(type), data); + append(data, signer.vector()); + encode64LE(static_cast(seedLength), data); + append(data, vecSeed); + encode64LE(static_cast(value), data); + encode64LE(static_cast(space), data); + append(data, programId.vector()); + + return Instruction(Address(SYSTEM_PROGRAM_ID_ADDRESS), accounts, data); + } + + // creates an Initialize Stake instruction + static Instruction createStakeInitialize(const std::vector& accounts, const Address& signer) { + const StakeInstruction type = Initialize; + auto data = Data(); + encode32LE(static_cast(type), data); + append(data, signer.vector()); + append(data, signer.vector()); + auto lockup = Data(48); + append(data, lockup); + + return Instruction(Address(STAKE_PROGRAM_ID_ADDRESS), accounts, data); + } + + // creates a Withdraw Stake instruction + static Instruction createStakeWithdraw(const std::vector& accounts, uint64_t value) { + const StakeInstruction type = Withdraw; + auto data = Data(); + encode32LE(static_cast(type), data); + encode64LE(static_cast(value), data); + + return Instruction(Address(STAKE_PROGRAM_ID_ADDRESS), accounts, data); + } + + // creates a Stake instruction + static Instruction createStake(StakeInstruction type, const std::vector& accounts) { + auto data = Data(); + encode32LE(static_cast(type), data); + + return Instruction(Address(STAKE_PROGRAM_ID_ADDRESS), accounts, data); + } + + // creates a createAccount token instruction. + static Instruction createTokenCreateAccount(const std::vector& accounts) { + auto data = Data(); + return Instruction(Address(ASSOCIATED_TOKEN_PROGRAM_ID_ADDRESS), accounts, data); + } + + // creates a transfer token instruction. + static Instruction createTokenTransfer(const std::vector& accounts, uint64_t value, uint8_t decimals) { + const TokenInstruction type = TokenTransfer; + auto data = Data(); + data.push_back(static_cast(type)); + encode64LE(value, data); + data.push_back(static_cast(decimals)); + + return Instruction(Address(TOKEN_PROGRAM_ID_ADDRESS), accounts, data); + } + + static Instruction createMemo(std::string memo) { + auto data = TW::data(memo); + std::vector accounts; // empty + return Instruction(Address(MEMO_PROGRAM_ID_ADDRESS), accounts, data); + } +}; + +} diff --git a/src/Solana/LegacyMessage.cpp b/src/Solana/LegacyMessage.cpp new file mode 100644 index 00000000000..42f411578c9 --- /dev/null +++ b/src/Solana/LegacyMessage.cpp @@ -0,0 +1,99 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Solana/LegacyMessage.h" +#include "Solana/Encoding.h" + +namespace TW::Solana { +void LegacyMessage::addAccount(const AccountMeta& account) { + bool inSigned = (std::find(signedAccounts.begin(), signedAccounts.end(), account.account) != signedAccounts.end()); + bool inUnsigned = (std::find(unsignedAccounts.begin(), unsignedAccounts.end(), account.account) != unsignedAccounts.end()); + bool inReadOnly = (std::find(readOnlyAccounts.begin(), readOnlyAccounts.end(), account.account) != readOnlyAccounts.end()); + if (account.isSigner) { + if (!inSigned) { + signedAccounts.push_back(account.account); + } + } else if (!account.isReadOnly) { + if (!inSigned && !inUnsigned) { + unsignedAccounts.push_back(account.account); + } + } else { + if (!inSigned && !inUnsigned && !inReadOnly) { + readOnlyAccounts.push_back(account.account); + } + } +} + +void LegacyMessage::addAccountKeys(const Address& account) { + if (std::find(accountKeys.begin(), accountKeys.end(), account) == accountKeys.end()) { + accountKeys.push_back(account); + } +} + +Data LegacyMessage::serialize() const { + Data buffer; + + buffer.push_back(this->header.numRequiredSignatures); + buffer.push_back(this->header.numCreditOnlySignedAccounts); + buffer.push_back(this->header.numCreditOnlyUnsignedAccounts); + append(buffer, shortVecLength
(this->accountKeys)); + for (auto account_key : this->accountKeys) { + Data account_key_vec(account_key.bytes.begin(), account_key.bytes.end()); + append(buffer, account_key_vec); + } + append(buffer, mRecentBlockHash); + + // apppend compiled instructions + append(buffer, shortVecLength(compiledInstructions)); + for (auto instruction : compiledInstructions) { + buffer.push_back(instruction.programIdIndex); + append(buffer, shortVecLength(instruction.accounts)); + append(buffer, instruction.accounts); + append(buffer, shortVecLength(instruction.data)); + append(buffer, instruction.data); + } + + return buffer; +} + +void LegacyMessage::compileAccounts() { + for (auto& instr : instructions) { + for (auto& address : instr.accounts) { + addAccount(address); + } + } + // add programIds (read-only, at end) + for (auto& instr : instructions) { + addAccount(AccountMeta{instr.programId, false, true}); + } + + header = MessageHeader{ + (uint8_t)signedAccounts.size(), + 0, + (uint8_t)readOnlyAccounts.size()}; + + // merge the three buckets + accountKeys.clear(); + for (auto& a : signedAccounts) { + addAccountKeys(a); + } + for (auto& a : unsignedAccounts) { + addAccountKeys(a); + } + for (auto& a : readOnlyAccounts) { + addAccountKeys(a); + } + + compileInstructions(); +} + +void LegacyMessage::compileInstructions() { + compiledInstructions.clear(); + for (auto instruction : instructions) { + compiledInstructions.emplace_back(CompiledInstruction(instruction, accountKeys)); + } +} +} diff --git a/src/Solana/LegacyMessage.h b/src/Solana/LegacyMessage.h new file mode 100644 index 00000000000..f6dca77a5ef --- /dev/null +++ b/src/Solana/LegacyMessage.h @@ -0,0 +1,253 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Solana/MessageHeader.h" +#include "Solana/Address.h" +#include "Solana/Instruction.h" +#include "Solana/CompiledInstruction.h" +#include "Solana/Constants.h" + +#include + +namespace TW::Solana { + +class LegacyMessage { +public: + // The message header, identifying signed and credit-only `accountKeys` + MessageHeader header; + // All the account keys used by this transaction + std::vector
accountKeys; + // The id of a recent ledger entry. + Data mRecentBlockHash; + // Programs that will be executed in sequence and committed in one atomic + // transaction if all succeed. + std::vector instructions; + + // three buckets of different account types + std::vector
signedAccounts; + std::vector
unsignedAccounts; + std::vector
readOnlyAccounts; + std::vector compiledInstructions; + + LegacyMessage() + : mRecentBlockHash(Base58::bitcoin.decode(NULL_ID_ADDRESS)){}; + + LegacyMessage(Data recentBlockHash, const std::vector& instructions) + : mRecentBlockHash(recentBlockHash) + , instructions(instructions) { + compileAccounts(); + } + + // add an acount, to the corresponding bucket + void addAccount(const AccountMeta& account); + // add an account to accountKeys if not yet present + void addAccountKeys(const Address& account); + // compile the single accounts lists from the buckets + void compileAccounts(); + // compile the instructions; replace instruction accounts with indices + void compileInstructions(); + + // Serialize to msg data + Data serialize() const; + + static void appendReferences(std::vector& accountMetas, const std::vector
& references) { + for (auto&& reference : references) { + accountMetas.emplace_back(reference, false, true); + } + } + + // This constructor creates a default single-signer Transfer message + static LegacyMessage createTransfer(const Address& from, const Address& to, uint64_t value, Data mRecentBlockHash, + std::string memo = "", std::vector
references = {}) { + std::vector instructions; + if (memo.length() > 0) { + // Optional memo. Order: before transfer, as per documentation. + instructions.push_back(Instruction::createMemo(memo)); + } + std::vector accountMetas = { + AccountMeta(from, true, false), + AccountMeta(to, false, false), + }; + appendReferences(accountMetas, references); + instructions.push_back(Instruction::createTransfer(accountMetas, value)); + return LegacyMessage(mRecentBlockHash, instructions); + } + + // This constructor creates a create_account_with_seed_and_delegate_stake message + // see delegate_stake() solana/programs/stake/src/stake_instruction.rs + static LegacyMessage createStake(const Address& signer, const Address& stakeAddress, const Address& voteAddress, uint64_t value, Data mRecentBlockHash) { + auto sysvarRentId = Address(SYSVAR_RENT_ID_ADDRESS); + auto sysvarClockId = Address(SYSVAR_CLOCK_ID_ADDRESS); + auto stakeConfigId = Address(STAKE_CONFIG_ID_ADDRESS); + auto sysvarStakeHistoryId = Address(SYSVAR_STAKE_HISTORY_ID_ADDRESS); + auto stakeProgramId = Address(STAKE_PROGRAM_ID_ADDRESS); + std::vector instructions; + instructions.reserve(3); + // create_account_with_seed instruction + Address seed = Address(mRecentBlockHash); + auto createAccountInstruction = Instruction::createAccountWithSeed(std::vector{ + AccountMeta(signer, true, true), + AccountMeta(stakeAddress, false, false), + AccountMeta(signer, true, true), + }, + value, 200, stakeProgramId, seed, 32, signer); + instructions.push_back(createAccountInstruction); + // initialize instruction + auto initializeInstruction = Instruction::createStakeInitialize(std::vector{ + AccountMeta(stakeAddress, false, false), + AccountMeta(sysvarRentId, false, true)}, + signer); + instructions.push_back(initializeInstruction); + // delegate_stake instruction + auto delegateInstruction = Instruction::createStake(DelegateStake, + std::vector{ + AccountMeta(stakeAddress, false, false), // 0. `[WRITE]` Initialized stake account to be delegated + AccountMeta(voteAddress, false, true), // 1. `[]` Vote account to which this stake will be delegated + AccountMeta(sysvarClockId, false, true), // 2. `[]` Clock sysvar + AccountMeta(sysvarStakeHistoryId, false, true), // 3. `[]` Stake history sysvar that carries stake warmup/cooldown history + AccountMeta(stakeConfigId, false, true), // 4. `[]` Address of config account that carries stake config + AccountMeta(signer, true, true), // 5. `[SIGNER]` Stake authority + }); + instructions.push_back(delegateInstruction); + return LegacyMessage(mRecentBlockHash, instructions); + } + + // This constructor creates a deactivate_stake message + static LegacyMessage createStakeDeactivate(const Address& signer, const Address& stakeAddress, Data mRecentBlockHash) { + auto sysvarClockId = Address(SYSVAR_CLOCK_ID_ADDRESS); + auto instruction = Instruction::createStake(Deactivate, std::vector{ + AccountMeta(stakeAddress, false, false), // 0. `[WRITE]` Delegated stake account + AccountMeta(sysvarClockId, false, true), // 1. `[]` Clock sysvar + AccountMeta(signer, true, false), // 2. `[SIGNER]` Stake authority + }); + return LegacyMessage(mRecentBlockHash, {instruction}); + } + + // This constructor creates a deactivate_stake message with multiple stake accounts + static LegacyMessage createStakeDeactivateAll(const Address& signer, const std::vector
& stakeAddresses, Data mRecentBlockHash) { + auto sysvarClockId = Address(SYSVAR_CLOCK_ID_ADDRESS); + std::vector instructions; + for (auto& address : stakeAddresses) { + auto instruction = Instruction::createStake(Deactivate, std::vector{ + AccountMeta(address, false, false), // 0. `[WRITE]` Delegated stake account + AccountMeta(sysvarClockId, false, true), // 1. `[]` Clock sysvar + AccountMeta(signer, true, false), // 2. `[SIGNER]` Stake authority + }); + instructions.push_back(instruction); + } + return LegacyMessage(mRecentBlockHash, instructions); + } + + // This constructor creates a withdraw message, with the signer as the default recipient + static LegacyMessage createStakeWithdraw(const Address& signer, const Address& stakeAddress, uint64_t value, Data mRecentBlockHash) { + auto sysvarClockId = Address(SYSVAR_CLOCK_ID_ADDRESS); + auto sysvarStakeHistoryId = Address(SYSVAR_STAKE_HISTORY_ID_ADDRESS); + auto instruction = Instruction::createStakeWithdraw(std::vector{ + AccountMeta(stakeAddress, false, false), // 0. `[WRITE]` Stake account from which to withdraw + AccountMeta(signer, false, false), // 1. `[WRITE]` Recipient account + AccountMeta(sysvarClockId, false, true), // 2. `[]` Clock sysvar + AccountMeta(sysvarStakeHistoryId, false, true), // 3. `[]` Stake history sysvar that carries stake warmup/cooldown history + AccountMeta(signer, true, false), // 4. `[SIGNER]` Withdraw authority + }, + value); + return LegacyMessage(mRecentBlockHash, {instruction}); + } + + // This constructor creates a withdraw message, with multiple stake accounts + static LegacyMessage createStakeWithdrawAll(const Address& signer, const std::vector>& stakes, Data mRecentBlockHash) { + auto sysvarClockId = Address(SYSVAR_CLOCK_ID_ADDRESS); + auto sysvarStakeHistoryId = Address(SYSVAR_STAKE_HISTORY_ID_ADDRESS); + std::vector instructions; + for (auto& stake : stakes) { + auto instruction = Instruction::createStakeWithdraw(std::vector{ + AccountMeta(stake.first, false, false), // 0. `[WRITE]` Stake account from which to withdraw + AccountMeta(signer, false, false), // 1. `[WRITE]` Recipient account + AccountMeta(sysvarClockId, false, true), // 2. `[]` Clock sysvar + AccountMeta(sysvarStakeHistoryId, false, true), // 3. `[]` Stake history sysvar that carries stake warmup/cooldown history + AccountMeta(signer, true, false), // 4. `[SIGNER]` Withdraw authority + }, + stake.second); + instructions.push_back(instruction); + } + return LegacyMessage(mRecentBlockHash, instructions); + } + + // This constructor creates a createAccount token message + // see create_associated_token_account() solana-program-library/associated-token-account/program/src/lib.rs + static LegacyMessage createTokenCreateAccount(const Address& signer, const Address& otherMainAccount, const Address& tokenMintAddress, const Address& tokenAddress, Data mRecentBlockHash) { + auto sysvarRentId = Address(SYSVAR_RENT_ID_ADDRESS); + auto systemProgramId = Address(SYSTEM_PROGRAM_ID_ADDRESS); + auto tokenProgramId = Address(TOKEN_PROGRAM_ID_ADDRESS); + auto instruction = Instruction::createTokenCreateAccount(std::vector{ + AccountMeta(signer, true, false), // fundingAddress, + AccountMeta(tokenAddress, false, false), + AccountMeta(otherMainAccount, false, true), + AccountMeta(tokenMintAddress, false, true), + AccountMeta(systemProgramId, false, true), + AccountMeta(tokenProgramId, false, true), + AccountMeta(sysvarRentId, false, true), + }); + return LegacyMessage(mRecentBlockHash, {instruction}); + } + + // This constructor creates a transfer token message. + // see transfer_checked() solana-program-library/token/program/src/instruction.rs + static LegacyMessage createTokenTransfer(const Address& signer, const Address& tokenMintAddress, + const Address& senderTokenAddress, const Address& recipientTokenAddress, uint64_t amount, uint8_t decimals, Data mRecentBlockHash, + std::string memo = "", std::vector
references = {}) { + std::vector instructions; + if (memo.length() > 0) { + // Optional memo. Order: before transfer, as per documentation. + instructions.push_back(Instruction::createMemo(memo)); + } + std::vector accountMetas = { + AccountMeta(senderTokenAddress, false, false), + AccountMeta(tokenMintAddress, false, true), + AccountMeta(recipientTokenAddress, false, false), + AccountMeta(signer, true, false), + }; + appendReferences(accountMetas, references); + instructions.push_back(Instruction::createTokenTransfer(accountMetas, amount, decimals)); + return LegacyMessage(mRecentBlockHash, instructions); + } + + // This constructor creates a createAndTransferToken message, combining createAccount and transfer. + static LegacyMessage createTokenCreateAndTransfer(const Address& signer, const Address& recipientMainAddress, const Address& tokenMintAddress, + const Address& recipientTokenAddress, const Address& senderTokenAddress, uint64_t amount, uint8_t decimals, Data mRecentBlockHash, + std::string memo = "", std::vector
references = {}) { + const auto sysvarRentId = Address(SYSVAR_RENT_ID_ADDRESS); + const auto systemProgramId = Address(SYSTEM_PROGRAM_ID_ADDRESS); + const auto tokenProgramId = Address(TOKEN_PROGRAM_ID_ADDRESS); + std::vector instructions; + instructions.reserve(3); + instructions.emplace_back(Instruction::createTokenCreateAccount(std::vector{ + AccountMeta(signer, true, false), // fundingAddress, + AccountMeta(recipientTokenAddress, false, false), + AccountMeta(recipientMainAddress, false, true), + AccountMeta(tokenMintAddress, false, true), + AccountMeta(systemProgramId, false, true), + AccountMeta(tokenProgramId, false, true), + AccountMeta(sysvarRentId, false, true), + })); + if (memo.length() > 0) { + // Optional memo. Order: before transfer, as per documentation. + instructions.emplace_back(Instruction::createMemo(memo)); + } + std::vector accountMetas = { + AccountMeta(senderTokenAddress, false, false), + AccountMeta(tokenMintAddress, false, true), + AccountMeta(recipientTokenAddress, false, false), + AccountMeta(signer, true, false), + }; + appendReferences(accountMetas, references); + instructions.push_back(Instruction::createTokenTransfer(accountMetas, amount, decimals)); + return LegacyMessage(mRecentBlockHash, instructions); + } +}; + +} diff --git a/src/Solana/MessageHeader.h b/src/Solana/MessageHeader.h new file mode 100644 index 00000000000..bb06ce56076 --- /dev/null +++ b/src/Solana/MessageHeader.h @@ -0,0 +1,22 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include // << std::uint8_t + +struct MessageHeader { + // The number of signatures required for this message to be considered + // valid. The signatures must match the first `numRequiredSignatures` of + // `accountKeys`. + uint8_t numRequiredSignatures = 0; + // The last numCreditOnlySignedAccounts of the signed keys are + // credit-only accounts. + uint8_t numCreditOnlySignedAccounts = 0; + // The last numCreditOnlyUnsignedAccounts of the unsigned keys are + // credit-only accounts. + uint8_t numCreditOnlyUnsignedAccounts = 0; +}; diff --git a/src/Solana/Program.cpp b/src/Solana/Program.cpp index bac0340caa8..d5023c3a66a 100644 --- a/src/Solana/Program.cpp +++ b/src/Solana/Program.cpp @@ -25,9 +25,9 @@ Address StakeProgram::addressFromValidatorSeed(const Address& fromAddress, const return Address(hash); } -Address StakeProgram::addressFromRecentBlockhash(const Address& fromAddress, const Hash& recentBlockhash, const Address& programId) { +Address StakeProgram::addressFromRecentBlockhash(const Address& fromAddress, const Data& recentBlockhash, const Address& programId) { Data extended = fromAddress.vector(); - std::string seed = recentBlockhash.encoded(); + std::string seed = Base58::bitcoin.encode(recentBlockhash); Data vecSeed(seed.begin(), seed.end()); vecSeed.resize(32); Data additional = programId.vector(); diff --git a/src/Solana/Program.h b/src/Solana/Program.h index 4214bb98355..e2880c3c173 100644 --- a/src/Solana/Program.h +++ b/src/Solana/Program.h @@ -19,7 +19,7 @@ class StakeProgram { const Address& validatorAddress, const Address& programId); - static Address addressFromRecentBlockhash(const Address& fromAddress, const Hash& recentBlockhash, const Address& programId); + static Address addressFromRecentBlockhash(const Address& fromAddress, const Data& recentBlockhash, const Address& programId); }; diff --git a/src/Solana/Signature.cpp b/src/Solana/Signature.cpp new file mode 100644 index 00000000000..e054ac0f8c2 --- /dev/null +++ b/src/Solana/Signature.cpp @@ -0,0 +1,13 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Solana/Signature.h" + +namespace TW::Solana { + bool Signature::operator==(const Signature& v) const { + return bytes == v.bytes; + } +} diff --git a/src/Solana/Signature.h b/src/Solana/Signature.h new file mode 100644 index 00000000000..8cb169b6e6a --- /dev/null +++ b/src/Solana/Signature.h @@ -0,0 +1,30 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include + +#include "Base58.h" + +namespace TW::Solana { +class Signature { +public: + static const size_t size = 64; + /// Signature data + std::array bytes; + + Signature(const std::string& string) { + const auto data = Base58::bitcoin.decode(string); + std::copy(data.begin(), data.end(), this->bytes.begin()); + } + Signature(const std::array& bytes) { this->bytes = bytes; } + Signature(const Data& bytes) { std::copy(bytes.begin(), bytes.end(), this->bytes.begin()); } + + bool operator==(const Signature& v) const; +}; +} diff --git a/src/Solana/Signer.cpp b/src/Solana/Signer.cpp index e14351939fd..e427bd76401 100644 --- a/src/Solana/Signer.cpp +++ b/src/Solana/Signer.cpp @@ -7,6 +7,8 @@ #include "Signer.h" #include "Address.h" #include "Program.h" +#include "Solana/Encoding.h" +#include "Solana/VersionedTransaction.h" #include @@ -14,7 +16,7 @@ namespace TW::Solana { -void Signer::sign(const std::vector& privateKeys, Transaction& transaction) { +void Signer::sign(const std::vector& privateKeys, VersionedTransaction& transaction) { for (auto privateKey : privateKeys) { auto address = Address(privateKey.getPublicKey(TWPublicKeyTypeED25519)); auto index = transaction.getAccountIndex(address); @@ -36,15 +38,15 @@ std::vector
convertReferences(const google::protobuf::RepeatedPtrField< } Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { - auto blockhash = Solana::Hash(input.recent_blockhash()); + auto blockhash = Base58::bitcoin.decode(input.recent_blockhash()); auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); - Message message; + LegacyMessage message; std::vector signerKeys; switch (input.transaction_type_case()) { case Proto::SigningInput::TransactionTypeCase::kTransferTransaction: { auto protoMessage = input.transfer_transaction(); - message = Message::createTransfer( + message = LegacyMessage::createTransfer( /* from */ Address(key.getPublicKey(TWPublicKeyTypeED25519)), /* to */ Address(protoMessage.recipient()), /* value */ protoMessage.value(), @@ -67,7 +69,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { // stake address specified, use it stakeAddress = Address(protoMessage.stake_account()); } - message = Message::createStake( + message = LegacyMessage::createStake( /* signer */ userAddress, /* stakeAddress */ stakeAddress.value(), /* voteAddress */ validatorAddress, @@ -80,7 +82,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto protoMessage = input.deactivate_stake_transaction(); auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); auto stakeAddress = Address(protoMessage.stake_account()); - message = Message::createStakeDeactivate( + message = LegacyMessage::createStakeDeactivate( /* signer */ userAddress, /* stakeAddress */ stakeAddress, /* recent_blockhash */ blockhash); @@ -94,7 +96,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { for (auto i = 0; i < protoMessage.stake_accounts_size(); ++i) { addresses.emplace_back(Address(protoMessage.stake_accounts(i))); } - message = Message::createStakeDeactivateAll(userAddress, addresses, blockhash); + message = LegacyMessage::createStakeDeactivateAll(userAddress, addresses, blockhash); signerKeys.push_back(key); } break; @@ -102,7 +104,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto protoMessage = input.withdraw_transaction(); auto userAddress = Address(key.getPublicKey(TWPublicKeyTypeED25519)); auto stakeAddress = Address(protoMessage.stake_account()); - message = Message::createStakeWithdraw( + message = LegacyMessage::createStakeWithdraw( /* signer */ userAddress, /* stakeAddress */ stakeAddress, /* value */ protoMessage.value(), @@ -119,7 +121,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { Address(protoMessage.stake_accounts(i).stake_account()), protoMessage.stake_accounts(i).value())); } - message = Message::createStakeWithdrawAll(userAddress, stakes, blockhash); + message = LegacyMessage::createStakeWithdrawAll(userAddress, stakes, blockhash); signerKeys.push_back(key); } break; @@ -129,7 +131,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto mainAddress = Address(protoMessage.main_address()); auto tokenMintAddress = Address(protoMessage.token_mint_address()); auto tokenAddress = Address(protoMessage.token_address()); - message = Message::createTokenCreateAccount(userAddress, mainAddress, tokenMintAddress, tokenAddress, blockhash); + message = LegacyMessage::createTokenCreateAccount(userAddress, mainAddress, tokenMintAddress, tokenAddress, blockhash); signerKeys.push_back(key); } break; @@ -142,7 +144,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto amount = protoMessage.amount(); auto decimals = static_cast(protoMessage.decimals()); const auto memo = protoMessage.memo(); - message = Message::createTokenTransfer(userAddress, tokenMintAddress, senderTokenAddress, recipientTokenAddress, amount, decimals, blockhash, + message = LegacyMessage::createTokenTransfer(userAddress, tokenMintAddress, senderTokenAddress, recipientTokenAddress, amount, decimals, blockhash, memo, convertReferences(protoMessage.references())); signerKeys.push_back(key); } break; @@ -157,7 +159,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto amount = protoMessage.amount(); auto decimals = static_cast(protoMessage.decimals()); const auto memo = protoMessage.memo(); - message = Message::createTokenCreateAndTransfer(userAddress, recipientMainAddress, tokenMintAddress, recipientTokenAddress, senderTokenAddress, amount, decimals, blockhash, + message = LegacyMessage::createTokenCreateAndTransfer(userAddress, recipientMainAddress, tokenMintAddress, recipientTokenAddress, senderTokenAddress, amount, decimals, blockhash, memo, convertReferences(protoMessage.references())); signerKeys.push_back(key); } break; @@ -165,7 +167,11 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { default: assert(input.transaction_type_case() != Proto::SigningInput::TransactionTypeCase::TRANSACTION_TYPE_NOT_SET); } - auto transaction = Transaction(message); + auto msg = VersionedMessage(message); + if (input.v0_msg()) { + msg = VersionedMessage(V0Message{.msg = message}); + } + auto transaction = VersionedTransaction(msg); sign(signerKeys, transaction); @@ -180,8 +186,8 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { } void Signer::signUpdateBlockhash(const std::vector& privateKeys, - Transaction& transaction, Solana::Hash& recentBlockhash) { - transaction.message.recentBlockhash = recentBlockhash; + VersionedTransaction& transaction, Data& recentBlockhash) { + updateRecentHash(transaction.message, recentBlockhash); Signer::sign(privateKeys, transaction); } diff --git a/src/Solana/Signer.h b/src/Solana/Signer.h index 46bed571ffb..d89d4656a34 100644 --- a/src/Solana/Signer.h +++ b/src/Solana/Signer.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,7 +6,7 @@ #pragma once -#include "Transaction.h" +#include "VersionedTransaction.h" #include "Data.h" #include "../Hash.h" #include "../PrivateKey.h" @@ -18,13 +18,13 @@ namespace TW::Solana { class Signer { public: /// Signs the given transaction. - static void sign(const std::vector& privateKeys, Transaction& transaction); + static void sign(const std::vector& privateKeys, VersionedTransaction& transaction); /// Signs a json Proto::SigningInput with private key static std::string signJSON(const std::string& json, const Data& key); static void signUpdateBlockhash(const std::vector& privateKeys, - Transaction& transaction, Solana::Hash& recentBlockhash); + VersionedTransaction& transaction, Data& recentBlockhash); static Data signRawMessage(const std::vector& privateKeys, const Data messageData); static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept; diff --git a/src/Solana/Transaction.cpp b/src/Solana/Transaction.cpp index ac345134dc6..172779dee30 100644 --- a/src/Solana/Transaction.cpp +++ b/src/Solana/Transaction.cpp @@ -1,10 +1,11 @@ -// Copyright © 2017-2022 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. #include "Transaction.h" +#include "Solana/Encoding.h" #include "Hash.h" #include "Signer.h" @@ -13,80 +14,6 @@ namespace TW::Solana { -uint8_t CompiledInstruction::findAccount(const Address& address) { - auto it = std::find(addresses.begin(), addresses.end(), address); - if (it == addresses.end()) { - throw std::invalid_argument("address not found"); - } - assert(it != addresses.end()); - auto dist = std::distance(addresses.begin(), it); - assert(dist < 256); - return (uint8_t)dist; -} - -void Message::addAccount(const AccountMeta& account) { - bool inSigned = (std::find(signedAccounts.begin(), signedAccounts.end(), account.account) != signedAccounts.end()); - bool inUnsigned = (std::find(unsignedAccounts.begin(), unsignedAccounts.end(), account.account) != unsignedAccounts.end()); - bool inReadOnly = (std::find(readOnlyAccounts.begin(), readOnlyAccounts.end(), account.account) != readOnlyAccounts.end()); - if (account.isSigner) { - if (!inSigned) { - signedAccounts.push_back(account.account); - } - } else if (!account.isReadOnly) { - if (!inSigned && !inUnsigned) { - unsignedAccounts.push_back(account.account); - } - } else { - if (!inSigned && !inUnsigned && !inReadOnly) { - readOnlyAccounts.push_back(account.account); - } - } -} - -void Message::addAccountKeys(const Address& account) { - if (std::find(accountKeys.begin(), accountKeys.end(), account) == accountKeys.end()) { - accountKeys.push_back(account); - } -} - -void Message::compileAccounts() { - for (auto& instr : instructions) { - for (auto& address : instr.accounts) { - addAccount(address); - } - } - // add programIds (read-only, at end) - for (auto& instr : instructions) { - addAccount(AccountMeta{instr.programId, false, true}); - } - - header = MessageHeader{ - (uint8_t)signedAccounts.size(), - 0, - (uint8_t)readOnlyAccounts.size()}; - - // merge the three buckets - accountKeys.clear(); - for (auto& a : signedAccounts) { - addAccountKeys(a); - } - for (auto& a : unsignedAccounts) { - addAccountKeys(a); - } - for (auto& a : readOnlyAccounts) { - addAccountKeys(a); - } - - compileInstructions(); -} - -void Message::compileInstructions() { - compiledInstructions.clear(); - for (auto instruction : instructions) { - compiledInstructions.emplace_back(CompiledInstruction(instruction, accountKeys)); - } -} - std::string Transaction::serialize() const { Data buffer; @@ -101,31 +28,7 @@ std::string Transaction::serialize() const { } Data Transaction::messageData() const { - Data buffer; - - buffer.push_back(this->message.header.numRequiredSignatures); - buffer.push_back(this->message.header.numCreditOnlySignedAccounts); - buffer.push_back(this->message.header.numCreditOnlyUnsignedAccounts); - append(buffer, shortVecLength
(this->message.accountKeys)); - for (auto account_key : this->message.accountKeys) { - Data account_key_vec(account_key.bytes.begin(), account_key.bytes.end()); - append(buffer, account_key_vec); - } - Data recentBlockhash(this->message.recentBlockhash.bytes.begin(), - this->message.recentBlockhash.bytes.end()); - append(buffer, recentBlockhash); - - // apppend compiled instructions - append(buffer, shortVecLength(message.compiledInstructions)); - for (auto instruction : message.compiledInstructions) { - buffer.push_back(instruction.programIdIndex); - append(buffer, shortVecLength(instruction.accounts)); - append(buffer, instruction.accounts); - append(buffer, shortVecLength(instruction.data)); - append(buffer, instruction.data); - } - - return buffer; + return this->message.serialize(); } uint8_t Transaction::getAccountIndex(Address publicKey) { @@ -137,8 +40,4 @@ uint8_t Transaction::getAccountIndex(Address publicKey) { return (uint8_t)std::distance(this->message.accountKeys.begin(), item); } -bool Signature::operator==(const Signature& v) const { - return bytes == v.bytes; -} - } // namespace TW::Solana diff --git a/src/Solana/Transaction.h b/src/Solana/Transaction.h index 8ea3e6c5fca..65d24a3bfb0 100644 --- a/src/Solana/Transaction.h +++ b/src/Solana/Transaction.h @@ -6,493 +6,31 @@ #pragma once -#include "Address.h" -#include "../Base58.h" -#include "../BinaryCoding.h" +#include "Solana/Address.h" +#include "Solana/LegacyMessage.h" +#include "Solana/Signature.h" #include "Data.h" +#include "BinaryCoding.h" #include #include namespace TW::Solana { -// https://docs.solana.com/developing/programming-model/transactions - -const std::string SYSTEM_PROGRAM_ID_ADDRESS = "11111111111111111111111111111111"; -const std::string STAKE_PROGRAM_ID_ADDRESS = "Stake11111111111111111111111111111111111111"; -const std::string TOKEN_PROGRAM_ID_ADDRESS = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; -const std::string ASSOCIATED_TOKEN_PROGRAM_ID_ADDRESS = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"; -const std::string SYSVAR_RENT_ID_ADDRESS = "SysvarRent111111111111111111111111111111111"; -const std::string SYSVAR_CLOCK_ID_ADDRESS = "SysvarC1ock11111111111111111111111111111111"; -const std::string STAKE_CONFIG_ID_ADDRESS = "StakeConfig11111111111111111111111111111111"; -const std::string NULL_ID_ADDRESS = "11111111111111111111111111111111"; -const std::string SYSVAR_STAKE_HISTORY_ID_ADDRESS = "SysvarStakeHistory1111111111111111111111111"; -const std::string MEMO_PROGRAM_ID_ADDRESS = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"; - -template -Data shortVecLength(std::vector vec) { - auto bytes = Data(); - auto remLen = vec.size(); - while (true) { - uint8_t elem = remLen & 0x7f; - remLen >>= 7; - if (remLen == 0) { - bytes.push_back(elem); - break; - } else { - elem |= 0x80; - bytes.push_back(elem); - } - } - return bytes; -} - -// System instruction types -enum SystemInstruction { - CreateAccount, - Assign, - Transfer, - CreateAccountWithSeed -}; - -// Stake instruction types -enum StakeInstruction { - Initialize = 0, - DelegateStake = 2, - Withdraw = 4, - Deactivate = 5, -}; - -// Token instruction types -enum TokenInstruction { - CreateTokenAccount = 1, - //SetAuthority = 6, - TokenTransfer = 12, -}; - -enum TokenAuthorityType { - MintTokens = 0, - FreezeAccount = 1, - AccountOwner = 2, - CloseAccount = 3, -}; - -struct AccountMeta { - Address account; - bool isSigner; - bool isReadOnly; - AccountMeta(const Address& address, bool isSigner, bool isReadOnly): account(address), isSigner(isSigner), isReadOnly(isReadOnly) {} -}; - -// An instruction to execute a program -struct Instruction { - // Index into the transaction keys array indicating the program account that - // executes this instruction - Address programId; - // Ordered indices into the transaction keys array indicating which accounts - // to pass to the program - std::vector accounts; - // The program input data - Data data; - - Instruction(const Address& programId, const std::vector& accounts, const Data& data) - : programId(programId), accounts(accounts), data(data) {} - - // This creator creates a default System Transfer instruction - static Instruction createTransfer(const std::vector& accounts, uint64_t value) { - const SystemInstruction type = Transfer; - auto data = Data(); - encode32LE(static_cast(type), data); - encode64LE(static_cast(value), data); - - return Instruction(Address(SYSTEM_PROGRAM_ID_ADDRESS), accounts, data); - } - - static Instruction createAccountWithSeed(const std::vector& accounts, uint64_t value, uint64_t space, const Address& programId, - const Address& voteAddress, uint64_t seedLength, const Address& signer) { - const SystemInstruction type = CreateAccountWithSeed; - auto data = Data(); - std::string seed = voteAddress.string(); - Data vecSeed(seed.begin(), seed.end()); - vecSeed.resize(static_cast(seedLength)); - encode32LE(static_cast(type), data); - append(data, signer.vector()); - encode64LE(static_cast(seedLength), data); - append(data, vecSeed); - encode64LE(static_cast(value), data); - encode64LE(static_cast(space), data); - append(data, programId.vector()); - - return Instruction(Address(SYSTEM_PROGRAM_ID_ADDRESS), accounts, data); - } - - // creates an Initialize Stake instruction - static Instruction createStakeInitialize(const std::vector& accounts, const Address& signer) { - const StakeInstruction type = Initialize; - auto data = Data(); - encode32LE(static_cast(type), data); - append(data, signer.vector()); - append(data, signer.vector()); - auto lockup = Data(48); - append(data, lockup); - - return Instruction(Address(STAKE_PROGRAM_ID_ADDRESS), accounts, data); - } - - // creates a Withdraw Stake instruction - static Instruction createStakeWithdraw(const std::vector& accounts, uint64_t value) { - const StakeInstruction type = Withdraw; - auto data = Data(); - encode32LE(static_cast(type), data); - encode64LE(static_cast(value), data); - - return Instruction(Address(STAKE_PROGRAM_ID_ADDRESS), accounts, data); - } - - // creates a Stake instruction - static Instruction createStake(StakeInstruction type, const std::vector& accounts) { - auto data = Data(); - encode32LE(static_cast(type), data); - - return Instruction(Address(STAKE_PROGRAM_ID_ADDRESS), accounts, data); - } - - // creates a createAccount token instruction. - static Instruction createTokenCreateAccount(const std::vector& accounts) { - auto data = Data(); - return Instruction(Address(ASSOCIATED_TOKEN_PROGRAM_ID_ADDRESS), accounts, data); - } - - // creates a transfer token instruction. - static Instruction createTokenTransfer(const std::vector& accounts, uint64_t value, uint8_t decimals) { - const TokenInstruction type = TokenTransfer; - auto data = Data(); - data.push_back(static_cast(type)); - encode64LE(value, data); - data.push_back(static_cast(decimals)); - - return Instruction(Address(TOKEN_PROGRAM_ID_ADDRESS), accounts, data); - } - - static Instruction createMemo(std::string memo) { - auto data = TW::data(memo); - std::vector accounts; // empty - return Instruction(Address(MEMO_PROGRAM_ID_ADDRESS), accounts, data); - } -}; - -// A compiled instruction -struct CompiledInstruction { - // Index into the transaction keys array indicating the program account that executes this instruction - uint8_t programIdIndex; - // Ordered indices into the transaction keys array indicating which accounts - // to pass to the program - std::vector accounts; - // The program input data - Data data; - - // Reference to the address vector - const std::vector
& addresses; - - /// Supplied address vector is expected to contain all addresses and programId from the instruction; they are replaced by index into the address vector. - CompiledInstruction(const Instruction& instruction, const std::vector
& addresses): addresses(addresses) { - programIdIndex = findAccount(instruction.programId); - for (auto& account: instruction.accounts) { - accounts.push_back(findAccount(account.account)); - } - data = instruction.data; - } - - uint8_t findAccount(const Address& address); -}; - -class Hash { - public: - static const size_t size = 32; - /// Hash data - std::array bytes; - - Hash(const std::string& string) { - const auto data = Base58::bitcoin.decode(string); - std::copy(data.begin(), data.end(), this->bytes.begin()); - } - - std::string encoded() const { return Base58::bitcoin.encode(bytes); } -}; - -class Signature { - public: - static const size_t size = 64; - /// Signature data - std::array bytes; - - Signature(const std::string& string) { - const auto data = Base58::bitcoin.decode(string); - std::copy(data.begin(), data.end(), this->bytes.begin()); - } - Signature(const std::array& bytes) { this->bytes = bytes; } - Signature(const Data& bytes) { std::copy(bytes.begin(), bytes.end(), this->bytes.begin()); } - - bool operator==(const Signature& v) const; -}; - -struct MessageHeader { - // The number of signatures required for this message to be considered - // valid. The signatures must match the first `numRequiredSignatures` of - // `accountKeys`. - uint8_t numRequiredSignatures = 0; - // The last numCreditOnlySignedAccounts of the signed keys are - // credit-only accounts. - uint8_t numCreditOnlySignedAccounts = 0; - // The last numCreditOnlyUnsignedAccounts of the unsigned keys are - // credit-only accounts. - uint8_t numCreditOnlyUnsignedAccounts = 0; -}; - -class Message { - public: - // The message header, identifying signed and credit-only `accountKeys` - MessageHeader header; - // All the account keys used by this transaction - std::vector
accountKeys; - // The id of a recent ledger entry. - Hash recentBlockhash; - // Programs that will be executed in sequence and committed in one atomic - // transaction if all succeed. - std::vector instructions; - - // three buckets of different account types - std::vector
signedAccounts; - std::vector
unsignedAccounts; - std::vector
readOnlyAccounts; - std::vector compiledInstructions; - - Message() : recentBlockhash(NULL_ID_ADDRESS) {}; - - Message(Hash recentBlockhash, const std::vector& instructions) - : recentBlockhash(recentBlockhash) - , instructions(instructions) { - compileAccounts(); - } - - // add an acount, to the corresponding bucket - void addAccount(const AccountMeta& account); - // add an account to accountKeys if not yet present - void addAccountKeys(const Address& account); - // compile the single accounts lists from the buckets - void compileAccounts(); - // compile the instructions; replace instruction accounts with indices - void compileInstructions(); - - static void appendReferences(std::vector& accountMetas, const std::vector
& references) { - for (auto &&reference: references) { - accountMetas.emplace_back(reference, false, true); - } - } - - // This constructor creates a default single-signer Transfer message - static Message createTransfer(const Address& from, const Address& to, uint64_t value, Hash recentBlockhash, - std::string memo = "", std::vector
references = {} - ) { - std::vector instructions; - if (memo.length() > 0) { - // Optional memo. Order: before transfer, as per documentation. - instructions.push_back(Instruction::createMemo(memo)); - } - std::vector accountMetas = { - AccountMeta(from, true, false), - AccountMeta(to, false, false), - }; - appendReferences(accountMetas, references); - instructions.push_back(Instruction::createTransfer(accountMetas, value)); - return Message(recentBlockhash, instructions); - } - - // This constructor creates a create_account_with_seed_and_delegate_stake message - // see delegate_stake() solana/programs/stake/src/stake_instruction.rs - static Message createStake(const Address& signer, const Address& stakeAddress, const Address& voteAddress, uint64_t value, Hash recentBlockhash) { - auto sysvarRentId = Address(SYSVAR_RENT_ID_ADDRESS); - auto sysvarClockId = Address(SYSVAR_CLOCK_ID_ADDRESS); - auto stakeConfigId = Address(STAKE_CONFIG_ID_ADDRESS); - auto sysvarStakeHistoryId = Address(SYSVAR_STAKE_HISTORY_ID_ADDRESS); - auto stakeProgramId = Address(STAKE_PROGRAM_ID_ADDRESS); - std::vector instructions; - instructions.reserve(3); - // create_account_with_seed instruction - Address seed = Address(data(recentBlockhash.bytes.data(), recentBlockhash.bytes.size())); - auto createAccountInstruction = Instruction::createAccountWithSeed(std::vector{ - AccountMeta(signer, true, true), - AccountMeta(stakeAddress, false, false), - AccountMeta(signer, true, true), - }, value, 200, stakeProgramId, seed, 32, signer); - instructions.push_back(createAccountInstruction); - // initialize instruction - auto initializeInstruction = Instruction::createStakeInitialize(std::vector{ - AccountMeta(stakeAddress, false, false), - AccountMeta(sysvarRentId, false, true) - }, signer); - instructions.push_back(initializeInstruction); - // delegate_stake instruction - auto delegateInstruction = Instruction::createStake(DelegateStake, - std::vector{ - AccountMeta(stakeAddress, false, false), // 0. `[WRITE]` Initialized stake account to be delegated - AccountMeta(voteAddress, false, true), // 1. `[]` Vote account to which this stake will be delegated - AccountMeta(sysvarClockId, false, true), // 2. `[]` Clock sysvar - AccountMeta(sysvarStakeHistoryId, false, true), // 3. `[]` Stake history sysvar that carries stake warmup/cooldown history - AccountMeta(stakeConfigId, false, true), // 4. `[]` Address of config account that carries stake config - AccountMeta(signer, true, true), // 5. `[SIGNER]` Stake authority - }); - instructions.push_back(delegateInstruction); - return Message(recentBlockhash, instructions); - } - - // This constructor creates a deactivate_stake message - static Message createStakeDeactivate(const Address& signer, const Address& stakeAddress, Hash recentBlockhash) { - auto sysvarClockId = Address(SYSVAR_CLOCK_ID_ADDRESS); - auto instruction = Instruction::createStake(Deactivate, std::vector{ - AccountMeta(stakeAddress, false, false), // 0. `[WRITE]` Delegated stake account - AccountMeta(sysvarClockId, false, true), // 1. `[]` Clock sysvar - AccountMeta(signer, true, false), // 2. `[SIGNER]` Stake authority - }); - return Message(recentBlockhash, {instruction}); - } - - // This constructor creates a deactivate_stake message with multiple stake accounts - static Message createStakeDeactivateAll(const Address& signer, const std::vector
& stakeAddresses, Hash recentBlockhash) { - auto sysvarClockId = Address(SYSVAR_CLOCK_ID_ADDRESS); - std::vector instructions; - for(auto& address: stakeAddresses) { - auto instruction = Instruction::createStake(Deactivate, std::vector{ - AccountMeta(address, false, false), // 0. `[WRITE]` Delegated stake account - AccountMeta(sysvarClockId, false, true), // 1. `[]` Clock sysvar - AccountMeta(signer, true, false), // 2. `[SIGNER]` Stake authority - }); - instructions.push_back(instruction); - } - return Message(recentBlockhash, instructions); - } - - // This constructor creates a withdraw message, with the signer as the default recipient - static Message createStakeWithdraw(const Address& signer, const Address& stakeAddress, uint64_t value, Hash recentBlockhash) { - auto sysvarClockId = Address(SYSVAR_CLOCK_ID_ADDRESS); - auto sysvarStakeHistoryId = Address(SYSVAR_STAKE_HISTORY_ID_ADDRESS); - auto instruction = Instruction::createStakeWithdraw(std::vector{ - AccountMeta(stakeAddress, false, false), // 0. `[WRITE]` Stake account from which to withdraw - AccountMeta(signer, false, false), // 1. `[WRITE]` Recipient account - AccountMeta(sysvarClockId, false, true), // 2. `[]` Clock sysvar - AccountMeta(sysvarStakeHistoryId, false, true), // 3. `[]` Stake history sysvar that carries stake warmup/cooldown history - AccountMeta(signer, true, false), // 4. `[SIGNER]` Withdraw authority - }, value); - return Message(recentBlockhash, {instruction}); - } - - // This constructor creates a withdraw message, with multiple stake accounts - static Message createStakeWithdrawAll(const Address& signer, const std::vector>& stakes, Hash recentBlockhash) { - auto sysvarClockId = Address(SYSVAR_CLOCK_ID_ADDRESS); - auto sysvarStakeHistoryId = Address(SYSVAR_STAKE_HISTORY_ID_ADDRESS); - std::vector instructions; - for(auto& stake: stakes) { - auto instruction = Instruction::createStakeWithdraw(std::vector{ - AccountMeta(stake.first, false, false), // 0. `[WRITE]` Stake account from which to withdraw - AccountMeta(signer, false, false), // 1. `[WRITE]` Recipient account - AccountMeta(sysvarClockId, false, true), // 2. `[]` Clock sysvar - AccountMeta(sysvarStakeHistoryId, false, true), // 3. `[]` Stake history sysvar that carries stake warmup/cooldown history - AccountMeta(signer, true, false), // 4. `[SIGNER]` Withdraw authority - }, stake.second); - instructions.push_back(instruction); - } - return Message(recentBlockhash, instructions); - } - - // This constructor creates a createAccount token message - // see create_associated_token_account() solana-program-library/associated-token-account/program/src/lib.rs - static Message createTokenCreateAccount(const Address& signer, const Address& otherMainAccount, const Address& tokenMintAddress, const Address& tokenAddress, Hash recentBlockhash) { - auto sysvarRentId = Address(SYSVAR_RENT_ID_ADDRESS); - auto systemProgramId = Address(SYSTEM_PROGRAM_ID_ADDRESS); - auto tokenProgramId = Address(TOKEN_PROGRAM_ID_ADDRESS); - auto instruction = Instruction::createTokenCreateAccount(std::vector{ - AccountMeta(signer, true, false), // fundingAddress, - AccountMeta(tokenAddress, false, false), - AccountMeta(otherMainAccount, false, true), - AccountMeta(tokenMintAddress, false, true), - AccountMeta(systemProgramId, false, true), - AccountMeta(tokenProgramId, false, true), - AccountMeta(sysvarRentId, false, true), - }); - return Message(recentBlockhash, {instruction}); - } - - // This constructor creates a transfer token message. - // see transfer_checked() solana-program-library/token/program/src/instruction.rs - static Message createTokenTransfer(const Address& signer, const Address& tokenMintAddress, - const Address& senderTokenAddress, const Address& recipientTokenAddress, uint64_t amount, uint8_t decimals, Hash recentBlockhash, - std::string memo = "", std::vector
references = {} - ) { - std::vector instructions; - if (memo.length() > 0) { - // Optional memo. Order: before transfer, as per documentation. - instructions.push_back(Instruction::createMemo(memo)); - } - std::vector accountMetas = { - AccountMeta(senderTokenAddress, false, false), - AccountMeta(tokenMintAddress, false, true), - AccountMeta(recipientTokenAddress, false, false), - AccountMeta(signer, true, false), - }; - appendReferences(accountMetas, references); - instructions.push_back(Instruction::createTokenTransfer(accountMetas, amount, decimals)); - return Message(recentBlockhash, instructions); - } - - // This constructor creates a createAndTransferToken message, combining createAccount and transfer. - static Message createTokenCreateAndTransfer(const Address& signer, const Address& recipientMainAddress, const Address& tokenMintAddress, - const Address& recipientTokenAddress, const Address& senderTokenAddress, uint64_t amount, uint8_t decimals, Hash recentBlockhash, - std::string memo = "", std::vector
references = {} - ) { - const auto sysvarRentId = Address(SYSVAR_RENT_ID_ADDRESS); - const auto systemProgramId = Address(SYSTEM_PROGRAM_ID_ADDRESS); - const auto tokenProgramId = Address(TOKEN_PROGRAM_ID_ADDRESS); - std::vector instructions; - instructions.reserve(3); - instructions.emplace_back(Instruction::createTokenCreateAccount(std::vector{ - AccountMeta(signer, true, false), // fundingAddress, - AccountMeta(recipientTokenAddress, false, false), - AccountMeta(recipientMainAddress, false, true), - AccountMeta(tokenMintAddress, false, true), - AccountMeta(systemProgramId, false, true), - AccountMeta(tokenProgramId, false, true), - AccountMeta(sysvarRentId, false, true), - })); - if (memo.length() > 0) { - // Optional memo. Order: before transfer, as per documentation. - instructions.emplace_back(Instruction::createMemo(memo)); - } - std::vector accountMetas = { - AccountMeta(senderTokenAddress, false, false), - AccountMeta(tokenMintAddress, false, true), - AccountMeta(recipientTokenAddress, false, false), - AccountMeta(signer, true, false), - }; - appendReferences(accountMetas, references); - instructions.push_back(Instruction::createTokenTransfer(accountMetas, amount, decimals)); - return Message(recentBlockhash, instructions); - } -}; - class Transaction { public: // Signatures std::vector signatures; // The message to sign - Message message; + LegacyMessage message; - Transaction(const Message& message) : message(message) { + Transaction(const LegacyMessage& message) : message(message) { this->signatures.resize(message.header.numRequiredSignatures, Signature(defaultSignature)); } // Default basic transfer transaction - Transaction(const Address& from, const Address& to, uint64_t value, Hash recentBlockhash, std::string memo = "", std::vector
references = {}) - : message(Message::createTransfer(from, to, value, recentBlockhash, memo, references)) { + Transaction(const Address& from, const Address& to, uint64_t value, Data recentBlockhash, std::string memo = "", std::vector
references = {}) + : message(LegacyMessage::createTransfer(from, to, value, recentBlockhash, memo, references)) { this->signatures.resize(1, Signature(defaultSignature)); } diff --git a/src/Solana/V0Message.h b/src/Solana/V0Message.h new file mode 100644 index 00000000000..a3f7c18a165 --- /dev/null +++ b/src/Solana/V0Message.h @@ -0,0 +1,19 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Solana/LegacyMessage.h" +#include "Solana/AddressLookupTable.h" + +namespace TW::Solana { + +struct V0Message { + LegacyMessage msg; + MessageAddressTableLookup addressTableLookups; +}; + +} diff --git a/src/Solana/VersionedMessage.cpp b/src/Solana/VersionedMessage.cpp new file mode 100644 index 00000000000..420bd64ea18 --- /dev/null +++ b/src/Solana/VersionedMessage.cpp @@ -0,0 +1,67 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Solana/VersionedMessage.h" +#include "Solana/Constants.h" +#include "Solana/Encoding.h" + +namespace TW::Solana { + +Data serialize(const VersionedMessage& message) { + auto visit_functor = [](const VersionedMessage& message) -> Data { + if (auto* msg = std::get_if(&message); msg) { + Data out; + append(out, MESSAGE_VERSION_PREFIX); + append(out, msg->msg.serialize()); + append(out, shortVecLength(msg->addressTableLookups)); + return out; + } else if (auto* legacyMsg = std::get_if(&message); legacyMsg) { + return legacyMsg->serialize(); + } else { + return {}; + } + }; + + return std::visit(visit_functor, message); +} + +MessageHeader header(const VersionedMessage& message) { + auto visit_functor = [](const VersionedMessage& message) -> MessageHeader { + if (auto* msg = std::get_if(&message); msg) { + return msg->msg.header; + } else if (auto* legacyMsg = std::get_if(&message); legacyMsg) { + return legacyMsg->header; + } else { + return {}; + } + }; + + return std::visit(visit_functor, message); +} + +std::vector
accountKeys(const VersionedMessage& message) { + auto visit_functor = [](const VersionedMessage& message) -> std::vector
{ + if (auto* msg = std::get_if(&message); msg) { + return msg->msg.accountKeys; + } else if (auto* legacyMsg = std::get_if(&message); legacyMsg) { + return legacyMsg->accountKeys; + } else { + return {}; + } + }; + + return std::visit(visit_functor, message); +} + +void updateRecentHash(VersionedMessage& message, const Data& recentHash) { + if (auto* msg = std::get_if(&message); msg) { + msg->msg.mRecentBlockHash = recentHash; + } else if (auto* legacyMsg = std::get_if(&message); legacyMsg) { + legacyMsg->mRecentBlockHash = recentHash; + } +} + +} // namespace TW::Solana diff --git a/src/Solana/VersionedMessage.h b/src/Solana/VersionedMessage.h new file mode 100644 index 00000000000..0428945b812 --- /dev/null +++ b/src/Solana/VersionedMessage.h @@ -0,0 +1,21 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include +#include "Solana/V0Message.h" +#include "Solana/LegacyMessage.h" +#include "Solana/MessageHeader.h" + +namespace TW::Solana { + using VersionedMessage = std::variant; + + Data serialize(const VersionedMessage& message); + MessageHeader header(const VersionedMessage& message); + std::vector
accountKeys(const VersionedMessage& message); + void updateRecentHash(VersionedMessage& message, const Data& recentHash); +} diff --git a/src/Solana/VersionedTransaction.cpp b/src/Solana/VersionedTransaction.cpp new file mode 100644 index 00000000000..548617f09be --- /dev/null +++ b/src/Solana/VersionedTransaction.cpp @@ -0,0 +1,37 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include "Solana/VersionedTransaction.h" +#include "Solana/Encoding.h" + +namespace TW::Solana { + +std::string VersionedTransaction::serialize() const { + Data buffer; + + append(buffer, shortVecLength(this->signatures)); + for (auto signature : this->signatures) { + Data signature_vec(signature.bytes.begin(), signature.bytes.end()); + append(buffer, signature_vec); + } + append(buffer, this->messageData()); + + return Base58::bitcoin.encode(buffer); +} + +Data VersionedTransaction::messageData() const { + return Solana::serialize(this->message); +} + +uint8_t VersionedTransaction::getAccountIndex(Address publicKey) { + const auto accountKeys = Solana::accountKeys(this->message); + auto item = std::find(accountKeys.begin(), accountKeys.end(), publicKey); + if (item == accountKeys.end()) { + throw std::invalid_argument("publicKey not found in message.accountKeys"); + } + return (uint8_t)std::distance(accountKeys.begin(), item); +} +} // namespace TW::Solana diff --git a/src/Solana/VersionedTransaction.h b/src/Solana/VersionedTransaction.h new file mode 100644 index 00000000000..02af2d377be --- /dev/null +++ b/src/Solana/VersionedTransaction.h @@ -0,0 +1,46 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "Solana/Address.h" +#include "Solana/VersionedMessage.h" +#include "Solana/Signature.h" +#include "Data.h" +#include "BinaryCoding.h" + +#include +#include + +namespace TW::Solana { + +class VersionedTransaction { + public: + // Signatures + std::vector signatures; + // The message to sign + VersionedMessage message; + + VersionedTransaction(const VersionedMessage& message) : message(message) { + this->signatures.resize(header(message).numRequiredSignatures, Signature(defaultSignature)); + } + + // Default basic transfer transaction + VersionedTransaction(const Address& from, const Address& to, uint64_t value, Data recentBlockhash, std::string memo = "", std::vector
references = {}) + : message(VersionedMessage(LegacyMessage::createTransfer(from, to, value, recentBlockhash, memo, references))) { + this->signatures.resize(1, Signature(defaultSignature)); + } + + public: + std::string serialize() const; + std::vector messageData() const; + uint8_t getAccountIndex(Address publicKey); + + private: + TW::Data defaultSignature = TW::Data(64); +}; + +} // namespace TW::Solana diff --git a/src/proto/Solana.proto b/src/proto/Solana.proto index 07fb6a00f58..67a250cbffe 100644 --- a/src/proto/Solana.proto +++ b/src/proto/Solana.proto @@ -138,17 +138,19 @@ message SigningInput { // Relatively recent block hash string recent_blockhash = 2; + bool v0_msg = 3; + // Payload message oneof transaction_type { - Transfer transfer_transaction = 3; - DelegateStake delegate_stake_transaction = 4; - DeactivateStake deactivate_stake_transaction = 5; - DeactivateAllStake deactivate_all_stake_transaction = 6; - WithdrawStake withdraw_transaction = 7; - WithdrawAllStake withdraw_all_transaction = 8; - CreateTokenAccount create_token_account_transaction = 9; - TokenTransfer token_transfer_transaction = 10; - CreateAndTransferToken create_and_transfer_token_transaction = 11; + Transfer transfer_transaction = 4; + DelegateStake delegate_stake_transaction = 5; + DeactivateStake deactivate_stake_transaction = 6; + DeactivateAllStake deactivate_all_stake_transaction = 7; + WithdrawStake withdraw_transaction = 8; + WithdrawAllStake withdraw_all_transaction = 9; + CreateTokenAccount create_token_account_transaction = 10; + TokenTransfer token_transfer_transaction = 11; + CreateAndTransferToken create_and_transfer_token_transaction = 12; } } diff --git a/tests/chains/Solana/ProgramTests.cpp b/tests/chains/Solana/ProgramTests.cpp index f943622e28b..2b443c6ddfb 100644 --- a/tests/chains/Solana/ProgramTests.cpp +++ b/tests/chains/Solana/ProgramTests.cpp @@ -27,14 +27,14 @@ TEST(SolanaStakeProgram, addressFromValidatorSeed) { TEST(SolanaStakeProgram, addressFromRecentBlockhash) { { auto user = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); - Solana::Hash recentBlockhash("11111111111111111111111111111111"); + Data recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); auto programId = Address("Stake11111111111111111111111111111111111111"); auto expected = Address("GQDDc5EVGJZFC7AvpEJ8eoCQ75Yy4gr7eu17frCjvQRQ"); EXPECT_EQ(StakeProgram::addressFromRecentBlockhash(user, recentBlockhash, programId), expected); } { auto user = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); - Solana::Hash recentBlockhash("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); + Data recentBlockhash = Base58::bitcoin.decode("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); auto programId = Address("Stake11111111111111111111111111111111111111"); auto expected = Address("2Kos1xJRBq3Ae1GnVNBx7HgJhq8KvdUe2bXE4QGdNaXb"); EXPECT_EQ(StakeProgram::addressFromRecentBlockhash(user, recentBlockhash, programId), expected); diff --git a/tests/chains/Solana/SignerTests.cpp b/tests/chains/Solana/SignerTests.cpp index 875300fb5e2..b4ee4910b8e 100644 --- a/tests/chains/Solana/SignerTests.cpp +++ b/tests/chains/Solana/SignerTests.cpp @@ -92,8 +92,8 @@ TEST(SolanaSigner, SingleSignTransaction) { const auto from = Address(publicKey); auto to = Address("EN2sCsJ1WDV8UFqsiTXHcUPUxQ4juE71eCknHYYMifkd"); - Solana::Hash recentBlockhash("11111111111111111111111111111111"); - auto transaction = Transaction(from, to, 42, recentBlockhash); + auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto transaction = VersionedTransaction(from, to, 42, recentBlockhash); std::vector signerKeys; signerKeys.push_back(privateKey); @@ -132,8 +132,8 @@ TEST(SolanaSigner, SignTransactionToSelf) { const auto from = Address(publicKey); auto to = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); - Solana::Hash recentBlockhash("11111111111111111111111111111111"); - auto transaction = Transaction(from, to, 42, recentBlockhash); + auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto transaction = VersionedTransaction(from, to, 42, recentBlockhash); std::vector signerKeys; signerKeys.push_back(privateKey); @@ -177,15 +177,15 @@ TEST(SolanaSigner, MultipleSignTransaction) { MessageHeader header = {2, 0, 1}; std::vector
accountKeys = {address0, address1, programId}; - Solana::Hash recentBlockhash("11111111111111111111111111111111"); - Message message; + auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + LegacyMessage message; message.header = header; message.accountKeys = accountKeys; - message.recentBlockhash = recentBlockhash; + message.mRecentBlockHash = recentBlockhash; message.instructions = instructions; message.compileInstructions(); - auto transaction = Transaction(message); + auto transaction = VersionedTransaction(VersionedMessage(message)); std::vector signerKeys; // Sign order should not matter @@ -220,14 +220,14 @@ TEST(SolanaSigner, SignUpdateBlockhash) { const auto from = Address(publicKey); auto to = Address("4iSnyfDKaejniaPc2pBBckwQqV3mDS93go15NdxWJq2y"); - Solana::Hash recentBlockhash("11111111111111111111111111111111"); - auto transaction = Transaction(from, to, 42, recentBlockhash); + auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto transaction = VersionedTransaction(from, to, 42, recentBlockhash); std::vector signerKeys; signerKeys.push_back(privateKey); Signer::sign(signerKeys, transaction); - Solana::Hash newBlockhash("GgBaCs3NCBuZN12kCJgAW63ydqohFkHEdfdEXBPzLHq"); + auto newBlockhash = Base58::bitcoin.decode("GgBaCs3NCBuZN12kCJgAW63ydqohFkHEdfdEXBPzLHq"); Signer::signUpdateBlockhash(signerKeys, transaction, newBlockhash); std::vector expectedSignatures; @@ -279,11 +279,11 @@ TEST(SolanaSigner, SignDelegateStakeV2) { auto voteAddress = Address("4jpwTqt1qZoR7u6u639z2AngYFGN3nakvKhowcnRZDEC"); auto programId = Address("Stake11111111111111111111111111111111111111"); - Solana::Hash recentBlockhash("11111111111111111111111111111111"); + auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); auto stakeAddress = StakeProgram::addressFromRecentBlockhash(signer, recentBlockhash, programId); - auto message = Message::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); - auto transaction = Transaction(message); + auto message = LegacyMessage::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); + auto transaction = VersionedTransaction(VersionedMessage(message)); std::vector signerKeys; signerKeys.push_back(privateKeySigner); @@ -307,11 +307,11 @@ TEST(SolanaSigner, SignDelegateStakeV1) { auto voteAddress = Address("4jpwTqt1qZoR7u6u639z2AngYFGN3nakvKhowcnRZDEC"); auto programId = Address("Stake11111111111111111111111111111111111111"); - Solana::Hash recentBlockhash("11111111111111111111111111111111"); + auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); auto stakeAddress = StakeProgram::addressFromValidatorSeed(signer, voteAddress, programId); - auto message = Message::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); - auto transaction = Transaction(message); + auto message = LegacyMessage::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); + auto transaction = VersionedTransaction(VersionedMessage(message)); std::vector signerKeys; signerKeys.push_back(privateKeySigner); @@ -335,10 +335,10 @@ TEST(SolanaSigner, SignCreateTokenAccount) { auto token = Address("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"); auto tokenAddress = Address("EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); - Solana::Hash recentBlockhash("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); + auto recentBlockhash = Base58::bitcoin.decode("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); - auto message = Message::createTokenCreateAccount(signer, signer, token, tokenAddress, recentBlockhash); - auto transaction = Transaction(message); + auto message = LegacyMessage::createTokenCreateAccount(signer, signer, token, tokenAddress, recentBlockhash); + auto transaction = VersionedTransaction(VersionedMessage(message)); std::vector signerKeys; signerKeys.push_back(privateKeySigner); @@ -365,10 +365,10 @@ TEST(SolanaSigner, SignCreateTokenAccountForOther_3E6UFV) { auto otherMainAddress = Address("3xJ3MoUVFPNFEHfWdtNFa8ajXUHsJPzXcBSWMKLd76ft"); auto token = Address("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"); auto tokenAddress = Address("67BrwFYt7qUnbAcYBVx7sQ4jeD2KWN1ohP6bMikmmQV3"); - Solana::Hash recentBlockhash("HmWyvrif3QfZJnDiRyrojmH9iLr7eMxxqiC9RJWFeunr"); + auto recentBlockhash = Base58::bitcoin.decode("HmWyvrif3QfZJnDiRyrojmH9iLr7eMxxqiC9RJWFeunr"); - auto message = Message::createTokenCreateAccount(signer, otherMainAddress, token, tokenAddress, recentBlockhash); - auto transaction = Transaction(message); + auto message = LegacyMessage::createTokenCreateAccount(signer, otherMainAddress, token, tokenAddress, recentBlockhash); + auto transaction = VersionedTransaction(VersionedMessage(message)); std::vector signerKeys; signerKeys.push_back(privateKeySigner); @@ -392,11 +392,11 @@ TEST(SolanaSigner, SignTransferToken_3vZ67C) { auto recipientTokenAddress = Address("3WUX9wASxyScbA7brDipioKfXS1XEYkQ4vo3Kej9bKei"); uint64_t amount = 4000; uint8_t decimals = 6; - Solana::Hash recentBlockhash("CNaHfvqePgGYMvtYi9RuUdVxDYttr1zs4TWrTXYabxZi"); + auto recentBlockhash = Base58::bitcoin.decode("CNaHfvqePgGYMvtYi9RuUdVxDYttr1zs4TWrTXYabxZi"); - auto message = Message::createTokenTransfer(signer, token, + auto message = LegacyMessage::createTokenTransfer(signer, token, senderTokenAddress, recipientTokenAddress, amount, decimals, recentBlockhash); - auto transaction = Transaction(message); + auto transaction = VersionedTransaction(VersionedMessage(message)); std::vector signerKeys; signerKeys.push_back(privateKeySigner); diff --git a/tests/chains/Solana/TWAnySignerTests.cpp b/tests/chains/Solana/TWAnySignerTests.cpp index 5fd474bbf0e..de5ee2cd869 100644 --- a/tests/chains/Solana/TWAnySignerTests.cpp +++ b/tests/chains/Solana/TWAnySignerTests.cpp @@ -41,6 +41,24 @@ TEST(TWAnySignerSolana, SignTransfer) { ASSERT_EQ(output.unsigned_tx(), "87PYsiS4MUU1UqXrsDoCBmD5FcKsXhwEBD8hc4zbq78yePu7bLENmbnmjmVbsj4VvaxnZhy4bERndPFzjSRH5WpwKwMLSCKvn9eSDmPESNcdkqne2UdMfWiFoq8ZeQBnF9h98dP8GM9kfzWPjvLmhjwuwA1E2k5WCtfii7LKQ34v6AtmFQGZqgdKiNqygP7ZKusHWGT8ZkTZ"); } +TEST(TWAnySignerSolana, SignV0Transfer) { + // Successfully broadcasted: https://explorer.solana.com/tx/4ffBzXxLPYEEdCYpQGETkCTCCsH6iTdmKzwUZXZZgFemdhRpxQwboguFFoKCeGF3SsZPzuwwE7LbRwLgJbsyRqyP?cluster=testnet + auto privateKey = parse_hex("833a053c59e78138a3ed090459bc6743cca6a9cbc2809a7bf5dbc7939b8775c8"); + auto input = Proto::SigningInput(); + + auto& message = *input.mutable_transfer_transaction(); + message.set_recipient("6pEfiZjMycJY4VA2FtAbKgYvRwzXDpxY58Xp4b7FQCz9"); + message.set_value((uint64_t)5000L); + input.set_private_key(privateKey.data(), privateKey.size()); + input.set_recent_blockhash("HxKwWFTHixCu8aw35J1uxAX6yUhLHkFCdJJdK4y98Gyj"); + input.set_v0_msg(true); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeSolana); + + ASSERT_EQ(output.encoded(), "6NijVxwQoDjqt6A41HXCK9kXwNDp48uLgvRyE8uz6NY5dEzaEDLzjzuMnc5TGatHZZUXehKrzUGzbg9jPSdn6pVsMc9TXNH6JGe5RJLmHwWey3MC1p8Hs2zhjw5P439P57NToatraDX9ZwvBtK4EzZzRjWbyGdicheTPjeYKCzvPCLxDkTFtPCM9VZGGXSN2Bne92NLDvf6ntNm5pxsPkZGxPe4w9Eq26gkE83hZyrYXKaiDh8TbqbHatSkw"); +} + TEST(TWAnySignerSolana, SignTransferToSelf) { auto privateKey = Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); auto input = Proto::SigningInput(); diff --git a/tests/chains/Solana/TransactionTests.cpp b/tests/chains/Solana/TransactionTests.cpp index c6ff726f613..c8c4458ec3e 100644 --- a/tests/chains/Solana/TransactionTests.cpp +++ b/tests/chains/Solana/TransactionTests.cpp @@ -18,7 +18,7 @@ namespace TW::Solana { TEST(SolanaTransaction, TransferMessageData) { auto from = Address("6eoo7i1khGhVm8tLBMAdq4ax2FxkKP4G7mCcfHyr3STN"); auto to = Address("56B334QvCDMSirsmtEJGfanZm8GqeQarrSjdAb2MbeNM"); - Solana::Hash recentBlockhash("11111111111111111111111111111111"); + auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); auto transaction = Transaction(from, to, 42, recentBlockhash); auto expectedHex = @@ -32,7 +32,7 @@ TEST(SolanaTransaction, TransferMessageData) { TEST(SolanaTransaction, TransferSerializeTransaction) { auto from = Address("41a5jYky56M6EWDsFfLaZRxoRtgAJSRWxJnxaJNJELn5"); auto to = Address("4iSnyfDKaejniaPc2pBBckwQqV3mDS93go15NdxWJq2y"); - Solana::Hash recentBlockhash("11111111111111111111111111111111"); + auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); auto transaction = Transaction(from, to, 42, recentBlockhash); Signature signature( "46SRiQGvtPb1iivDfnuC3dW1GzXkfQPTjdUyvFqF2sdPvFrsfx94fys2xpNKR6UiAj7RgKWdJG6mEfe85up6i1JT"); @@ -50,7 +50,7 @@ TEST(SolanaTransaction, TransferSerializeTransaction) { TEST(SolanaTransaction, TransferTransactionPayToSelf) { auto from = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); auto to = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); - Solana::Hash recentBlockhash("11111111111111111111111111111111"); + auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); auto transaction = Transaction(from, to, 42, recentBlockhash); Signature signature( "3CFWDEK51noPJP4v2t8JZ3qj7kC7kLKyws9akfHMyuJnQ35EtzBptHqvaHfeswiLsvUSxzMVNoj4CuRxWtDD9zB1"); @@ -67,7 +67,7 @@ TEST(SolanaTransaction, TransferTransactionPayToSelf) { TEST(SolanaTransaction, TransferWithMemoAndReferenceTransaction) { const auto from = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); const auto to = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); - const Solana::Hash recentBlockhash("11111111111111111111111111111111"); + auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); const auto memo = "HelloSolana73"; std::vector
references = {Address("GaeTAQZyhVEocTC7iY8GztSyY5cBAJTkAUUA1kLFLMV")}; auto transaction = Transaction(from, to, 42, recentBlockhash, memo, references); @@ -83,9 +83,9 @@ TEST(SolanaTransaction, StakeSerializeTransactionV2) { auto signer = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); auto voteAddress = Address("4jpwTqt1qZoR7u6u639z2AngYFGN3nakvKhowcnRZDEC"); auto programId = Address("Stake11111111111111111111111111111111111111"); - Solana::Hash recentBlockhash("11111111111111111111111111111111"); + auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); auto stakeAddress = StakeProgram::addressFromRecentBlockhash(signer, recentBlockhash, programId); - auto message = Message::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); + auto message = LegacyMessage::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); auto transaction = Transaction(message); Signature signature( "2GXRrZMMWTaY8ycwFTLFojAVZ1EepFqnVGW7b5bBuuKPiVrpaPXMAwyYsSmYc2okCa1MuJjNguu1emSJRtZxVdwt"); @@ -100,9 +100,9 @@ TEST(SolanaTransaction, StakeSerializeTransactionV1) { auto signer = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); auto voteAddress = Address("4jpwTqt1qZoR7u6u639z2AngYFGN3nakvKhowcnRZDEC"); auto programId = Address("Stake11111111111111111111111111111111111111"); - Solana::Hash recentBlockhash("11111111111111111111111111111111"); + auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); auto stakeAddress = StakeProgram::addressFromValidatorSeed(signer, voteAddress, programId); - auto message = Message::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); + auto message = LegacyMessage::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); auto transaction = Transaction(message); Signature signature( "2GXRrZMMWTaY8ycwFTLFojAVZ1EepFqnVGW7b5bBuuKPiVrpaPXMAwyYsSmYc2okCa1MuJjNguu1emSJRtZxVdwt"); @@ -117,8 +117,8 @@ TEST(SolanaTransaction, CreateTokenAccountTransaction) { auto signer = Address("B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); auto token = Address("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"); auto tokenAddress = Address("EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); - Solana::Hash recentBlockhash("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); - auto message = Message::createTokenCreateAccount(signer, signer, token, tokenAddress, recentBlockhash); + auto recentBlockhash = Base58::bitcoin.decode("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); + auto message = LegacyMessage::createTokenCreateAccount(signer, signer, token, tokenAddress, recentBlockhash); EXPECT_EQ(message.header.numRequiredSignatures, 1); EXPECT_EQ(message.header.numCreditOnlySignedAccounts, 0); EXPECT_EQ(message.header.numCreditOnlyUnsignedAccounts, 5); @@ -130,7 +130,7 @@ TEST(SolanaTransaction, CreateTokenAccountTransaction) { EXPECT_EQ(message.accountKeys[4].string(), "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); EXPECT_EQ(message.accountKeys[5].string(), "SysvarRent111111111111111111111111111111111"); EXPECT_EQ(message.accountKeys[6].string(), "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); - EXPECT_EQ(Base58::bitcoin.encode(message.recentBlockhash.bytes), "9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); + EXPECT_EQ(Base58::bitcoin.encode(message.mRecentBlockHash), "9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); ASSERT_EQ(message.instructions.size(), 1ul); EXPECT_EQ(message.instructions[0].programId.string(), "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); ASSERT_EQ(message.instructions[0].accounts.size(), 7ul); @@ -159,8 +159,8 @@ TEST(SolanaTransaction, TransferTokenTransaction_3vZ67C) { auto recipientTokenAddress = Address("3WUX9wASxyScbA7brDipioKfXS1XEYkQ4vo3Kej9bKei"); uint64_t amount = 4000; uint8_t decimals = 6; - Solana::Hash recentBlockhash("CNaHfvqePgGYMvtYi9RuUdVxDYttr1zs4TWrTXYabxZi"); - auto message = Message::createTokenTransfer(signer, token, senderTokenAddress, recipientTokenAddress, amount, decimals, recentBlockhash); + auto recentBlockhash = Base58::bitcoin.decode("CNaHfvqePgGYMvtYi9RuUdVxDYttr1zs4TWrTXYabxZi"); + auto message = LegacyMessage::createTokenTransfer(signer, token, senderTokenAddress, recipientTokenAddress, amount, decimals, recentBlockhash); EXPECT_EQ(message.header.numRequiredSignatures, 1); EXPECT_EQ(message.header.numCreditOnlySignedAccounts, 0); EXPECT_EQ(message.header.numCreditOnlyUnsignedAccounts, 2); From 1dabdbe26bbf0067e62270aba2bac1ecedd11cdb Mon Sep 17 00:00:00 2001 From: Tyera Date: Tue, 21 Feb 2023 16:55:56 -0700 Subject: [PATCH 200/497] [Solana] Refine `programId` and `accounts` comments, `CreditOnly` -> `ReadOnly` (#2939) * Fixup Instruction comments * Update MessageHeader field names --- src/Solana/Instruction.h | 6 ++---- src/Solana/LegacyMessage.cpp | 4 ++-- src/Solana/MessageHeader.h | 12 ++++++------ tests/chains/Solana/TransactionTests.cpp | 8 ++++---- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/Solana/Instruction.h b/src/Solana/Instruction.h index 7c9dd24cc05..535fcb25ccd 100644 --- a/src/Solana/Instruction.h +++ b/src/Solana/Instruction.h @@ -38,11 +38,9 @@ enum TokenInstruction { // An instruction to execute a program struct Instruction { - // Index into the transaction keys array indicating the program account that - // executes this instruction + // The address of the program account that executes this instruction Address programId; - // Ordered indices into the transaction keys array indicating which accounts - // to pass to the program + // List of accounts to pass to the program std::vector accounts; // The program input data Data data; diff --git a/src/Solana/LegacyMessage.cpp b/src/Solana/LegacyMessage.cpp index 42f411578c9..d997465e8b9 100644 --- a/src/Solana/LegacyMessage.cpp +++ b/src/Solana/LegacyMessage.cpp @@ -37,8 +37,8 @@ Data LegacyMessage::serialize() const { Data buffer; buffer.push_back(this->header.numRequiredSignatures); - buffer.push_back(this->header.numCreditOnlySignedAccounts); - buffer.push_back(this->header.numCreditOnlyUnsignedAccounts); + buffer.push_back(this->header.numReadOnlySignedAccounts); + buffer.push_back(this->header.numReadOnlyUnsignedAccounts); append(buffer, shortVecLength
(this->accountKeys)); for (auto account_key : this->accountKeys) { Data account_key_vec(account_key.bytes.begin(), account_key.bytes.end()); diff --git a/src/Solana/MessageHeader.h b/src/Solana/MessageHeader.h index bb06ce56076..f01c2142305 100644 --- a/src/Solana/MessageHeader.h +++ b/src/Solana/MessageHeader.h @@ -13,10 +13,10 @@ struct MessageHeader { // valid. The signatures must match the first `numRequiredSignatures` of // `accountKeys`. uint8_t numRequiredSignatures = 0; - // The last numCreditOnlySignedAccounts of the signed keys are - // credit-only accounts. - uint8_t numCreditOnlySignedAccounts = 0; - // The last numCreditOnlyUnsignedAccounts of the unsigned keys are - // credit-only accounts. - uint8_t numCreditOnlyUnsignedAccounts = 0; + // The last numRequiredSignatures of the signed keys are + // read-only accounts. + uint8_t numReadOnlySignedAccounts = 0; + // The last numReadOnlyUnsignedAccounts of the unsigned keys are + // read-only accounts. + uint8_t numReadOnlyUnsignedAccounts = 0; }; diff --git a/tests/chains/Solana/TransactionTests.cpp b/tests/chains/Solana/TransactionTests.cpp index c8c4458ec3e..0558f31605e 100644 --- a/tests/chains/Solana/TransactionTests.cpp +++ b/tests/chains/Solana/TransactionTests.cpp @@ -120,8 +120,8 @@ TEST(SolanaTransaction, CreateTokenAccountTransaction) { auto recentBlockhash = Base58::bitcoin.decode("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); auto message = LegacyMessage::createTokenCreateAccount(signer, signer, token, tokenAddress, recentBlockhash); EXPECT_EQ(message.header.numRequiredSignatures, 1); - EXPECT_EQ(message.header.numCreditOnlySignedAccounts, 0); - EXPECT_EQ(message.header.numCreditOnlyUnsignedAccounts, 5); + EXPECT_EQ(message.header.numReadOnlySignedAccounts, 0); + EXPECT_EQ(message.header.numReadOnlyUnsignedAccounts, 5); ASSERT_EQ(message.accountKeys.size(), 7ul); EXPECT_EQ(message.accountKeys[0].string(), "B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); EXPECT_EQ(message.accountKeys[1].string(), "EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); @@ -162,8 +162,8 @@ TEST(SolanaTransaction, TransferTokenTransaction_3vZ67C) { auto recentBlockhash = Base58::bitcoin.decode("CNaHfvqePgGYMvtYi9RuUdVxDYttr1zs4TWrTXYabxZi"); auto message = LegacyMessage::createTokenTransfer(signer, token, senderTokenAddress, recipientTokenAddress, amount, decimals, recentBlockhash); EXPECT_EQ(message.header.numRequiredSignatures, 1); - EXPECT_EQ(message.header.numCreditOnlySignedAccounts, 0); - EXPECT_EQ(message.header.numCreditOnlyUnsignedAccounts, 2); + EXPECT_EQ(message.header.numReadOnlySignedAccounts, 0); + EXPECT_EQ(message.header.numReadOnlyUnsignedAccounts, 2); ASSERT_EQ(message.accountKeys.size(), 5ul); ASSERT_EQ(message.instructions.size(), 1ul); EXPECT_EQ(message.instructions[0].programId.string(), "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); From 90b18837742fca65edfaaf0ca2fececf51bfbc1e Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Wed, 22 Feb 2023 14:16:48 +0100 Subject: [PATCH 201/497] [Base58]: Move base58 implementation to rust (#2944) --- rust/Cargo.lock | 7 + rust/Cargo.toml | 1 + rust/src/encoding/base32.rs | 12 +- rust/src/encoding/base58.rs | 99 +++++++++ rust/src/encoding/mod.rs | 1 + rust/src/memory/mod.rs | 10 + src/Aeternity/Address.cpp | 6 +- src/Aeternity/Signer.cpp | 2 +- src/Aeternity/Transaction.cpp | 2 +- src/Base58.cpp | 196 ------------------ src/Base58.h | 85 ++++---- src/Base58Address.h | 8 +- src/Bitcoin/Script.cpp | 2 +- src/Cardano/AddressV2.cpp | 4 +- src/Decred/Address.cpp | 6 +- src/EOS/Address.cpp | 4 +- src/EOS/Transaction.cpp | 2 +- src/FIO/Address.cpp | 4 +- src/FIO/Signer.cpp | 2 +- src/Groestlcoin/Address.cpp | 8 +- src/HDWallet.cpp | 4 +- src/NEAR/Address.cpp | 2 +- src/NEO/Address.cpp | 2 +- src/NULS/Address.cpp | 6 +- src/Nebulas/Address.cpp | 6 +- src/Polkadot/SS58Address.cpp | 6 +- src/Solana/Address.cpp | 6 +- src/Solana/LegacyMessage.h | 2 +- src/Solana/Program.cpp | 2 +- src/Solana/Signature.h | 2 +- src/Solana/Signer.cpp | 4 +- src/Solana/Transaction.cpp | 2 +- src/Solana/VersionedTransaction.cpp | 2 +- src/Tezos/Address.cpp | 6 +- src/Tezos/BinaryCoding.cpp | 6 +- src/Tezos/Forging.cpp | 4 +- src/Tezos/OperationList.cpp | 4 +- src/Tron/Address.cpp | 2 +- src/Tron/Signer.cpp | 34 +-- src/Waves/Address.cpp | 6 +- src/Waves/Transaction.cpp | 24 +-- src/XRP/Address.cpp | 6 +- src/XRP/XAddress.cpp | 6 +- src/interface/TWBase58.cpp | 8 +- .../chains/Bitcoin/TWBitcoinSigningTests.cpp | 2 +- tests/chains/FIO/SignerTests.cpp | 2 +- tests/chains/NEAR/AddressTests.cpp | 2 +- tests/chains/NEAR/SerializationTests.cpp | 54 ++--- tests/chains/NEAR/SignerTests.cpp | 6 +- tests/chains/NEAR/TWAnySignerTests.cpp | 10 +- tests/chains/Nebulas/AddressTests.cpp | 4 +- tests/chains/Solana/AddressTests.cpp | 16 +- tests/chains/Solana/ProgramTests.cpp | 18 +- tests/chains/Solana/SignerTests.cpp | 62 +++--- tests/chains/Solana/TWAnySignerTests.cpp | 34 +-- tests/chains/Solana/TransactionTests.cpp | 18 +- tests/chains/Tezos/SignerTests.cpp | 2 +- tests/chains/Waves/TWAnySignerTests.cpp | 2 +- 58 files changed, 376 insertions(+), 469 deletions(-) create mode 100644 rust/src/encoding/base58.rs delete mode 100644 src/Base58.cpp diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 601d9de59d3..ca96211a88d 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -143,6 +143,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + [[package]] name = "bumpalo" version = "3.12.0" @@ -1040,6 +1046,7 @@ version = "0.1.0" dependencies = [ "base64 0.21.0", "bcs", + "bs58", "hex", "move-core-types", "starknet-crypto", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 7752a93202d..939ac5c6dbb 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -17,5 +17,6 @@ starknet-signers = "0.1.0" bcs = "0.1.4" hex = "0.4.3" base64 = "0.21.0" +bs58 = "0.4.0" [dev-dependencies] diff --git a/rust/src/encoding/base32.rs b/rust/src/encoding/base32.rs index 2d56b74c767..dc9fe7e4ccd 100644 --- a/rust/src/encoding/base32.rs +++ b/rust/src/encoding/base32.rs @@ -94,7 +94,7 @@ fn base32_decode(input: &str, alphabet: Option<&[u8]>, padding: bool) -> Result< } if output == vec![0] { - return Ok(vec![]) + return Ok(vec![]); } Ok(output) } @@ -106,15 +106,11 @@ pub extern "C" fn decode_base32(input: *const c_char, alphabet: *const c_char, p match base32_decode(input, alphabet, padding) { Ok(decoded) => { - let size = decoded.len(); - let mut decoded_vec = decoded.to_vec(); - let ptr = decoded_vec.as_mut_ptr(); - std::mem::forget(decoded_vec); - CByteArray { data: ptr, size } - }, + decoded.into() + } Err(_) => { CByteArray { data: std::ptr::null_mut(), size: 0 } - }, + } } } diff --git a/rust/src/encoding/base58.rs b/rust/src/encoding/base58.rs new file mode 100644 index 00000000000..d9c3da459bb --- /dev/null +++ b/rust/src/encoding/base58.rs @@ -0,0 +1,99 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +use std::ffi::{c_char, CStr, CString}; +use bs58::{encode, decode, Alphabet}; +use crate::memory::CByteArray; + +#[repr(C)] +#[derive(PartialEq, Debug)] +pub enum Base58Alphabet { + Bitcoin = 1, + Ripple = 2, +} + +impl From for &Alphabet { + fn from(value: Base58Alphabet) -> Self { + match value { + Base58Alphabet::Bitcoin => Alphabet::BITCOIN, + Base58Alphabet::Ripple => Alphabet::RIPPLE + } + } +} + +fn base58_encode(input: &[u8], alphabet: Base58Alphabet) -> String { + encode(input) + .with_alphabet(alphabet.into()) + .into_string() +} + +#[no_mangle] +pub extern "C" fn encode_base58(input: *const u8, input_len: usize, alphabet: Base58Alphabet) -> *mut c_char { + let input = unsafe { std::slice::from_raw_parts(input, input_len) }; + CString::new(base58_encode(input, alphabet)).unwrap().into_raw() +} + +fn base58_decode(input: &str, alphabet: Base58Alphabet) -> decode::Result> { + decode(input).with_alphabet(alphabet.into()).into_vec() +} + +#[no_mangle] +pub extern "C" fn decode_base58(input: *const c_char, alphabet: Base58Alphabet) -> CByteArray { + let input = unsafe { CStr::from_ptr(input).to_str().unwrap() }; + + match base58_decode(input, alphabet) { + Ok(decoded) => { + decoded.into() + }, + Err(_) => { + CByteArray { data: std::ptr::null_mut(), size: 0 } + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_base58_encode() { + let data = b"Hello, world!"; + let expected = "72k1xXWG59wUsYv7h2"; + + let result = base58_encode(data, Base58Alphabet::Bitcoin); + assert_eq!(result, expected); + } + + #[test] + fn test_base58_decode() { + let data = "72k1xXWG59wUsYv7h2"; + let expected = b"Hello, world!"; + + let result = base58_decode(data, Base58Alphabet::Bitcoin).unwrap(); + assert_eq!(result, expected.to_vec()); + } + + #[test] + fn test_base58_encode_ffi() { + let data = b"Hello, world!"; + let expected = "72k1xXWG59wUsYv7h2"; + + let result_ptr = encode_base58(data.as_ptr(), data.len(), Base58Alphabet::Bitcoin); + let result = unsafe { CString::from_raw(result_ptr) }; + assert_eq!(result.to_str().unwrap(), expected); + } + + #[test] + fn test_base58_decode_ffi() { + let data = "72k1xXWG59wUsYv7h2"; + let expected = b"Hello, world!"; + + let input = CString::new(data).unwrap(); + let decoded_ptr = decode_base58(input.as_ptr(), Base58Alphabet::Bitcoin); + let decoded_slice = unsafe { std::slice::from_raw_parts(decoded_ptr.data, decoded_ptr.size) }; + assert_eq!(decoded_slice, expected); + } +} diff --git a/rust/src/encoding/mod.rs b/rust/src/encoding/mod.rs index f0648e99e5a..9face5a38ec 100644 --- a/rust/src/encoding/mod.rs +++ b/rust/src/encoding/mod.rs @@ -5,5 +5,6 @@ // file LICENSE at the root of the source code distribution tree. mod base32; +mod base58; mod base64; mod hex; diff --git a/rust/src/memory/mod.rs b/rust/src/memory/mod.rs index a923e03a8c0..4376cf6ea14 100644 --- a/rust/src/memory/mod.rs +++ b/rust/src/memory/mod.rs @@ -12,6 +12,16 @@ pub struct CByteArray { pub size: usize, } +impl From> for CByteArray { + fn from(value: Vec) -> Self { + let size = value.len(); + let mut mut_vec = value.to_vec(); + let ptr = mut_vec.as_mut_ptr(); + std::mem::forget(mut_vec); + CByteArray { data: ptr, size } + } +} + #[no_mangle] pub unsafe extern fn free_string(ptr: *const c_char) { // Take the ownership back to rust and drop the owner diff --git a/src/Aeternity/Address.cpp b/src/Aeternity/Address.cpp index b3d0ecc64fb..b95f5bcede3 100644 --- a/src/Aeternity/Address.cpp +++ b/src/Aeternity/Address.cpp @@ -38,12 +38,12 @@ Address::Address(const std::string& string) { } auto payload = string.substr(Identifiers::prefixAccountPubkey.size(), string.size()); - bytes = Base58::bitcoin.decodeCheck(payload); + bytes = Base58::decodeCheck(payload); } /// Returns a string representation of the Aeternity address. std::string Address::string() const { - return Identifiers::prefixAccountPubkey + Base58::bitcoin.encodeCheck(bytes); + return Identifiers::prefixAccountPubkey + Base58::encodeCheck(bytes); } bool Address::checkType(const std::string& type) { @@ -51,7 +51,7 @@ bool Address::checkType(const std::string& type) { } bool Address::checkPayload(const std::string& payload) { - unsigned long base58 = Base58::bitcoin.decodeCheck(payload).size(); + unsigned long base58 = Base58::decodeCheck(payload).size(); return base58 == size; } diff --git a/src/Aeternity/Signer.cpp b/src/Aeternity/Signer.cpp index ff27db8d81a..a2f314bba4d 100644 --- a/src/Aeternity/Signer.cpp +++ b/src/Aeternity/Signer.cpp @@ -37,7 +37,7 @@ Proto::SigningOutput Signer::sign(const TW::PrivateKey& privateKey, Transaction& /// sign ed25519 auto sigRaw = privateKey.sign(msg, TWCurveED25519); - auto signature = Identifiers::prefixSignature + Base58::bitcoin.encodeCheck(sigRaw); + auto signature = Identifiers::prefixSignature + Base58::encodeCheck(sigRaw); /// encode the message using rlp auto rlpTxRaw = buildRlpTxRaw(txRlp, sigRaw); diff --git a/src/Aeternity/Transaction.cpp b/src/Aeternity/Transaction.cpp index 7ed0515b97b..32690b4cebf 100644 --- a/src/Aeternity/Transaction.cpp +++ b/src/Aeternity/Transaction.cpp @@ -34,7 +34,7 @@ TW::Data Transaction::buildTag(const std::string& address) { auto data = Data(); append(data, Identifiers::iDTagAccount); - append(data, Base58::bitcoin.decodeCheck(payload)); + append(data, Base58::decodeCheck(payload)); return data; } diff --git a/src/Base58.cpp b/src/Base58.cpp deleted file mode 100644 index 61ed8d4600b..00000000000 --- a/src/Base58.cpp +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright © 2014-2018 The Bitcoin Core developers -// Copyright © 2017-2020 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -#include "Base58.h" - -#include "Hash.h" - -#include -#include -#include -#include - -using namespace TW; - -// clang-format off - -static const std::array bitcoinDigits = { - '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', - 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' -}; - -static const std::array bitcoinCharacterMap = { - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1, - -1, 9,10,11,12,13,14,15,16,-1,17,18,19,20,21,-1, - 22,23,24,25,26,27,28,29,30,31,32,-1,-1,-1,-1,-1, - -1,33,34,35,36,37,38,39,40,41,42,43,-1,44,45,46, - 47,48,49,50,51,52,53,54,55,56,57,-1,-1,-1,-1,-1, -}; - -static const std::array rippleDigits = { - 'r', 'p', 's', 'h', 'n', 'a', 'f', '3', '9', 'w', 'B', 'U', 'D', 'N', 'E', - 'G', 'H', 'J', 'K', 'L', 'M', '4', 'P', 'Q', 'R', 'S', 'T', '7', 'V', 'W', - 'X', 'Y', 'Z', '2', 'b', 'c', 'd', 'e', 'C', 'g', '6', '5', 'j', 'k', 'm', - '8', 'o', 'F', 'q', 'i', '1', 't', 'u', 'v', 'A', 'x', 'y', 'z' -}; - -static const std::array rippleCharacterMap = { - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,50,33,7,21,41,40,27,45,8,-1,-1,-1,-1,-1,-1, - -1,54,10,38,12,14,47,15,16,-1,17,18,19,20,13,-1, - 22,23,24,25,26,11,28,29,30,31,32,-1,-1,-1,-1,-1, - -1,5,34,35,36,37,6,39,3,49,42,43,-1,44,4,46, - 1,48,0,2,51,52,53,9,55,56,57,-1,-1,-1,-1,-1, -}; - -// clang-format on - -Base58 Base58::bitcoin = Base58(bitcoinDigits, bitcoinCharacterMap); - -Base58 Base58::ripple = Base58(rippleDigits, rippleCharacterMap); - -Data Base58::decodeCheck(const char* begin, const char* end, Hash::Hasher hasher) const { - auto result = decode(begin, end); - if (result.size() < 4) { - return {}; - } - - // re-calculate the checksum, ensure it matches the included 4-byte checksum - auto hash = Hash::hash(hasher, result.data(), result.size() - 4); - if (!std::equal(hash.begin(), hash.begin() + 4, result.end() - 4)) { - return {}; - } - - return Data(result.begin(), result.end() - 4); -} - -Data Base58::decode(const char* begin, const char* end) const { - const auto* it = begin; - - // Skip leading spaces. - it = std::find_if_not(it, end, [](char c) { return std::isspace(c);}); - - // Skip and count leading zeros. - std::size_t zeroes = 0; - std::size_t length = 0; - while (it != end && *it == digits[0]) { - zeroes += 1; - it += 1; - } - - // Allocate enough space in big-endian base256 representation. - std::size_t base258Size = (end - it) * 733 / 1000 + 1; // log(58) / log(256), rounded up. - Data b256(base258Size); - - // Process the characters. - while (it != end && !std::isspace(*it)) { - if (static_cast(*it) >= 128) { - // Invalid b58 character - return {}; - } - - // Decode base58 character - int carry = characterMap[static_cast(*it)]; - if (carry == -1) { - // Invalid b58 character - return {}; - } - - std::size_t i = 0; - for (auto b256it = b256.rbegin(); (carry != 0 || i < length) && (b256it != b256.rend()); - ++b256it, ++i) { - carry += 58 * (*b256it); - *b256it = static_cast(carry % 256); - carry /= 256; - } - assert(carry == 0); - length = i; - it += 1; - } - - // Skip trailing spaces. - it = std::find_if_not(it, end, [](char c) { return std::isspace(c);}); - if (it != end) { - // Extra charaters at the end - return {}; - } - - // Skip leading zeroes in b256. - auto b256it = b256.begin() + (base258Size - length); - while (b256it != b256.end() && *b256it == 0) { - b256it++; - } - - // Copy result into output vector. - Data result; - result.reserve(zeroes + (b256.end() - b256it)); - result.assign(zeroes, 0x00); - std::copy(b256it, b256.end(), std::back_inserter(result)); - - return result; -} - -std::string Base58::encodeCheck(const byte* begin, const byte* end, Hash::Hasher hasher) const { - // add 4-byte hash check to the end - Data dataWithCheck(begin, end); - auto hash = Hash::hash(hasher, begin, end - begin); - dataWithCheck.insert(dataWithCheck.end(), hash.begin(), hash.begin() + 4); - return encode(dataWithCheck); -} - -std::string Base58::encode(const byte* begin, const byte* end) const { - // Skip & count leading zeroes. - int zeroes = 0; - int length = 0; - while (begin != end && *begin == 0) { - begin += 1; - zeroes += 1; - } - - // Allocate enough space in big-endian base58 representation. - auto base58Size = (end - begin) * 138 / 100 + 1; // log(256) / log(58), rounded up. - Data b58(base58Size); - - while (begin != end) { - int carry = *begin; - int i = 0; - // Apply "b58 = b58 * 256 + ch". - for (auto b58it = b58.rbegin(); (carry != 0 || i < length) && (b58it != b58.rend()); - b58it++, i++) { - carry += 256 * (*b58it); - *b58it = carry % 58; - carry /= 58; - } - - assert(carry == 0); - length = i; - begin += 1; - } - - // Skip leading zeroes in base58 result. - auto it = b58.begin() + (base58Size - length); - while (it != b58.end() && *it == 0) { - it++; - } - - // Translate the result into a string. - std::string str; - str.reserve(zeroes + (b58.end() - it)); - str.assign(zeroes, digits[0]); - while (it != b58.end()) { - str += digits[*it]; - it += 1; - } - return str; -} diff --git a/src/Base58.h b/src/Base58.h index d5e231d307d..6091b316646 100644 --- a/src/Base58.h +++ b/src/Base58.h @@ -8,64 +8,53 @@ #include "Data.h" #include "Hash.h" +#include "rust/bindgen/WalletCoreRSBindgen.h" -#include #include -namespace TW { - -class Base58 { - public: - /// Base58 coder with Bitcoin character map. - static Base58 bitcoin; - - /// Base58 coder with Ripple character map. - static Base58 ripple; - - public: - /// Ordered list of valid characters. - const std::array digits; - - /// Maps characters to base58 values. - const std::array characterMap; - - /// Initializes a Base58 class with custom digit mapping. - Base58(const std::array& digits, const std::array& characterMap) - : digits(digits), characterMap(characterMap) {} - - /// Decodes a base 58 string verifying the checksum, returns empty on failure. - Data decodeCheck(const std::string& string, Hash::Hasher hasher = Hash::HasherSha256d) const { - return decodeCheck(string.data(), string.data() + string.size(), hasher); +namespace TW::Base58 { + /// Decodes a base 58 string into `result`, returns `false` on failure. + static inline Data decode(const std::string& string, Base58Alphabet alphabet = Base58Alphabet::Bitcoin) { + if (string.empty()) { + return {}; + } + auto decoded = decode_base58(string.c_str(), alphabet); + if (decoded.data == nullptr || decoded.size == 0) { + return {}; + } + Data decoded_vec(&decoded.data[0], &decoded.data[decoded.size]); + std::free(decoded.data); + return decoded_vec; } - /// Decodes a base 58 string verifying the checksum, returns empty on failure. - Data decodeCheck(const char* begin, const char* end, Hash::Hasher hasher = Hash::HasherSha256d) const; + static inline Data decodeCheck(const std::string& string, Base58Alphabet alphabet = Base58Alphabet::Bitcoin, Hash::Hasher hasher = Hash::HasherSha256d) { + auto result = decode(string, alphabet); + if (result.size() < 4) { + return {}; + } - /// Decodes a base 58 string into `result`, returns `false` on failure. - Data decode(const std::string& string) const { - return decode(string.data(), string.data() + string.size()); - } + // re-calculate the checksum, ensure it matches the included 4-byte checksum + auto hash = Hash::hash(hasher, result.data(), result.size() - 4); + if (!std::equal(hash.begin(), hash.begin() + 4, result.end() - 4)) { + return {}; + } - /// Decodes a base 58 string into `result`, returns `false` on failure. - Data decode(const char* begin, const char* end) const; + return Data(result.begin(), result.end() - 4); + } - /// Encodes data as a base 58 string with a checksum. template - std::string encodeCheck(const T& data, Hash::Hasher hasher = Hash::HasherSha256d) const { - return encodeCheck(data.data(), data.data() + data.size(), hasher); + static inline std::string encode(const T& data, Base58Alphabet alphabet = Base58Alphabet::Bitcoin) { + auto encoded = encode_base58(data.data(), data.size(), alphabet); + std::string encoded_str(encoded); + free_string(encoded); + return encoded_str; } - /// Encodes data as a base 58 string with a checksum. - std::string encodeCheck(const byte* pbegin, const byte* pend, Hash::Hasher hasher = Hash::HasherSha256d) const; - - /// Encodes data as a base 58 string. template - std::string encode(const T& data) const { - return encode(data.data(), data.data() + data.size()); + static inline std::string encodeCheck(const T& data, Base58Alphabet alphabet = Base58Alphabet::Bitcoin, Hash::Hasher hasher = Hash::HasherSha256d) { + auto hash = Hash::hash(hasher, data); + Data toBeEncoded(std::begin(data), std::end(data)); + toBeEncoded.insert(toBeEncoded.end(), hash.begin(), hash.begin() + 4); + return encode(toBeEncoded, alphabet); } - - /// Encodes data as a base 58 string. - std::string encode(const byte* pbegin, const byte* pend) const; -}; - -} // namespace TW +} diff --git a/src/Base58Address.h b/src/Base58Address.h index ee66c495a93..6ec9f4e65ac 100644 --- a/src/Base58Address.h +++ b/src/Base58Address.h @@ -33,7 +33,7 @@ class Base58Address { /// Determines whether a string makes a valid address. static bool isValid(const std::string& string) { - const auto decoded = Base58::bitcoin.decodeCheck(string); + const auto decoded = Base58::decodeCheck(string); if (decoded.size() != Base58Address::size) { return false; } @@ -43,7 +43,7 @@ class Base58Address { /// Determines whether a string makes a valid address, and the prefix is /// within the valid set. static bool isValid(const std::string& string, const std::vector& validPrefixes) { - const auto decoded = Base58::bitcoin.decodeCheck(string); + const auto decoded = Base58::decodeCheck(string); if (decoded.size() != Base58Address::size) { return false; } @@ -59,7 +59,7 @@ class Base58Address { /// Initializes an address with a string representation. explicit Base58Address(const std::string& string) { - const auto decoded = Base58::bitcoin.decodeCheck(string); + const auto decoded = Base58::decodeCheck(string); if (decoded.size() != Base58Address::size) { throw std::invalid_argument("Invalid address string"); } @@ -86,7 +86,7 @@ class Base58Address { /// Returns a string representation of the address. std::string string() const { - return Base58::bitcoin.encodeCheck(bytes); + return Base58::encodeCheck(bytes); } }; diff --git a/src/Bitcoin/Script.cpp b/src/Bitcoin/Script.cpp index 08bbaa042f3..473493dfcae 100644 --- a/src/Bitcoin/Script.cpp +++ b/src/Bitcoin/Script.cpp @@ -342,7 +342,7 @@ Script Script::lockScriptForAddress(const std::string& string, enum TWCoinType c case TWCoinTypeDecred: if (Decred::Address::isValid(string)) { - auto bytes = Base58::bitcoin.decodeCheck(string, Hash::HasherBlake256d); + auto bytes = Base58::decodeCheck(string, Base58Alphabet::Bitcoin, Hash::HasherBlake256d); if (bytes[1] == TW::p2pkhPrefix(TWCoinTypeDecred)) { return buildPayToPublicKeyHash(Data(bytes.begin() + 2, bytes.end())); } diff --git a/src/Cardano/AddressV2.cpp b/src/Cardano/AddressV2.cpp index 6d2140ab82f..673f47d6c92 100644 --- a/src/Cardano/AddressV2.cpp +++ b/src/Cardano/AddressV2.cpp @@ -15,7 +15,7 @@ namespace TW::Cardano { bool AddressV2::parseAndCheck(const std::string& addr, Data& root_out, Data& attrs_out, byte& type_out) { // Decode Bas58, decode payload + crc, decode root, attr - Data base58decoded = Base58::bitcoin.decode(addr); + Data base58decoded = Base58::decode(addr); if (base58decoded.empty()) { throw std::invalid_argument("Invalid address: could not Base58 decode"); } @@ -100,7 +100,7 @@ Data AddressV2::getCborData() const { std::string AddressV2::string() const { // Base58 encode the CBOR data - return Base58::bitcoin.encode(getCborData()); + return Base58::encode(getCborData()); } Data AddressV2::keyHash(const TW::Data& xpub) { diff --git a/src/Decred/Address.cpp b/src/Decred/Address.cpp index cd3685f9463..81c537a24a7 100644 --- a/src/Decred/Address.cpp +++ b/src/Decred/Address.cpp @@ -17,7 +17,7 @@ static const auto keyhashSize = Hash::ripemdSize; static const auto addressDataSize = keyhashSize + 2; bool Address::isValid(const std::string& string) noexcept { - const auto data = Base58::bitcoin.decodeCheck(string, Hash::HasherBlake256d); + const auto data = Base58::decodeCheck(string, Base58Alphabet::Bitcoin, Hash::HasherBlake256d); if (data.size() != addressDataSize) { return false; } @@ -30,7 +30,7 @@ bool Address::isValid(const std::string& string) noexcept { } Address::Address(const std::string& string) { - const auto data = Base58::bitcoin.decodeCheck(string, Hash::HasherBlake256d); + const auto data = Base58::decodeCheck(string, Base58Alphabet::Bitcoin, Hash::HasherBlake256d); if (data.size() != addressDataSize) { throw std::invalid_argument("Invalid address string"); } @@ -49,7 +49,7 @@ Address::Address(const PublicKey& publicKey) { } std::string Address::string() const { - return Base58::bitcoin.encodeCheck(bytes, Hash::HasherBlake256d); + return Base58::encodeCheck(bytes, Base58Alphabet::Bitcoin, Hash::HasherBlake256d); } } // namespace TW::Decred diff --git a/src/EOS/Address.cpp b/src/EOS/Address.cpp index db97a6d7853..3c5146aa663 100644 --- a/src/EOS/Address.cpp +++ b/src/EOS/Address.cpp @@ -89,7 +89,7 @@ bool Address::extractKeyData(const std::string& string, Address* address) { return false; } - const Data& decodedBytes = Base58::bitcoin.decode(string.substr(prefixSize)); + const Data& decodedBytes = Base58::decode(string.substr(prefixSize)); if (decodedBytes.size() != KeyDataSize) { return false; } @@ -139,7 +139,7 @@ Address::Address(const PublicKey& publicKey, Type type) /// Returns a string representation of the EOS address. std::string Address::string() const { - return prefix() + Base58::bitcoin.encode(keyData); + return prefix() + Base58::encode(keyData); } } // namespace TW::EOS diff --git a/src/EOS/Transaction.cpp b/src/EOS/Transaction.cpp index 72c2791b460..3185fc8bb05 100644 --- a/src/EOS/Transaction.cpp +++ b/src/EOS/Transaction.cpp @@ -57,7 +57,7 @@ std::string Signature::string() const noexcept { buffer.push_back(hash[i]); } - return prefix + TW::Base58::bitcoin.encode(buffer); + return prefix + TW::Base58::encode(buffer); } void Extension::serialize(Data& os) const noexcept { diff --git a/src/FIO/Address.cpp b/src/FIO/Address.cpp index 52d1086e48f..0c983d6c636 100644 --- a/src/FIO/Address.cpp +++ b/src/FIO/Address.cpp @@ -57,7 +57,7 @@ std::optional Address::decodeKeyData(const std::string& string) { return {}; } - const Data& decodedBytes = Base58::bitcoin.decode(string.substr(prefixSize)); + const Data& decodedBytes = Base58::decode(string.substr(prefixSize)); if (decodedBytes.size() != size) { return {}; } @@ -94,7 +94,7 @@ Address::Address(const PublicKey& publicKey) { /// Returns a string representation of the FIO address. std::string Address::string() const { - return prefix() + Base58::bitcoin.encode(bytes); + return prefix() + Base58::encode(bytes); } PublicKey Address::publicKey() const { diff --git a/src/FIO/Signer.cpp b/src/FIO/Signer.cpp index e4390dd3b44..b7d83313b12 100644 --- a/src/FIO/Signer.cpp +++ b/src/FIO/Signer.cpp @@ -47,7 +47,7 @@ std::string Signer::signatureToBase58(const Data& sig) { Data hash = Hash::ripemd(sigWithSuffix); Data sigWithChecksum(sig); append(sigWithChecksum, TW::data(hash.data(), 4)); - string s = SignaturePrefix + Base58::bitcoin.encode(sigWithChecksum); + string s = SignaturePrefix + Base58::encode(sigWithChecksum); return s; } diff --git a/src/Groestlcoin/Address.cpp b/src/Groestlcoin/Address.cpp index 290b097ad69..17339507aff 100644 --- a/src/Groestlcoin/Address.cpp +++ b/src/Groestlcoin/Address.cpp @@ -12,7 +12,7 @@ namespace TW::Groestlcoin { bool Address::isValid(const std::string& string) { - const auto decoded = Base58::bitcoin.decodeCheck(string, Hash::HasherGroestl512d); + const auto decoded = Base58::decodeCheck(string, Base58Alphabet::Bitcoin, Hash::HasherGroestl512d); if (decoded.size() != Address::size) { return false; } @@ -21,7 +21,7 @@ bool Address::isValid(const std::string& string) { } bool Address::isValid(const std::string& string, const std::vector& validPrefixes) { - const auto decoded = Base58::bitcoin.decodeCheck(string, Hash::HasherGroestl512d); + const auto decoded = Base58::decodeCheck(string, Base58Alphabet::Bitcoin, Hash::HasherGroestl512d); if (decoded.size() != Address::size) { return false; } @@ -32,7 +32,7 @@ bool Address::isValid(const std::string& string, const std::vector& validP } Address::Address(const std::string& string) { - const auto decoded = Base58::bitcoin.decodeCheck(string, Hash::HasherGroestl512d); + const auto decoded = Base58::decodeCheck(string, Base58Alphabet::Bitcoin, Hash::HasherGroestl512d); if (decoded.size() != Address::size) { throw std::invalid_argument("Invalid address string"); } @@ -56,7 +56,7 @@ Address::Address(const PublicKey& publicKey, uint8_t prefix) { } std::string Address::string() const { - return Base58::bitcoin.encodeCheck(bytes, Hash::HasherGroestl512d); + return Base58::encodeCheck(bytes, Base58Alphabet::Bitcoin, Hash::HasherGroestl512d); } } // namespace TW::Groestlcoin diff --git a/src/HDWallet.cpp b/src/HDWallet.cpp index 682bfcddc62..afbe4aedeee 100644 --- a/src/HDWallet.cpp +++ b/src/HDWallet.cpp @@ -348,7 +348,7 @@ std::string serialize(const HDNode* node, uint32_t fingerprint, uint32_t version node_data.insert(node_data.end(), node->private_key, node->private_key + 32); } - return Base58::bitcoin.encodeCheck(node_data, hasher); + return Base58::encodeCheck(node_data, Base58Alphabet::Bitcoin, hasher); } bool deserialize(const std::string& extended, TWCurve curve, Hash::Hasher hasher, HDNode* node) { @@ -360,7 +360,7 @@ bool deserialize(const std::string& extended, TWCurve curve, Hash::Hasher hasher node->curve = get_curve_by_name(curveNameStr); assert(node->curve != nullptr); - const auto node_data = Base58::bitcoin.decodeCheck(extended, hasher); + const auto node_data = Base58::decodeCheck(extended, Base58Alphabet::Bitcoin, hasher); if (node_data.size() != 78) { return false; } diff --git a/src/NEAR/Address.cpp b/src/NEAR/Address.cpp index 1d669e3d449..f9f7a92ecf1 100644 --- a/src/NEAR/Address.cpp +++ b/src/NEAR/Address.cpp @@ -30,7 +30,7 @@ std::optional Address::decodeLegacyAddress(const std::string& string) { return {}; } - const Data& decoded = Base58::bitcoin.decode(string.substr(prefix.size())); + const Data& decoded = Base58::decode(string.substr(prefix.size())); return Data(decoded.begin(), decoded.end() - 4); } diff --git a/src/NEO/Address.cpp b/src/NEO/Address.cpp index 64c4c28a808..bb77c138e8a 100644 --- a/src/NEO/Address.cpp +++ b/src/NEO/Address.cpp @@ -17,7 +17,7 @@ using namespace TW; namespace TW::NEO { bool Address::isValid(const std::string& string) { - const auto decoded = Base58::bitcoin.decodeCheck(string); + const auto decoded = Base58::decodeCheck(string); return !(decoded.size() != Address::size || decoded[0] != version); } diff --git a/src/NULS/Address.cpp b/src/NULS/Address.cpp index be8a488e320..c70065d78bf 100644 --- a/src/NULS/Address.cpp +++ b/src/NULS/Address.cpp @@ -27,7 +27,7 @@ bool Address::isValid(const std::string& string) { } std::string address = string.substr(prefix.length(), string.length() - prefix.length()); - Data decoded = Base58::bitcoin.decode(address); + Data decoded = Base58::decode(address); if (decoded.size() != size) { return false; } @@ -56,7 +56,7 @@ Address::Address(const std::string& string) { throw std::invalid_argument("Invalid address string"); } std::string address = string.substr(prefix.length(), string.length() - prefix.length()); - const auto decoded = Base58::bitcoin.decode(address); + const auto decoded = Base58::decode(address); std::copy(decoded.begin(), decoded.end(), bytes.begin()); } @@ -69,7 +69,7 @@ uint8_t Address::type() const { } std::string Address::string() const { - return prefix + Base58::bitcoin.encode(bytes.begin(), bytes.end()); + return prefix + Base58::encode(bytes); } uint8_t Address::checksum(std::array& byteArray) const { diff --git a/src/Nebulas/Address.cpp b/src/Nebulas/Address.cpp index 4b113b6cd8c..6b0cfd8e9f6 100644 --- a/src/Nebulas/Address.cpp +++ b/src/Nebulas/Address.cpp @@ -12,7 +12,7 @@ namespace TW::Nebulas { bool Address::isValid(const std::string& string) { - auto data = Base58::bitcoin.decode(string); + auto data = Base58::decode(string); if (data.size() != (size_t)Address::size) { return false; } @@ -35,7 +35,7 @@ Address::Address(const std::string& string) { throw std::invalid_argument("Invalid address string"); } - auto data = Base58::bitcoin.decode(string); + auto data = Base58::decode(string); std::copy(data.begin(), data.end(), bytes.begin()); } @@ -60,7 +60,7 @@ Address::Address(const PublicKey& publicKey) { } std::string Address::string() const { - return Base58::bitcoin.encode(bytes); + return Base58::encode(bytes); } } // namespace TW::Nebulas diff --git a/src/Polkadot/SS58Address.cpp b/src/Polkadot/SS58Address.cpp index 2c99b764ba9..f87b6395045 100644 --- a/src/Polkadot/SS58Address.cpp +++ b/src/Polkadot/SS58Address.cpp @@ -10,7 +10,7 @@ using namespace TW; using namespace std; bool SS58Address::isValid(const std::string& string, uint32_t network) { - const auto decoded = Base58::bitcoin.decode(string); + const auto decoded = Base58::decode(string); byte decodedNetworkSize = 0; uint32_t decodedNetwork = 0; if (!decodeNetwork(decoded, decodedNetworkSize, decodedNetwork)) { @@ -47,7 +47,7 @@ SS58Address::SS58Address(const std::string& string, uint32_t network) { if (!isValid(string, network)) { throw std::invalid_argument("Invalid address string"); } - const auto decoded = Base58::bitcoin.decode(string); + const auto decoded = Base58::decode(string); bytes.resize(decoded.size() - checksumSize); std::copy(decoded.begin(), decoded.end() - checksumSize, bytes.begin()); } @@ -68,7 +68,7 @@ std::string SS58Address::string() const { auto result = Data(bytes.begin(), bytes.end()); auto checksum = computeChecksum(bytes); append(result, checksum); - return Base58::bitcoin.encode(result); + return Base58::encode(result); } /// Returns public key bytes diff --git a/src/Solana/Address.cpp b/src/Solana/Address.cpp index 3e4f77cface..b1df361aaab 100644 --- a/src/Solana/Address.cpp +++ b/src/Solana/Address.cpp @@ -20,12 +20,12 @@ using namespace TW; namespace TW::Solana { bool Address::isValid(const std::string& string) { - const auto data = Base58::bitcoin.decode(string); + const auto data = Base58::decode(string); return Address::isValid(data); } Address::Address(const std::string& string) { - const auto data = Base58::bitcoin.decode(string); + const auto data = Base58::decode(string); if (!isValid(data)) { throw std::invalid_argument("Invalid address string"); } @@ -48,7 +48,7 @@ Address::Address(const Data& publicKeyData) { } std::string Address::string() const { - return Base58::bitcoin.encode(bytes); + return Base58::encode(bytes); } Data Address::vector() const { diff --git a/src/Solana/LegacyMessage.h b/src/Solana/LegacyMessage.h index f6dca77a5ef..6694e23607d 100644 --- a/src/Solana/LegacyMessage.h +++ b/src/Solana/LegacyMessage.h @@ -35,7 +35,7 @@ class LegacyMessage { std::vector compiledInstructions; LegacyMessage() - : mRecentBlockHash(Base58::bitcoin.decode(NULL_ID_ADDRESS)){}; + : mRecentBlockHash(Base58::decode(NULL_ID_ADDRESS)){}; LegacyMessage(Data recentBlockHash, const std::vector& instructions) : mRecentBlockHash(recentBlockHash) diff --git a/src/Solana/Program.cpp b/src/Solana/Program.cpp index d5023c3a66a..f9f196bb209 100644 --- a/src/Solana/Program.cpp +++ b/src/Solana/Program.cpp @@ -27,7 +27,7 @@ Address StakeProgram::addressFromValidatorSeed(const Address& fromAddress, const Address StakeProgram::addressFromRecentBlockhash(const Address& fromAddress, const Data& recentBlockhash, const Address& programId) { Data extended = fromAddress.vector(); - std::string seed = Base58::bitcoin.encode(recentBlockhash); + std::string seed = Base58::encode(recentBlockhash); Data vecSeed(seed.begin(), seed.end()); vecSeed.resize(32); Data additional = programId.vector(); diff --git a/src/Solana/Signature.h b/src/Solana/Signature.h index 8cb169b6e6a..3a1983cbaa9 100644 --- a/src/Solana/Signature.h +++ b/src/Solana/Signature.h @@ -19,7 +19,7 @@ class Signature { std::array bytes; Signature(const std::string& string) { - const auto data = Base58::bitcoin.decode(string); + const auto data = Base58::decode(string); std::copy(data.begin(), data.end(), this->bytes.begin()); } Signature(const std::array& bytes) { this->bytes = bytes; } diff --git a/src/Solana/Signer.cpp b/src/Solana/Signer.cpp index e427bd76401..bab36a4cd76 100644 --- a/src/Solana/Signer.cpp +++ b/src/Solana/Signer.cpp @@ -38,7 +38,7 @@ std::vector
convertReferences(const google::protobuf::RepeatedPtrField< } Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { - auto blockhash = Base58::bitcoin.decode(input.recent_blockhash()); + auto blockhash = Base58::decode(input.recent_blockhash()); auto key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); LegacyMessage message; std::vector signerKeys; @@ -179,7 +179,7 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { auto encoded = transaction.serialize(); protoOutput.set_encoded(encoded); - auto unsignedTx = Base58::bitcoin.encode(transaction.messageData()); + auto unsignedTx = Base58::encode(transaction.messageData()); protoOutput.set_unsigned_tx(unsignedTx.data(), unsignedTx.size()); return protoOutput; diff --git a/src/Solana/Transaction.cpp b/src/Solana/Transaction.cpp index 172779dee30..313f8cc60ac 100644 --- a/src/Solana/Transaction.cpp +++ b/src/Solana/Transaction.cpp @@ -24,7 +24,7 @@ std::string Transaction::serialize() const { } append(buffer, this->messageData()); - return Base58::bitcoin.encode(buffer); + return Base58::encode(buffer); } Data Transaction::messageData() const { diff --git a/src/Solana/VersionedTransaction.cpp b/src/Solana/VersionedTransaction.cpp index 548617f09be..439add21b80 100644 --- a/src/Solana/VersionedTransaction.cpp +++ b/src/Solana/VersionedTransaction.cpp @@ -19,7 +19,7 @@ std::string VersionedTransaction::serialize() const { } append(buffer, this->messageData()); - return Base58::bitcoin.encode(buffer); + return Base58::encode(buffer); } Data VersionedTransaction::messageData() const { diff --git a/src/Tezos/Address.cpp b/src/Tezos/Address.cpp index e351ce4d776..a495096b61a 100644 --- a/src/Tezos/Address.cpp +++ b/src/Tezos/Address.cpp @@ -23,7 +23,7 @@ const std::array tz2Prefix{6, 161, 161}; const std::array tz3Prefix{6, 161, 164}; bool Address::isValid(const std::string& string) { - const auto decoded = Base58::bitcoin.decodeCheck(string); + const auto decoded = Base58::decodeCheck(string); if (decoded.size() != Address::size) { return false; } @@ -50,7 +50,7 @@ Address::Address(const PublicKey& publicKey) { std::string Address::deriveOriginatedAddress(const std::string& operationHash, int operationIndex) { // Decode and remove 2 byte prefix. - auto decoded = Base58::bitcoin.decodeCheck(operationHash); + auto decoded = Base58::decodeCheck(operationHash); decoded.erase(decoded.begin(), decoded.begin() + 2); TW::encode32BE(operationIndex, decoded); @@ -59,7 +59,7 @@ std::string Address::deriveOriginatedAddress(const std::string& operationHash, i auto prefix = Data({2, 90, 121}); prefix.insert(prefix.end(), hash.begin(), hash.end()); - return Base58::bitcoin.encodeCheck(prefix); + return Base58::encodeCheck(prefix); } Data Address::forge() const { diff --git a/src/Tezos/BinaryCoding.cpp b/src/Tezos/BinaryCoding.cpp index 363ab9ef76b..1b8dd1c481d 100644 --- a/src/Tezos/BinaryCoding.cpp +++ b/src/Tezos/BinaryCoding.cpp @@ -16,7 +16,7 @@ namespace TW::Tezos { std::string base58ToHex(const std::string& string, size_t prefixLength) { - const auto decoded = Base58::bitcoin.decodeCheck(string); + const auto decoded = Base58::decodeCheck(string); if (decoded.size() < prefixLength) { return ""; } @@ -25,7 +25,7 @@ std::string base58ToHex(const std::string& string, size_t prefixLength) { } PublicKey parsePublicKey(const std::string& publicKey) { - const auto decoded = Base58::bitcoin.decodeCheck(publicKey); + const auto decoded = Base58::decodeCheck(publicKey); std::array prefix = {13, 15, 37, 217}; auto pk = Data(); @@ -39,7 +39,7 @@ PublicKey parsePublicKey(const std::string& publicKey) { } PrivateKey parsePrivateKey(const std::string& privateKey) { - const auto decoded = Base58::bitcoin.decodeCheck(privateKey); + const auto decoded = Base58::decodeCheck(privateKey); auto pk = Data(); auto prefix_size = 4ul; diff --git a/src/Tezos/Forging.cpp b/src/Tezos/Forging.cpp index 83088b3f3c0..27bc81f4816 100644 --- a/src/Tezos/Forging.cpp +++ b/src/Tezos/Forging.cpp @@ -18,7 +18,7 @@ namespace { constexpr const char* gTezosContractAddressPrefix{"KT1"}; void encodePrefix(const std::string& address, Data& forged) { - const auto decoded = Base58::bitcoin.decodeCheck(address); + const auto decoded = Base58::decodeCheck(address); constexpr auto prefixSize{3}; forged.insert(forged.end(), decoded.begin() + prefixSize, decoded.end()); } @@ -114,7 +114,7 @@ Data forgePublicKey(PublicKey publicKey) { auto bytes = Data(publicKey.bytes.begin(), publicKey.bytes.end()); append(data, bytes); - auto pk = Base58::bitcoin.encodeCheck(data); + auto pk = Base58::encodeCheck(data); auto decoded = "00" + base58ToHex(pk, 4); return parse_hex(decoded); } diff --git a/src/Tezos/OperationList.cpp b/src/Tezos/OperationList.cpp index fc2e7ed3897..e72c5bf1e53 100644 --- a/src/Tezos/OperationList.cpp +++ b/src/Tezos/OperationList.cpp @@ -21,7 +21,7 @@ void Tezos::OperationList::addOperation(const Operation& operation) { // Forge the given branch to a hex encoded string. Data Tezos::OperationList::forgeBranch() const { std::array prefix = {1, 52}; - const auto decoded = Base58::bitcoin.decodeCheck(branch); + const auto decoded = Base58::decodeCheck(branch); if (decoded.size() != 34 || !std::equal(prefix.begin(), prefix.end(), decoded.begin())) { throw std::invalid_argument("Invalid branch for forge"); } @@ -49,4 +49,4 @@ Data Tezos::OperationList::forge(const PrivateKey& privateKey) const { return forged; } -} // namespace TW::Tezos \ No newline at end of file +} // namespace TW::Tezos diff --git a/src/Tron/Address.cpp b/src/Tron/Address.cpp index a67ea8fd1c2..b24b4806d23 100644 --- a/src/Tron/Address.cpp +++ b/src/Tron/Address.cpp @@ -15,7 +15,7 @@ namespace TW::Tron { bool Address::isValid(const std::string& string) { - const auto decoded = Base58::bitcoin.decodeCheck(string); + const auto decoded = Base58::decodeCheck(string); if (decoded.size() != Address::size) { return false; } diff --git a/src/Tron/Signer.cpp b/src/Tron/Signer.cpp index 87ed70b30f5..b3278891aea 100644 --- a/src/Tron/Signer.cpp +++ b/src/Tron/Signer.cpp @@ -24,10 +24,10 @@ const std::string TRANSFER_TOKEN_FUNCTION = "0xa9059cbb"; protocol::TransferContract to_internal(const Proto::TransferContract& transfer) { auto internal = protocol::TransferContract(); - const auto ownerAddress = Base58::bitcoin.decodeCheck(transfer.owner_address()); + const auto ownerAddress = Base58::decodeCheck(transfer.owner_address()); internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); - const auto toAddress = Base58::bitcoin.decodeCheck(transfer.to_address()); + const auto toAddress = Base58::decodeCheck(transfer.to_address()); internal.set_to_address(toAddress.data(), toAddress.size()); internal.set_amount(transfer.amount()); @@ -42,10 +42,10 @@ protocol::TransferAssetContract to_internal(const Proto::TransferAssetContract& internal.set_asset_name(transfer.asset_name()); - const auto ownerAddress = Base58::bitcoin.decodeCheck(transfer.owner_address()); + const auto ownerAddress = Base58::decodeCheck(transfer.owner_address()); internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); - const auto toAddress = Base58::bitcoin.decodeCheck(transfer.to_address()); + const auto toAddress = Base58::decodeCheck(transfer.to_address()); internal.set_to_address(toAddress.data(), toAddress.size()); internal.set_amount(transfer.amount()); @@ -56,8 +56,8 @@ protocol::TransferAssetContract to_internal(const Proto::TransferAssetContract& protocol::FreezeBalanceContract to_internal(const Proto::FreezeBalanceContract& freezeContract) { auto internal = protocol::FreezeBalanceContract(); auto resource = protocol::ResourceCode(); - const auto ownerAddress = Base58::bitcoin.decodeCheck(freezeContract.owner_address()); - const auto receiverAddress = Base58::bitcoin.decodeCheck(freezeContract.receiver_address()); + const auto ownerAddress = Base58::decodeCheck(freezeContract.owner_address()); + const auto receiverAddress = Base58::decodeCheck(freezeContract.receiver_address()); protocol::ResourceCode_Parse(freezeContract.resource(), &resource); @@ -73,8 +73,8 @@ protocol::FreezeBalanceContract to_internal(const Proto::FreezeBalanceContract& protocol::UnfreezeBalanceContract to_internal(const Proto::UnfreezeBalanceContract& unfreezeContract) { auto internal = protocol::UnfreezeBalanceContract(); auto resource = protocol::ResourceCode(); - const auto ownerAddress = Base58::bitcoin.decodeCheck(unfreezeContract.owner_address()); - const auto receiverAddress = Base58::bitcoin.decodeCheck(unfreezeContract.receiver_address()); + const auto ownerAddress = Base58::decodeCheck(unfreezeContract.owner_address()); + const auto receiverAddress = Base58::decodeCheck(unfreezeContract.receiver_address()); protocol::ResourceCode_Parse(unfreezeContract.resource(), &resource); @@ -87,7 +87,7 @@ protocol::UnfreezeBalanceContract to_internal(const Proto::UnfreezeBalanceContra protocol::UnfreezeAssetContract to_internal(const Proto::UnfreezeAssetContract& unfreezeContract) { auto internal = protocol::UnfreezeAssetContract(); - const auto ownerAddress = Base58::bitcoin.decodeCheck(unfreezeContract.owner_address()); + const auto ownerAddress = Base58::decodeCheck(unfreezeContract.owner_address()); internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); @@ -96,13 +96,13 @@ protocol::UnfreezeAssetContract to_internal(const Proto::UnfreezeAssetContract& protocol::VoteAssetContract to_internal(const Proto::VoteAssetContract& voteContract) { auto internal = protocol::VoteAssetContract(); - const auto ownerAddress = Base58::bitcoin.decodeCheck(voteContract.owner_address()); + const auto ownerAddress = Base58::decodeCheck(voteContract.owner_address()); internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); internal.set_support(voteContract.support()); internal.set_count(voteContract.count()); for (int i = 0; i < voteContract.vote_address_size(); i++) { - auto voteAddress = Base58::bitcoin.decodeCheck(voteContract.vote_address(i)); + auto voteAddress = Base58::decodeCheck(voteContract.vote_address(i)); internal.add_vote_address(voteAddress.data(), voteAddress.size()); } @@ -111,12 +111,12 @@ protocol::VoteAssetContract to_internal(const Proto::VoteAssetContract& voteCont protocol::VoteWitnessContract to_internal(const Proto::VoteWitnessContract& voteContract) { auto internal = protocol::VoteWitnessContract(); - const auto ownerAddress = Base58::bitcoin.decodeCheck(voteContract.owner_address()); + const auto ownerAddress = Base58::decodeCheck(voteContract.owner_address()); internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); internal.set_support(voteContract.support()); for (int i = 0; i < voteContract.votes_size(); i++) { - auto voteAddress = Base58::bitcoin.decodeCheck(voteContract.votes(i).vote_address()); + auto voteAddress = Base58::decodeCheck(voteContract.votes(i).vote_address()); auto* vote = internal.add_votes(); vote->set_vote_address(voteAddress.data(), voteAddress.size()); @@ -128,7 +128,7 @@ protocol::VoteWitnessContract to_internal(const Proto::VoteWitnessContract& vote protocol::WithdrawBalanceContract to_internal(const Proto::WithdrawBalanceContract& withdrawContract) { auto internal = protocol::WithdrawBalanceContract(); - const auto ownerAddress = Base58::bitcoin.decodeCheck(withdrawContract.owner_address()); + const auto ownerAddress = Base58::decodeCheck(withdrawContract.owner_address()); internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); @@ -137,8 +137,8 @@ protocol::WithdrawBalanceContract to_internal(const Proto::WithdrawBalanceContra protocol::TriggerSmartContract to_internal(const Proto::TriggerSmartContract& triggerSmartContract) { auto internal = protocol::TriggerSmartContract(); - const auto ownerAddress = Base58::bitcoin.decodeCheck(triggerSmartContract.owner_address()); - const auto contractAddress = Base58::bitcoin.decodeCheck(triggerSmartContract.contract_address()); + const auto ownerAddress = Base58::decodeCheck(triggerSmartContract.owner_address()); + const auto contractAddress = Base58::decodeCheck(triggerSmartContract.contract_address()); internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); internal.set_contract_address(contractAddress.data(), contractAddress.size()); @@ -151,7 +151,7 @@ protocol::TriggerSmartContract to_internal(const Proto::TriggerSmartContract& tr } protocol::TriggerSmartContract to_internal(const Proto::TransferTRC20Contract& transferTrc20Contract) { - auto toAddress = Base58::bitcoin.decodeCheck(transferTrc20Contract.to_address()); + auto toAddress = Base58::decodeCheck(transferTrc20Contract.to_address()); // amount is 256 bits, big endian Data amount = data(transferTrc20Contract.amount()); diff --git a/src/Waves/Address.cpp b/src/Waves/Address.cpp index 2f5ad758be7..6103765c48b 100644 --- a/src/Waves/Address.cpp +++ b/src/Waves/Address.cpp @@ -43,12 +43,12 @@ bool Address::isValid(const Data& decoded) { } bool Address::isValid(const std::string& string) { - const auto decoded = Base58::bitcoin.decode(string); + const auto decoded = Base58::decode(string); return isValid(decoded); } Address::Address(const std::string& string) { - const auto decoded = Base58::bitcoin.decode(string); + const auto decoded = Base58::decode(string); if (!isValid(string)) { throw std::invalid_argument("Invalid address key data"); } @@ -79,7 +79,7 @@ Address::Address(const PublicKey &publicKey) { } std::string Address::string() const { - return Base58::bitcoin.encode(bytes); + return Base58::encode(bytes); } } // namespace TW::Waves diff --git a/src/Waves/Transaction.cpp b/src/Waves/Transaction.cpp index 36ac5cb3447..bb6e7885c0d 100644 --- a/src/Waves/Transaction.cpp +++ b/src/Waves/Transaction.cpp @@ -34,13 +34,13 @@ Data serializeTransfer(int64_t amount, std::string asset, int64_t fee, std::stri data.push_back(static_cast(0)); } else { data.push_back(static_cast(1)); - append(data, Base58::bitcoin.decode(asset)); + append(data, Base58::decode(asset)); } if (fee_asset == Transaction::WAVES) { data.push_back(static_cast(0)); } else { data.push_back(static_cast(1)); - append(data, Base58::bitcoin.decode(fee_asset)); + append(data, Base58::decode(fee_asset)); } encode64BE(timestamp, data); encode64BE(amount, data); @@ -86,9 +86,9 @@ json jsonTransfer(const Data& signature, int64_t amount, const std::string& asse jsonTx["type"] = TransactionType::transfer; jsonTx["version"] = TransactionVersion::V2; jsonTx["fee"] = fee; - jsonTx["senderPublicKey"] = Base58::bitcoin.encode(pub_key); + jsonTx["senderPublicKey"] = Base58::encode(pub_key); jsonTx["timestamp"] = timestamp; - jsonTx["proofs"] = json::array({Base58::bitcoin.encode(signature)}); + jsonTx["proofs"] = json::array({Base58::encode(signature)}); jsonTx["recipient"] = Address(to).string(); if (asset != Transaction::WAVES) { jsonTx["assetId"] = asset; @@ -97,7 +97,7 @@ json jsonTransfer(const Data& signature, int64_t amount, const std::string& asse jsonTx["feeAssetId"] = fee_asset; } jsonTx["amount"] = amount; - jsonTx["attachment"] = Base58::bitcoin.encode(attachment); + jsonTx["attachment"] = Base58::encode(attachment); return jsonTx; } @@ -108,9 +108,9 @@ json jsonLease(const Data& signature, int64_t amount, int64_t fee, Address to, i jsonTx["type"] = TransactionType::lease; jsonTx["version"] = TransactionVersion::V2; jsonTx["fee"] = fee; - jsonTx["senderPublicKey"] = Base58::bitcoin.encode(pub_key); + jsonTx["senderPublicKey"] = Base58::encode(pub_key); jsonTx["timestamp"] = timestamp; - jsonTx["proofs"] = json::array({Base58::bitcoin.encode(signature)}); + jsonTx["proofs"] = json::array({Base58::encode(signature)}); jsonTx["recipient"] = Address(to).string(); jsonTx["amount"] = amount; @@ -123,11 +123,11 @@ json jsonCancelLease(const Data& signature, const Data& leaseId, int64_t fee, in jsonTx["type"] = TransactionType::cancelLease; jsonTx["version"] = TransactionVersion::V2; jsonTx["fee"] = fee; - jsonTx["senderPublicKey"] = Base58::bitcoin.encode(pub_key); - jsonTx["leaseId"] = Base58::bitcoin.encode(leaseId); + jsonTx["senderPublicKey"] = Base58::encode(pub_key); + jsonTx["leaseId"] = Base58::encode(leaseId); jsonTx["chainId"] = 87; // mainnet jsonTx["timestamp"] = timestamp; - jsonTx["proofs"] = json::array({Base58::bitcoin.encode(signature)}); + jsonTx["proofs"] = json::array({Base58::encode(signature)}); return jsonTx; } @@ -152,7 +152,7 @@ Data Transaction::serializeToSign() const { return serializeLease(message.amount(), message.fee(), Address(message.to()), input.timestamp(), pub_key); } else if (input.has_cancel_lease_message()) { auto message = input.cancel_lease_message(); - auto leaseId = Base58::bitcoin.decode(message.lease_id()); + auto leaseId = Base58::decode(message.lease_id()); return serializeCancelLease(leaseId, message.fee(), input.timestamp(), pub_key); } @@ -184,7 +184,7 @@ json Transaction::buildJson(const Data& signature) const { pub_key); } else if (input.has_cancel_lease_message()) { auto message = input.cancel_lease_message(); - auto leaseId = Base58::bitcoin.decode(message.lease_id()); + auto leaseId = Base58::decode(message.lease_id()); return jsonCancelLease( signature, leaseId, diff --git a/src/XRP/Address.cpp b/src/XRP/Address.cpp index 2ff0026deba..f675c5afbcd 100644 --- a/src/XRP/Address.cpp +++ b/src/XRP/Address.cpp @@ -11,7 +11,7 @@ namespace TW::Ripple { bool Address::isValid(const std::string& string) { - const auto decoded = Base58::ripple.decodeCheck(string); + const auto decoded = Base58::decodeCheck(string, Base58Alphabet::Ripple); if (decoded.size() != Address::size) { return false; } @@ -19,7 +19,7 @@ bool Address::isValid(const std::string& string) { } Address::Address(const std::string& string) { - const auto decoded = Base58::ripple.decodeCheck(string); + const auto decoded = Base58::decodeCheck(string, Base58Alphabet::Ripple); if (decoded.size() != Address::size) { throw std::invalid_argument("Invalid address string"); } @@ -33,7 +33,7 @@ Address::Address(const PublicKey& publicKey) { } std::string Address::string() const { - return Base58::ripple.encodeCheck(bytes); + return Base58::encodeCheck(bytes, Base58Alphabet::Ripple); } } // namespace TW::Ripple diff --git a/src/XRP/XAddress.cpp b/src/XRP/XAddress.cpp index 0eb5e6978f8..da833880a8f 100644 --- a/src/XRP/XAddress.cpp +++ b/src/XRP/XAddress.cpp @@ -15,7 +15,7 @@ namespace TW::Ripple { const Data prefixMainnet = {0x05, 0x44}; bool XAddress::isValid(const std::string& string) { - const auto decoded = Base58::ripple.decodeCheck(string); + const auto decoded = Base58::decodeCheck(string, Base58Alphabet::Ripple); if (decoded.size() != XAddress::size) { return false; } @@ -32,7 +32,7 @@ XAddress::XAddress(const std::string& string) { if (!XAddress::isValid(string)) { throw std::invalid_argument("Invalid address string"); } - const auto decoded = Base58::ripple.decodeCheck(string); + const auto decoded = Base58::decodeCheck(string, Base58Alphabet::Ripple); std::copy(decoded.begin() + prefixMainnet.size(), decoded.begin() + prefixMainnet.size() + XAddress::keyHashSize, bytes.begin()); if (decoded[22] == byte(TagFlag::classic)) { tag = decode32LE(Data(decoded.end() - 8, decoded.end() - 4).data()); @@ -57,7 +57,7 @@ std::string XAddress::string() const { append(result, byte(flag)); encode32LE(tag, result); append(result, Data{0x00, 0x00, 0x00, 0x00}); - return Base58::ripple.encodeCheck(result); + return Base58::encodeCheck(result, Base58Alphabet::Ripple); } } // namespace TW::Ripple diff --git a/src/interface/TWBase58.cpp b/src/interface/TWBase58.cpp index 923b8a33bf0..e29779ed677 100644 --- a/src/interface/TWBase58.cpp +++ b/src/interface/TWBase58.cpp @@ -14,19 +14,19 @@ using namespace TW; TWString *_Nonnull TWBase58Encode(TWData *_Nonnull data) { const auto& d = *reinterpret_cast(data); - const auto str = Base58::bitcoin.encodeCheck(d); + const auto str = Base58::encodeCheck(d); return TWStringCreateWithUTF8Bytes(str.c_str()); } TWString *_Nonnull TWBase58EncodeNoCheck(TWData *_Nonnull data) { auto& d = *reinterpret_cast(data); - const auto encoded = Base58::bitcoin.encode(d); + const auto encoded = Base58::encode(d); return TWStringCreateWithUTF8Bytes(encoded.c_str()); } TWData *_Nullable TWBase58Decode(TWString *_Nonnull string) { auto& s = *reinterpret_cast(string); - const auto decoded = Base58::bitcoin.decodeCheck(s); + const auto decoded = Base58::decodeCheck(s); if (decoded.empty()) { return nullptr; } @@ -36,7 +36,7 @@ TWData *_Nullable TWBase58Decode(TWString *_Nonnull string) { TWData *_Nullable TWBase58DecodeNoCheck(TWString *_Nonnull string) { auto& s = *reinterpret_cast(string); - const auto decoded = Base58::bitcoin.decode(s); + const auto decoded = Base58::decode(s); if (decoded.empty()) { return nullptr; } diff --git a/tests/chains/Bitcoin/TWBitcoinSigningTests.cpp b/tests/chains/Bitcoin/TWBitcoinSigningTests.cpp index bdf001a94a8..5970e98caca 100644 --- a/tests/chains/Bitcoin/TWBitcoinSigningTests.cpp +++ b/tests/chains/Bitcoin/TWBitcoinSigningTests.cpp @@ -1497,7 +1497,7 @@ TEST(BitcoinSigning, EncodeThreeOutput) { TEST(BitcoinSigning, RedeemExtendedPubkeyUTXO) { auto wif = "L4BeKzm3AHDUMkxLRVKTSVxkp6Hz9FcMQPh18YCKU1uioXfovzwP"; - auto decoded = Base58::bitcoin.decodeCheck(wif); + auto decoded = Base58::decodeCheck(wif); auto key = PrivateKey(Data(decoded.begin() + 1, decoded.begin() + 33)); auto pubkey = key.getPublicKey(TWPublicKeyTypeSECP256k1Extended); auto hash = Hash::sha256ripemd(pubkey.bytes.data(), pubkey.bytes.size()); diff --git a/tests/chains/FIO/SignerTests.cpp b/tests/chains/FIO/SignerTests.cpp index 871db8d8091..a55e851f18f 100644 --- a/tests/chains/FIO/SignerTests.cpp +++ b/tests/chains/FIO/SignerTests.cpp @@ -29,7 +29,7 @@ TEST(FIOSigner, SignInternals) { { Data pk2 = parse_hex("80"); append(pk2, pk.bytes); - EXPECT_EQ("5KEDWtAUJcFX6Vz38WXsAQAv2geNqT7UaZC8gYu9kTuryr3qkri", Base58::bitcoin.encodeCheck(pk2)); + EXPECT_EQ("5KEDWtAUJcFX6Vz38WXsAQAv2geNqT7UaZC8gYu9kTuryr3qkri", Base58::encodeCheck(pk2)); } Data rawData = parse_hex("4e46572250454b796d7296eec9e8896327ea82dd40f2cd74cf1b1d8ba90bcd774a26285e19fac10ac5390000000001003056372503a85b0000c6eaa6645232017016f2cc12266c6b00000000a8ed3232bd010f6164616d4066696f746573746e657403034254432a626331717679343037347267676b647232707a773576706e6e3632656730736d7a6c7877703730643776034554482a30786365356342366339324461333762624261393142643430443443394434443732344133613846353103424e422a626e6231747333646735346170776c76723968757076326e306a366534367135347a6e6e75736a6b397300000000000000007016f2cc12266c6b0e726577617264734077616c6c6574000000000000000000000000000000000000000000000000000000000000000000"); Data hash = Hash::sha256(rawData); diff --git a/tests/chains/NEAR/AddressTests.cpp b/tests/chains/NEAR/AddressTests.cpp index 214cd3fab2b..a8acd44cf68 100644 --- a/tests/chains/NEAR/AddressTests.cpp +++ b/tests/chains/NEAR/AddressTests.cpp @@ -32,7 +32,7 @@ TEST(NEARAddress, FromString) { } TEST(NEARAddress, FromPrivateKey) { - auto fullKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + auto fullKey = Base58::decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); auto key = PrivateKey(Data(fullKey.begin(), fullKey.begin() + 32)); auto publicKey = key.getPublicKey(TWPublicKeyTypeED25519); auto address = Address(publicKey); diff --git a/tests/chains/NEAR/SerializationTests.cpp b/tests/chains/NEAR/SerializationTests.cpp index 7f6904988b6..98fd6db327b 100644 --- a/tests/chains/NEAR/SerializationTests.cpp +++ b/tests/chains/NEAR/SerializationTests.cpp @@ -15,7 +15,7 @@ namespace TW::NEAR { TEST(NEARSerialization, SerializeTransferTransaction) { - auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + auto publicKey = Base58::decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); auto input = Proto::SigningInput(); input.set_signer_id("test.near"); @@ -28,10 +28,10 @@ TEST(NEARSerialization, SerializeTransferTransaction) { deposit[0] = 1; transfer.set_deposit(deposit.data(), deposit.size()); - auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + auto blockHash = Base58::decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); input.set_block_hash(blockHash.data(), blockHash.size()); - auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + auto privateKey = Base58::decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); input.set_private_key(privateKey.data(), 32); auto serialized = transactionData(input); @@ -41,7 +41,7 @@ TEST(NEARSerialization, SerializeTransferTransaction) { } TEST(NEARSerialization, SerializeFunctionCallTransaction) { - auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + auto publicKey = Base58::decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); auto input = Proto::SigningInput(); input.set_signer_id("test.near"); @@ -64,10 +64,10 @@ TEST(NEARSerialization, SerializeFunctionCallTransaction) { args[2] = 3; functionCall.set_args(args.data(), args.size()); - auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + auto blockHash = Base58::decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); input.set_block_hash(blockHash.data(), blockHash.size()); - auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + auto privateKey = Base58::decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); input.set_private_key(privateKey.data(), 32); auto serialized = transactionData(input); @@ -77,7 +77,7 @@ TEST(NEARSerialization, SerializeFunctionCallTransaction) { } TEST(NEARSerialization, SerializeStakeTransaction) { - auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + auto publicKey = Base58::decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); auto input = Proto::SigningInput(); input.set_signer_id("test.near"); @@ -94,10 +94,10 @@ TEST(NEARSerialization, SerializeStakeTransaction) { pKey.set_data(publicKey.data(), publicKey.size()); pKey.set_key_type(0); - auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + auto blockHash = Base58::decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); input.set_block_hash(blockHash.data(), blockHash.size()); - auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + auto privateKey = Base58::decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); input.set_private_key(privateKey.data(), 32); auto serialized = transactionData(input); @@ -107,7 +107,7 @@ TEST(NEARSerialization, SerializeStakeTransaction) { } TEST(NEARSerialization, SerializeStakeTransaction2) { - auto publicKey = Base58::bitcoin.decode("C2P7YcEmBv31vtCHLBcESteN4Yi4vSCkXEXMTANyB649"); + auto publicKey = Base58::decode("C2P7YcEmBv31vtCHLBcESteN4Yi4vSCkXEXMTANyB649"); auto input = Proto::SigningInput(); input.set_signer_id("vdx.testnet"); @@ -124,10 +124,10 @@ TEST(NEARSerialization, SerializeStakeTransaction2) { pKey.set_data(publicKey.data(), publicKey.size()); pKey.set_key_type(0); - auto blockHash = Base58::bitcoin.decode("ByDnm7c25npQXwNUX5yivbYbpjFcNuNumF6BJjaK3vhJ"); + auto blockHash = Base58::decode("ByDnm7c25npQXwNUX5yivbYbpjFcNuNumF6BJjaK3vhJ"); input.set_block_hash(blockHash.data(), blockHash.size()); - auto privateKey = Base58::bitcoin.decode("5Cfk7QBnmDxxFxQk75FFq4ADrQS9gxHKe6vtuGH6JCCm8WV8aRPEGVqp579JHNmmHMUt49gkCVcH2t7NRnh2v7Qu"); + auto privateKey = Base58::decode("5Cfk7QBnmDxxFxQk75FFq4ADrQS9gxHKe6vtuGH6JCCm8WV8aRPEGVqp579JHNmmHMUt49gkCVcH2t7NRnh2v7Qu"); input.set_private_key(privateKey.data(), 32); auto serialized = transactionData(input); @@ -137,7 +137,7 @@ TEST(NEARSerialization, SerializeStakeTransaction2) { } TEST(NEARSerialization, SerializeAddKeyFunctionCallTransaction) { - auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + auto publicKey = Base58::decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); auto input = Proto::SigningInput(); input.set_signer_id("test.near"); @@ -157,10 +157,10 @@ TEST(NEARSerialization, SerializeAddKeyFunctionCallTransaction) { functionCallPermission.set_receiver_id("zzz"); functionCallPermission.add_method_names("www"); - auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + auto blockHash = Base58::decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); input.set_block_hash(blockHash.data(), blockHash.size()); - auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + auto privateKey = Base58::decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); input.set_private_key(privateKey.data(), 32); auto serialized = transactionData(input); @@ -170,7 +170,7 @@ TEST(NEARSerialization, SerializeAddKeyFunctionCallTransaction) { } TEST(NEARSerialization, SerializeAddKeyFullAccessTransaction) { - auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + auto publicKey = Base58::decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); auto input = Proto::SigningInput(); input.set_signer_id("test.near"); @@ -189,10 +189,10 @@ TEST(NEARSerialization, SerializeAddKeyFullAccessTransaction) { accessKey.mutable_full_access(); - auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + auto blockHash = Base58::decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); input.set_block_hash(blockHash.data(), blockHash.size()); - auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + auto privateKey = Base58::decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); input.set_private_key(privateKey.data(), 32); auto serialized = transactionData(input); @@ -202,7 +202,7 @@ TEST(NEARSerialization, SerializeAddKeyFullAccessTransaction) { } TEST(NEARSerialization, SerializeDeleteKeyTransaction) { - auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + auto publicKey = Base58::decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); auto input = Proto::SigningInput(); input.set_signer_id("test.near"); @@ -216,10 +216,10 @@ TEST(NEARSerialization, SerializeDeleteKeyTransaction) { pKey.set_data(publicKey.data(), publicKey.size()); pKey.set_key_type(0); - auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + auto blockHash = Base58::decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); input.set_block_hash(blockHash.data(), blockHash.size()); - auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + auto privateKey = Base58::decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); input.set_private_key(privateKey.data(), 32); auto serialized = transactionData(input); @@ -229,7 +229,7 @@ TEST(NEARSerialization, SerializeDeleteKeyTransaction) { } TEST(NEARSerialization, SerializeCreateAccountTransaction) { - auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + auto publicKey = Base58::decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); auto input = Proto::SigningInput(); input.set_signer_id("test.near"); @@ -239,10 +239,10 @@ TEST(NEARSerialization, SerializeCreateAccountTransaction) { input.add_actions(); input.mutable_actions(0)->mutable_create_account(); - auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + auto blockHash = Base58::decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); input.set_block_hash(blockHash.data(), blockHash.size()); - auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + auto privateKey = Base58::decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); input.set_private_key(privateKey.data(), 32); auto serialized = transactionData(input); @@ -252,7 +252,7 @@ TEST(NEARSerialization, SerializeCreateAccountTransaction) { } TEST(NEARSerialization, SerializeDeleteAccountTransaction) { - auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + auto publicKey = Base58::decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); auto input = Proto::SigningInput(); input.set_signer_id("test.near"); @@ -263,10 +263,10 @@ TEST(NEARSerialization, SerializeDeleteAccountTransaction) { auto& deleteAccount = *input.mutable_actions(0)->mutable_delete_account(); deleteAccount.set_beneficiary_id("123"); - auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + auto blockHash = Base58::decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); input.set_block_hash(blockHash.data(), blockHash.size()); - auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + auto privateKey = Base58::decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); input.set_private_key(privateKey.data(), 32); auto serialized = transactionData(input); diff --git a/tests/chains/NEAR/SignerTests.cpp b/tests/chains/NEAR/SignerTests.cpp index 2a41296484c..84961c45ea8 100644 --- a/tests/chains/NEAR/SignerTests.cpp +++ b/tests/chains/NEAR/SignerTests.cpp @@ -16,7 +16,7 @@ namespace TW::NEAR { TEST(NEARSigner, SignTx) { - auto publicKey = Base58::bitcoin.decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); + auto publicKey = Base58::decode("Anu7LYDfpLtkP7E16LT9imXF694BdQaa9ufVkQiwTQxC"); auto input = Proto::SigningInput(); input.set_signer_id("test.near"); @@ -30,10 +30,10 @@ TEST(NEARSigner, SignTx) { // uint128_t / little endian byte order transfer.set_deposit(deposit.data(), deposit.size()); - auto blockHash = Base58::bitcoin.decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); + auto blockHash = Base58::decode("244ZQ9cgj3CQ6bWBdytfrJMuMQ1jdXLFGnr4HhvtCTnM"); input.set_block_hash(blockHash.data(), blockHash.size()); - auto privateKey = Base58::bitcoin.decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); + auto privateKey = Base58::decode("3hoMW1HvnRLSFCLZnvPzWeoGwtdHzke34B2cTHM8rhcbG3TbuLKtShTv3DvyejnXKXKBiV7YPkLeqUHN1ghnqpFv"); input.set_private_key(privateKey.data(), 32); auto output = Signer::sign(std::move(input)); diff --git a/tests/chains/NEAR/TWAnySignerTests.cpp b/tests/chains/NEAR/TWAnySignerTests.cpp index 3286c0c8475..b9fa56f75cb 100644 --- a/tests/chains/NEAR/TWAnySignerTests.cpp +++ b/tests/chains/NEAR/TWAnySignerTests.cpp @@ -71,7 +71,7 @@ TEST(TWAnySignerNEAR, SignStake) { } TEST(TWAnySignerNEAR, SignStakeMainnetReplication) { - auto privateKey = Base58::bitcoin.decode("3BPZ9Qu7CviWD4CeKy3DYbNc4suyuBJYnjhVT2oTRCrfb4CQPiTK5tFVdg8Z3ijozxWoxxt9Y1kwkwPntrcc3dom"); + auto privateKey = Base58::decode("3BPZ9Qu7CviWD4CeKy3DYbNc4suyuBJYnjhVT2oTRCrfb4CQPiTK5tFVdg8Z3ijozxWoxxt9Y1kwkwPntrcc3dom"); auto blockHash = parse_hex("e78680996127b7a0f3f2343502e442f24366cba5f79cb72f8bc6d0debb26ce24"); // 0.1 with 24 decimal precision in big endian @@ -95,13 +95,13 @@ TEST(TWAnySignerNEAR, SignStakeMainnetReplication) { ANY_SIGN(input, TWCoinTypeNEAR); // https://explorer.near.org/transactions/kd7ajFw1CfXB8LiJXvhz5NDS7QpQXkuQraAbhb5MMMq - ASSERT_EQ(Base58::bitcoin.encode(data(output.hash())), "kd7ajFw1CfXB8LiJXvhz5NDS7QpQXkuQraAbhb5MMMq"); + ASSERT_EQ(Base58::encode(data(output.hash())), "kd7ajFw1CfXB8LiJXvhz5NDS7QpQXkuQraAbhb5MMMq"); ASSERT_EQ(Base64::encode(data(output.signed_transaction())), "QAAAAGI4ZDVkZjI1MDQ3ODQxMzY1MDA4ZjMwZmI2YjMwZGQ4MjBlOWE4NGQ4NjlmMDU2MjNkMTE0ZTk2ODMxZjJmYmYAzgCT6NK76nb1mB7pToefgkGUHfUe5BKvvr3gW/nq+MgEuu1Mq0YAABEAAABhdmFkby5wb29sdjEubmVhcueGgJlhJ7eg8/I0NQLkQvJDZsul95y3L4vG0N67Js4kAQAAAAIRAAAAZGVwb3NpdF9hbmRfc3Rha2UCAAAAe30A0JjUr3EAAAAAgPZK4ccCLRUAAAAAAAAALNrorr8qTL6u1nlxLpuPa45nFdYmjU96i7CmJP08mVHVzHUaw/bGN30Z3u3o1F2o2yefCBNqO9Ogn9fM25NGCg=="); } TEST(TWAnySignerNEAR, SignUnstakeMainnetReplication) { - auto privateKey = Base58::bitcoin.decode("3BPZ9Qu7CviWD4CeKy3DYbNc4suyuBJYnjhVT2oTRCrfb4CQPiTK5tFVdg8Z3ijozxWoxxt9Y1kwkwPntrcc3dom"); - auto blockHash = Base58::bitcoin.decode("CehJc9uZhqE2m17ZrkqcAog4mxSz6JSvYv1JEK1iBsX9"); + auto privateKey = Base58::decode("3BPZ9Qu7CviWD4CeKy3DYbNc4suyuBJYnjhVT2oTRCrfb4CQPiTK5tFVdg8Z3ijozxWoxxt9Y1kwkwPntrcc3dom"); + auto blockHash = Base58::decode("CehJc9uZhqE2m17ZrkqcAog4mxSz6JSvYv1JEK1iBsX9"); auto amount = parse_hex("00000000000000000000000000000000"); @@ -123,7 +123,7 @@ TEST(TWAnySignerNEAR, SignUnstakeMainnetReplication) { ANY_SIGN(input, TWCoinTypeNEAR); // https://explorer.near.org/transactions/DH6QAX3TkY6XtkteorvKBoGT5hA5ADkURZdzrbbKRs8P - ASSERT_EQ(Base58::bitcoin.encode(data(output.hash())), "DH6QAX3TkY6XtkteorvKBoGT5hA5ADkURZdzrbbKRs8P"); + ASSERT_EQ(Base58::encode(data(output.hash())), "DH6QAX3TkY6XtkteorvKBoGT5hA5ADkURZdzrbbKRs8P"); ASSERT_EQ(Base64::encode(data(output.signed_transaction())), "QAAAAGI4ZDVkZjI1MDQ3ODQxMzY1MDA4ZjMwZmI2YjMwZGQ4MjBlOWE4NGQ4NjlmMDU2MjNkMTE0ZTk2ODMxZjJmYmYAzgCT6NK76nb1mB7pToefgkGUHfUe5BKvvr3gW/nq+MgGuu1Mq0YAABEAAABhdmFkby5wb29sdjEubmVhcq0YnhRlt+TTtagkoy0qKn56zAfGhE+jkTJW6PR5k5r8AQAAAAILAAAAdW5zdGFrZV9hbGwCAAAAe30A0JjUr3EAAAAAAAAAAAAAAAAAAAAAAAAABaFP0EkfJU3VQZ4QAiTwq9ebWDJ7jx7TxbA+VGH4hwKX3gWnmDHVve+LK7/UbbffjF/y8vn0KrPxdh3ONAG0Ag=="); } diff --git a/tests/chains/Nebulas/AddressTests.cpp b/tests/chains/Nebulas/AddressTests.cpp index 45a70df9a09..3ab85ba59a6 100644 --- a/tests/chains/Nebulas/AddressTests.cpp +++ b/tests/chains/Nebulas/AddressTests.cpp @@ -27,7 +27,7 @@ TEST(NebulasAddress, String) { ASSERT_THROW(Address("abc"), std::invalid_argument); ASSERT_EQ(Address("n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY").string(), "n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY"); - ASSERT_EQ(Address(Base58::bitcoin.decode("n1TgpFZWCMmFd2sphb6RKsCvsEyMCNa2Yyv")).string(), + ASSERT_EQ(Address(Base58::decode("n1TgpFZWCMmFd2sphb6RKsCvsEyMCNa2Yyv")).string(), "n1TgpFZWCMmFd2sphb6RKsCvsEyMCNa2Yyv"); const auto address = Address("n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY"); @@ -37,7 +37,7 @@ TEST(NebulasAddress, String) { TEST(NebulasAddress, Data) { Data data; EXPECT_THROW(Address(data).string(), std::invalid_argument); - ASSERT_EQ(Address(Base58::bitcoin.decode("n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY")).string(), + ASSERT_EQ(Address(Base58::decode("n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY")).string(), "n1V5bB2tbaM3FUiL4eRwpBLgEredS5C2wLY"); } diff --git a/tests/chains/Solana/AddressTests.cpp b/tests/chains/Solana/AddressTests.cpp index 15f011299f9..c5217e3e7c9 100644 --- a/tests/chains/Solana/AddressTests.cpp +++ b/tests/chains/Solana/AddressTests.cpp @@ -19,7 +19,7 @@ namespace TW::Solana::tests { TEST(SolanaAddress, FromPublicKey) { const auto addressString = "2gVkYWexTHR5Hb2aLeQN3tnngvWzisFKXDUPrgMHpdST"; - const auto publicKey = PublicKey(Base58::bitcoin.decode(addressString), TWPublicKeyTypeED25519); + const auto publicKey = PublicKey(Base58::decode(addressString), TWPublicKeyTypeED25519); const auto address = Address(publicKey); ASSERT_EQ(addressString, address.string()); } @@ -39,14 +39,14 @@ TEST(SolanaAddress, isValid) { } TEST(SolanaAddress, isValidOnCurve) { - EXPECT_TRUE(PublicKey(Base58::bitcoin.decode("HzqnaMjWFbK2io6WgV2Z5uBguCBU21RMUS16wsDUHkon"), TWPublicKeyTypeED25519).isValidED25519()); - EXPECT_TRUE(PublicKey(Base58::bitcoin.decode("68io7dTfyeWua1wD1YcCMka4y5iiChceaFRCBjqCM5PK"), TWPublicKeyTypeED25519).isValidED25519()); - EXPECT_TRUE(PublicKey(Base58::bitcoin.decode("Dra34QLFCjxnk8tUNcBwxs6pgb5spF4oseQYF2xn7ABZ"), TWPublicKeyTypeED25519).isValidED25519()); + EXPECT_TRUE(PublicKey(Base58::decode("HzqnaMjWFbK2io6WgV2Z5uBguCBU21RMUS16wsDUHkon"), TWPublicKeyTypeED25519).isValidED25519()); + EXPECT_TRUE(PublicKey(Base58::decode("68io7dTfyeWua1wD1YcCMka4y5iiChceaFRCBjqCM5PK"), TWPublicKeyTypeED25519).isValidED25519()); + EXPECT_TRUE(PublicKey(Base58::decode("Dra34QLFCjxnk8tUNcBwxs6pgb5spF4oseQYF2xn7ABZ"), TWPublicKeyTypeED25519).isValidED25519()); // negative case - EXPECT_FALSE(PublicKey(Base58::bitcoin.decode("6X4X1Ae24mkoWeCEpktevySVG9jzeCufut5vtUW3wFrD"), TWPublicKeyTypeED25519).isValidED25519()); - EXPECT_FALSE(PublicKey(Base58::bitcoin.decode("EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"), TWPublicKeyTypeED25519).isValidED25519()); - EXPECT_FALSE(PublicKey(Base58::bitcoin.decode("ANVCrmRw7Ww7rTFfMbrjApSPXEEcZpBa6YEiBdf98pAf"), TWPublicKeyTypeED25519).isValidED25519()); - EXPECT_FALSE(PublicKey(Base58::bitcoin.decode("AbygL37RheNZv327cMvZPqKYLLkZ6wqWYexRxgNiZyeP"), TWPublicKeyTypeED25519).isValidED25519()); + EXPECT_FALSE(PublicKey(Base58::decode("6X4X1Ae24mkoWeCEpktevySVG9jzeCufut5vtUW3wFrD"), TWPublicKeyTypeED25519).isValidED25519()); + EXPECT_FALSE(PublicKey(Base58::decode("EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"), TWPublicKeyTypeED25519).isValidED25519()); + EXPECT_FALSE(PublicKey(Base58::decode("ANVCrmRw7Ww7rTFfMbrjApSPXEEcZpBa6YEiBdf98pAf"), TWPublicKeyTypeED25519).isValidED25519()); + EXPECT_FALSE(PublicKey(Base58::decode("AbygL37RheNZv327cMvZPqKYLLkZ6wqWYexRxgNiZyeP"), TWPublicKeyTypeED25519).isValidED25519()); } TEST(SolanaAddress, defaultTokenAddress) { diff --git a/tests/chains/Solana/ProgramTests.cpp b/tests/chains/Solana/ProgramTests.cpp index 2b443c6ddfb..a318e462d92 100644 --- a/tests/chains/Solana/ProgramTests.cpp +++ b/tests/chains/Solana/ProgramTests.cpp @@ -27,14 +27,14 @@ TEST(SolanaStakeProgram, addressFromValidatorSeed) { TEST(SolanaStakeProgram, addressFromRecentBlockhash) { { auto user = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); - Data recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + Data recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto programId = Address("Stake11111111111111111111111111111111111111"); auto expected = Address("GQDDc5EVGJZFC7AvpEJ8eoCQ75Yy4gr7eu17frCjvQRQ"); EXPECT_EQ(StakeProgram::addressFromRecentBlockhash(user, recentBlockhash, programId), expected); } { auto user = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); - Data recentBlockhash = Base58::bitcoin.decode("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); + Data recentBlockhash = Base58::decode("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); auto programId = Address("Stake11111111111111111111111111111111111111"); auto expected = Address("2Kos1xJRBq3Ae1GnVNBx7HgJhq8KvdUe2bXE4QGdNaXb"); EXPECT_EQ(StakeProgram::addressFromRecentBlockhash(user, recentBlockhash, programId), expected); @@ -49,9 +49,9 @@ TEST(SolanaTokenProgram, defaultTokenAddress) { TEST(SolanaTokenProgram, findProgramAddress) { std::vector seeds = { - Base58::bitcoin.decode("B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"), - Base58::bitcoin.decode("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), - Base58::bitcoin.decode("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"), + Base58::decode("B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"), + Base58::decode("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), + Base58::decode("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"), }; { Address address = TokenProgram::findProgramAddress(seeds, Address("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")); @@ -65,9 +65,9 @@ TEST(SolanaTokenProgram, findProgramAddress) { TEST(SolanaTokenProgram, createProgramAddress) { std::vector seeds4 = { - Base58::bitcoin.decode("B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"), - Base58::bitcoin.decode("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), - Base58::bitcoin.decode("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"), + Base58::decode("B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"), + Base58::decode("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), + Base58::decode("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"), Data{255}}; { Address address = TokenProgram::createProgramAddress(seeds4, Address("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")); @@ -89,7 +89,7 @@ TEST(SolanaTokenProgram, createProgramAddress) { EXPECT_EQ(address.string(), "HwRVBufQ4haG5XSgpspwKtNd3PC9GM9m1196uJW36vds"); } { - std::vector seeds = {Base58::bitcoin.decode("SeedPubey1111111111111111111111111111111111")}; + std::vector seeds = {Base58::decode("SeedPubey1111111111111111111111111111111111")}; Address address = TokenProgram::createProgramAddress(seeds, Address("BPFLoader1111111111111111111111111111111111")); EXPECT_EQ(address.string(), "GUs5qLUfsEHkcMB9T38vjr18ypEhRuNWiePW2LoK4E3K"); } diff --git a/tests/chains/Solana/SignerTests.cpp b/tests/chains/Solana/SignerTests.cpp index b4ee4910b8e..96bc64a332d 100644 --- a/tests/chains/Solana/SignerTests.cpp +++ b/tests/chains/Solana/SignerTests.cpp @@ -17,17 +17,17 @@ namespace TW::Solana::tests { TEST(SolanaSigner, CompiledInstruction) { const auto privateKey0 = - PrivateKey(Base58::bitcoin.decode("96PKHuMPtniu1T74RvUNkbDPXPPRZ8Mg1zXwciCAyaDq")); + PrivateKey(Base58::decode("96PKHuMPtniu1T74RvUNkbDPXPPRZ8Mg1zXwciCAyaDq")); const auto publicKey0 = privateKey0.getPublicKey(TWPublicKeyTypeED25519); const auto address0 = Address(publicKey0); ASSERT_EQ(Data(publicKey0.bytes.begin(), publicKey0.bytes.end()), - Base58::bitcoin.decode("GymAh18wHuFTytfSJWi8eYTA9x5S3sNb9CJSGBWoPRE3")); + Base58::decode("GymAh18wHuFTytfSJWi8eYTA9x5S3sNb9CJSGBWoPRE3")); const auto privateKey1 = - PrivateKey(Base58::bitcoin.decode("GvGmNPMQLZE2VNx3KG2GdiC4ndS8uCqd7PjioPgm9Qhi")); + PrivateKey(Base58::decode("GvGmNPMQLZE2VNx3KG2GdiC4ndS8uCqd7PjioPgm9Qhi")); const auto publicKey1 = privateKey1.getPublicKey(TWPublicKeyTypeED25519); const auto address1 = Address(publicKey1); ASSERT_EQ(Data(publicKey1.bytes.begin(), publicKey1.bytes.end()), - Base58::bitcoin.decode("2oKoYSAHgveX91917v4DUEuN8BNKXDg8KJWpaGyEay9V")); + Base58::decode("2oKoYSAHgveX91917v4DUEuN8BNKXDg8KJWpaGyEay9V")); Address programId("11111111111111111111111111111111"); std::vector
addresses = {address0, address1, programId}; @@ -85,14 +85,14 @@ TEST(SolanaSigner, CompiledInstructionFindAccount) { TEST(SolanaSigner, SingleSignTransaction) { const auto privateKey = - PrivateKey(Base58::bitcoin.decode("A7psj2GW7ZMdY4E5hJq14KMeYg7HFjULSsWSrTXZLvYr")); + PrivateKey(Base58::decode("A7psj2GW7ZMdY4E5hJq14KMeYg7HFjULSsWSrTXZLvYr")); const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519); ASSERT_EQ(Data(publicKey.bytes.begin(), publicKey.bytes.end()), - Base58::bitcoin.decode("7v91N7iZ9mNicL8WfG6cgSCKyRXydQjLh6UYBWwm6y1Q")); + Base58::decode("7v91N7iZ9mNicL8WfG6cgSCKyRXydQjLh6UYBWwm6y1Q")); const auto from = Address(publicKey); auto to = Address("EN2sCsJ1WDV8UFqsiTXHcUPUxQ4juE71eCknHYYMifkd"); - auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto transaction = VersionedTransaction(from, to, 42, recentBlockhash); std::vector signerKeys; @@ -113,7 +113,7 @@ TEST(SolanaSigner, SingleSignTransaction) { ASSERT_EQ(transaction.serialize(), expectedString); const auto additionalPrivateKey = - PrivateKey(Base58::bitcoin.decode("96PKHuMPtniu1T74RvUNkbDPXPPRZ8Mg1zXwciCAyaDq")); + PrivateKey(Base58::decode("96PKHuMPtniu1T74RvUNkbDPXPPRZ8Mg1zXwciCAyaDq")); signerKeys.push_back(additionalPrivateKey); try { Signer::sign(signerKeys, transaction); @@ -125,14 +125,14 @@ TEST(SolanaSigner, SingleSignTransaction) { TEST(SolanaSigner, SignTransactionToSelf) { const auto privateKey = - PrivateKey(Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746")); + PrivateKey(Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746")); const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519); ASSERT_EQ(Data(publicKey.bytes.begin(), publicKey.bytes.end()), - Base58::bitcoin.decode("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu")); + Base58::decode("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu")); const auto from = Address(publicKey); auto to = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); - auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto transaction = VersionedTransaction(from, to, 42, recentBlockhash); std::vector signerKeys; @@ -154,17 +154,17 @@ TEST(SolanaSigner, SignTransactionToSelf) { TEST(SolanaSigner, MultipleSignTransaction) { const auto privateKey0 = - PrivateKey(Base58::bitcoin.decode("96PKHuMPtniu1T74RvUNkbDPXPPRZ8Mg1zXwciCAyaDq")); + PrivateKey(Base58::decode("96PKHuMPtniu1T74RvUNkbDPXPPRZ8Mg1zXwciCAyaDq")); const auto publicKey0 = privateKey0.getPublicKey(TWPublicKeyTypeED25519); const auto address0 = Address(publicKey0); ASSERT_EQ(Data(publicKey0.bytes.begin(), publicKey0.bytes.end()), - Base58::bitcoin.decode("GymAh18wHuFTytfSJWi8eYTA9x5S3sNb9CJSGBWoPRE3")); + Base58::decode("GymAh18wHuFTytfSJWi8eYTA9x5S3sNb9CJSGBWoPRE3")); const auto privateKey1 = - PrivateKey(Base58::bitcoin.decode("GvGmNPMQLZE2VNx3KG2GdiC4ndS8uCqd7PjioPgm9Qhi")); + PrivateKey(Base58::decode("GvGmNPMQLZE2VNx3KG2GdiC4ndS8uCqd7PjioPgm9Qhi")); const auto publicKey1 = privateKey1.getPublicKey(TWPublicKeyTypeED25519); const auto address1 = Address(publicKey1); ASSERT_EQ(Data(publicKey1.bytes.begin(), publicKey1.bytes.end()), - Base58::bitcoin.decode("2oKoYSAHgveX91917v4DUEuN8BNKXDg8KJWpaGyEay9V")); + Base58::decode("2oKoYSAHgveX91917v4DUEuN8BNKXDg8KJWpaGyEay9V")); Data data = {0, 0, 0, 0}; Address programId("11111111111111111111111111111111"); @@ -177,7 +177,7 @@ TEST(SolanaSigner, MultipleSignTransaction) { MessageHeader header = {2, 0, 1}; std::vector
accountKeys = {address0, address1, programId}; - auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); LegacyMessage message; message.header = header; message.accountKeys = accountKeys; @@ -213,21 +213,21 @@ TEST(SolanaSigner, MultipleSignTransaction) { TEST(SolanaSigner, SignUpdateBlockhash) { const auto privateKey = - PrivateKey(Base58::bitcoin.decode("G4VSzrknPBWZ1z2YwUnWTxD1td7wmqR5jMPEJRN6wm8S")); + PrivateKey(Base58::decode("G4VSzrknPBWZ1z2YwUnWTxD1td7wmqR5jMPEJRN6wm8S")); const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519); ASSERT_EQ(Data(publicKey.bytes.begin(), publicKey.bytes.end()), - Base58::bitcoin.decode("41a5jYky56M6EWDsFfLaZRxoRtgAJSRWxJnxaJNJELn5")); + Base58::decode("41a5jYky56M6EWDsFfLaZRxoRtgAJSRWxJnxaJNJELn5")); const auto from = Address(publicKey); auto to = Address("4iSnyfDKaejniaPc2pBBckwQqV3mDS93go15NdxWJq2y"); - auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto transaction = VersionedTransaction(from, to, 42, recentBlockhash); std::vector signerKeys; signerKeys.push_back(privateKey); Signer::sign(signerKeys, transaction); - auto newBlockhash = Base58::bitcoin.decode("GgBaCs3NCBuZN12kCJgAW63ydqohFkHEdfdEXBPzLHq"); + auto newBlockhash = Base58::decode("GgBaCs3NCBuZN12kCJgAW63ydqohFkHEdfdEXBPzLHq"); Signer::signUpdateBlockhash(signerKeys, transaction, newBlockhash); std::vector expectedSignatures; @@ -246,10 +246,10 @@ TEST(SolanaSigner, SignUpdateBlockhash) { TEST(SolanaSigner, SignRawMessage) { const auto privateKey = - PrivateKey(Base58::bitcoin.decode("GjXseuD8JavBjKMdd6GEsPYZPV7tMMa46GS2JRS5tHRq")); + PrivateKey(Base58::decode("GjXseuD8JavBjKMdd6GEsPYZPV7tMMa46GS2JRS5tHRq")); const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519); ASSERT_EQ(Data(publicKey.bytes.begin(), publicKey.bytes.end()), - Base58::bitcoin.decode("3BocAWPm1oNXN5qkAV4QeDUmAPpkTcN1rrmCMWAfsXJY")); + Base58::decode("3BocAWPm1oNXN5qkAV4QeDUmAPpkTcN1rrmCMWAfsXJY")); auto rawMessageData = "01000203207be13c43c4528592eaf3fd34e064c641c5be3cb6691877d7ade94dff36734108eaea30723c33b525" @@ -272,14 +272,14 @@ TEST(SolanaSigner, SignRawMessage) { TEST(SolanaSigner, SignDelegateStakeV2) { const auto privateKeySigner = - PrivateKey(Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746")); + PrivateKey(Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746")); const auto publicKeySigner = privateKeySigner.getPublicKey(TWPublicKeyTypeED25519); auto signer = Address(publicKeySigner); ASSERT_EQ(signer.string(), "zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); auto voteAddress = Address("4jpwTqt1qZoR7u6u639z2AngYFGN3nakvKhowcnRZDEC"); auto programId = Address("Stake11111111111111111111111111111111111111"); - auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto stakeAddress = StakeProgram::addressFromRecentBlockhash(signer, recentBlockhash, programId); auto message = LegacyMessage::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); @@ -300,14 +300,14 @@ TEST(SolanaSigner, SignDelegateStakeV2) { TEST(SolanaSigner, SignDelegateStakeV1) { const auto privateKeySigner = - PrivateKey(Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746")); + PrivateKey(Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746")); const auto publicKeySigner = privateKeySigner.getPublicKey(TWPublicKeyTypeED25519); auto signer = Address(publicKeySigner); ASSERT_EQ(signer.string(), "zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); auto voteAddress = Address("4jpwTqt1qZoR7u6u639z2AngYFGN3nakvKhowcnRZDEC"); auto programId = Address("Stake11111111111111111111111111111111111111"); - auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto stakeAddress = StakeProgram::addressFromValidatorSeed(signer, voteAddress, programId); auto message = LegacyMessage::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); @@ -328,14 +328,14 @@ TEST(SolanaSigner, SignDelegateStakeV1) { TEST(SolanaSigner, SignCreateTokenAccount) { const auto privateKeySigner = - PrivateKey(Base58::bitcoin.decode("9YtuoD4sH4h88CVM8DSnkfoAaLY7YeGC2TarDJ8eyMS5")); + PrivateKey(Base58::decode("9YtuoD4sH4h88CVM8DSnkfoAaLY7YeGC2TarDJ8eyMS5")); const auto publicKeySigner = privateKeySigner.getPublicKey(TWPublicKeyTypeED25519); auto signer = Address(publicKeySigner); EXPECT_EQ(signer.string(), "B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); auto token = Address("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"); auto tokenAddress = Address("EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); - auto recentBlockhash = Base58::bitcoin.decode("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); + auto recentBlockhash = Base58::decode("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); auto message = LegacyMessage::createTokenCreateAccount(signer, signer, token, tokenAddress, recentBlockhash); auto transaction = VersionedTransaction(VersionedMessage(message)); @@ -365,7 +365,7 @@ TEST(SolanaSigner, SignCreateTokenAccountForOther_3E6UFV) { auto otherMainAddress = Address("3xJ3MoUVFPNFEHfWdtNFa8ajXUHsJPzXcBSWMKLd76ft"); auto token = Address("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"); auto tokenAddress = Address("67BrwFYt7qUnbAcYBVx7sQ4jeD2KWN1ohP6bMikmmQV3"); - auto recentBlockhash = Base58::bitcoin.decode("HmWyvrif3QfZJnDiRyrojmH9iLr7eMxxqiC9RJWFeunr"); + auto recentBlockhash = Base58::decode("HmWyvrif3QfZJnDiRyrojmH9iLr7eMxxqiC9RJWFeunr"); auto message = LegacyMessage::createTokenCreateAccount(signer, otherMainAddress, token, tokenAddress, recentBlockhash); auto transaction = VersionedTransaction(VersionedMessage(message)); @@ -382,7 +382,7 @@ TEST(SolanaSigner, SignCreateTokenAccountForOther_3E6UFV) { TEST(SolanaSigner, SignTransferToken_3vZ67C) { const auto privateKeySigner = - PrivateKey(Base58::bitcoin.decode("9YtuoD4sH4h88CVM8DSnkfoAaLY7YeGC2TarDJ8eyMS5")); + PrivateKey(Base58::decode("9YtuoD4sH4h88CVM8DSnkfoAaLY7YeGC2TarDJ8eyMS5")); const auto publicKeySigner = privateKeySigner.getPublicKey(TWPublicKeyTypeED25519); auto signer = Address(publicKeySigner); EXPECT_EQ(signer.string(), "B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); @@ -392,7 +392,7 @@ TEST(SolanaSigner, SignTransferToken_3vZ67C) { auto recipientTokenAddress = Address("3WUX9wASxyScbA7brDipioKfXS1XEYkQ4vo3Kej9bKei"); uint64_t amount = 4000; uint8_t decimals = 6; - auto recentBlockhash = Base58::bitcoin.decode("CNaHfvqePgGYMvtYi9RuUdVxDYttr1zs4TWrTXYabxZi"); + auto recentBlockhash = Base58::decode("CNaHfvqePgGYMvtYi9RuUdVxDYttr1zs4TWrTXYabxZi"); auto message = LegacyMessage::createTokenTransfer(signer, token, senderTokenAddress, recipientTokenAddress, amount, decimals, recentBlockhash); diff --git a/tests/chains/Solana/TWAnySignerTests.cpp b/tests/chains/Solana/TWAnySignerTests.cpp index de5ee2cd869..a96846eba74 100644 --- a/tests/chains/Solana/TWAnySignerTests.cpp +++ b/tests/chains/Solana/TWAnySignerTests.cpp @@ -25,7 +25,7 @@ const auto expectedString1 = "sW9kYUtRDW1UC2LgHr7npgq5W9TBmHf9hSmRgM9XXucjXLqubNWE7HUMhbKjuBqkirRM"; TEST(TWAnySignerSolana, SignTransfer) { - auto privateKey = Base58::bitcoin.decode("A7psj2GW7ZMdY4E5hJq14KMeYg7HFjULSsWSrTXZLvYr"); + auto privateKey = Base58::decode("A7psj2GW7ZMdY4E5hJq14KMeYg7HFjULSsWSrTXZLvYr"); auto input = Proto::SigningInput(); auto& message = *input.mutable_transfer_transaction(); @@ -60,7 +60,7 @@ TEST(TWAnySignerSolana, SignV0Transfer) { } TEST(TWAnySignerSolana, SignTransferToSelf) { - auto privateKey = Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); + auto privateKey = Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); auto input = Proto::SigningInput(); auto& message = *input.mutable_transfer_transaction(); @@ -80,7 +80,7 @@ TEST(TWAnySignerSolana, SignTransferToSelf) { } TEST(TWAnySignerSolana, SignTransferWithMemoAndReference) { - const auto privateKey = Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); + const auto privateKey = Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); auto input = Solana::Proto::SigningInput(); auto& message = *input.mutable_transfer_transaction(); @@ -100,7 +100,7 @@ TEST(TWAnySignerSolana, SignTransferWithMemoAndReference) { } TEST(TWAnySignerSolana, SignDelegateStakeTransaction_noStakeAccount) { - auto privateKey = Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); + auto privateKey = Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); auto input = Solana::Proto::SigningInput(); auto& message = *input.mutable_delegate_stake_transaction(); @@ -118,7 +118,7 @@ TEST(TWAnySignerSolana, SignDelegateStakeTransaction_noStakeAccount) { } TEST(TWAnySignerSolana, SignDelegateStakeTransaction_withAccount) { - auto privateKey = Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); + auto privateKey = Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); auto input = Solana::Proto::SigningInput(); auto& message = *input.mutable_delegate_stake_transaction(); @@ -136,7 +136,7 @@ TEST(TWAnySignerSolana, SignDelegateStakeTransaction_withAccount) { } TEST(TWAnySignerSolana, SignDeactivateStakeTransaction) { - auto privateKey = Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); + auto privateKey = Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); auto input = Solana::Proto::SigningInput(); auto& message = *input.mutable_deactivate_stake_transaction(); @@ -152,7 +152,7 @@ TEST(TWAnySignerSolana, SignDeactivateStakeTransaction) { } TEST(TWAnySignerSolana, SignDeactivateAllStakeTransaction) { - auto privateKey = Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); + auto privateKey = Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); auto input = Solana::Proto::SigningInput(); auto& message = *input.mutable_deactivate_all_stake_transaction(); @@ -169,7 +169,7 @@ TEST(TWAnySignerSolana, SignDeactivateAllStakeTransaction) { } TEST(TWAnySignerSolana, SignWithdrawStakeTransaction) { - auto privateKey = Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); + auto privateKey = Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); auto input = Solana::Proto::SigningInput(); auto& message = *input.mutable_withdraw_transaction(); @@ -186,7 +186,7 @@ TEST(TWAnySignerSolana, SignWithdrawStakeTransaction) { } TEST(TWAnySignerSolana, SignWithdrawAllStakeTransaction) { - auto privateKey = Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); + auto privateKey = Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); auto input = Solana::Proto::SigningInput(); auto& message = *input.mutable_withdraw_all_transaction(); @@ -207,7 +207,7 @@ TEST(TWAnySignerSolana, SignWithdrawAllStakeTransaction) { } TEST(TWAnySignerSolana, SignDeactivateStakeTransaction_1) { - auto privateKey = Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); + auto privateKey = Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); auto input = Solana::Proto::SigningInput(); auto& message = *input.mutable_deactivate_stake_transaction(); @@ -228,7 +228,7 @@ TEST(TWAnySignerSolana, SignDeactivateStakeTransaction_1) { } TEST(TWAnySignerSolana, SignWithdrawStakeTransaction_1) { - auto privateKey = Base58::bitcoin.decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); + auto privateKey = Base58::decode("AevJ4EWcvQ6dptBDvF2Ri5pU6QSBjkzSGHMfbLFKa746"); auto input = Solana::Proto::SigningInput(); auto& message = *input.mutable_withdraw_transaction(); @@ -245,7 +245,7 @@ TEST(TWAnySignerSolana, SignWithdrawStakeTransaction_1) { } TEST(TWAnySignerSolana, SignCreateTokenAccount1) { - auto privateKeyData = Base58::bitcoin.decode("9YtuoD4sH4h88CVM8DSnkfoAaLY7YeGC2TarDJ8eyMS5"); + auto privateKeyData = Base58::decode("9YtuoD4sH4h88CVM8DSnkfoAaLY7YeGC2TarDJ8eyMS5"); ASSERT_EQ(Address(PrivateKey(privateKeyData).getPublicKey(TWPublicKeyTypeED25519)).string(), "B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); auto input = Solana::Proto::SigningInput(); @@ -307,7 +307,7 @@ TEST(TWAnySignerSolana, SignCreateTokenAccountForOther_3E6UFV) { } TEST(TWAnySignerSolana, SignTokenTransfer1_3vZ67C) { - auto privateKeyData = Base58::bitcoin.decode("9YtuoD4sH4h88CVM8DSnkfoAaLY7YeGC2TarDJ8eyMS5"); + auto privateKeyData = Base58::decode("9YtuoD4sH4h88CVM8DSnkfoAaLY7YeGC2TarDJ8eyMS5"); ASSERT_EQ(Address(PrivateKey(privateKeyData).getPublicKey(TWPublicKeyTypeED25519)).string(), "B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); auto input = Solana::Proto::SigningInput(); @@ -330,7 +330,7 @@ TEST(TWAnySignerSolana, SignTokenTransfer1_3vZ67C) { } TEST(TWAnySignerSolana, SignTokenTransfer2_2pMvzp) { - auto privateKeyData = Base58::bitcoin.decode("9YtuoD4sH4h88CVM8DSnkfoAaLY7YeGC2TarDJ8eyMS5"); + auto privateKeyData = Base58::decode("9YtuoD4sH4h88CVM8DSnkfoAaLY7YeGC2TarDJ8eyMS5"); ASSERT_EQ(Address(PrivateKey(privateKeyData).getPublicKey(TWPublicKeyTypeED25519)).string(), "B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); auto input = Solana::Proto::SigningInput(); @@ -353,7 +353,7 @@ TEST(TWAnySignerSolana, SignTokenTransfer2_2pMvzp) { } TEST(TWAnySignerSolana, SignCreateAndTransferToken_449VaY) { - auto privateKeyData = Base58::bitcoin.decode("66ApBuKpo2uSzpjGBraHq7HP8UZMUJzp3um8FdEjkC9c"); + auto privateKeyData = Base58::decode("66ApBuKpo2uSzpjGBraHq7HP8UZMUJzp3um8FdEjkC9c"); ASSERT_EQ(Address(PrivateKey(privateKeyData).getPublicKey(TWPublicKeyTypeED25519)).string(), "Eg5jqooyG6ySaXKbQUu4Lpvu2SqUPZrNkM4zXs9iUDLJ"); auto input = Solana::Proto::SigningInput(); @@ -377,7 +377,7 @@ TEST(TWAnySignerSolana, SignCreateAndTransferToken_449VaY) { } TEST(TWAnySignerSolana, SignCreateAndTransferTokenWithMemoReferences) { - const auto privateKeyData = Base58::bitcoin.decode("66ApBuKpo2uSzpjGBraHq7HP8UZMUJzp3um8FdEjkC9c"); + const auto privateKeyData = Base58::decode("66ApBuKpo2uSzpjGBraHq7HP8UZMUJzp3um8FdEjkC9c"); EXPECT_EQ(Address(PrivateKey(privateKeyData).getPublicKey(TWPublicKeyTypeED25519)).string(), "Eg5jqooyG6ySaXKbQUu4Lpvu2SqUPZrNkM4zXs9iUDLJ"); auto input = Solana::Proto::SigningInput(); @@ -403,7 +403,7 @@ TEST(TWAnySignerSolana, SignCreateAndTransferTokenWithMemoReferences) { TEST(TWAnySignerSolana, SignJSON) { auto json = STRING(R"({"recentBlockhash":"11111111111111111111111111111111","transferTransaction":{"recipient":"EN2sCsJ1WDV8UFqsiTXHcUPUxQ4juE71eCknHYYMifkd","value":"42"}})"); - Data keyData = Base58::bitcoin.decode("A7psj2GW7ZMdY4E5hJq14KMeYg7HFjULSsWSrTXZLvYr"); + Data keyData = Base58::decode("A7psj2GW7ZMdY4E5hJq14KMeYg7HFjULSsWSrTXZLvYr"); EXPECT_EQ(hex(keyData), "8778cc93c6596387e751d2dc693bbd93e434bd233bc5b68a826c56131821cb63"); auto key = WRAPD(TWDataCreateWithBytes(keyData.data(), keyData.size())); diff --git a/tests/chains/Solana/TransactionTests.cpp b/tests/chains/Solana/TransactionTests.cpp index 0558f31605e..25bed86af71 100644 --- a/tests/chains/Solana/TransactionTests.cpp +++ b/tests/chains/Solana/TransactionTests.cpp @@ -18,7 +18,7 @@ namespace TW::Solana { TEST(SolanaTransaction, TransferMessageData) { auto from = Address("6eoo7i1khGhVm8tLBMAdq4ax2FxkKP4G7mCcfHyr3STN"); auto to = Address("56B334QvCDMSirsmtEJGfanZm8GqeQarrSjdAb2MbeNM"); - auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto transaction = Transaction(from, to, 42, recentBlockhash); auto expectedHex = @@ -32,7 +32,7 @@ TEST(SolanaTransaction, TransferMessageData) { TEST(SolanaTransaction, TransferSerializeTransaction) { auto from = Address("41a5jYky56M6EWDsFfLaZRxoRtgAJSRWxJnxaJNJELn5"); auto to = Address("4iSnyfDKaejniaPc2pBBckwQqV3mDS93go15NdxWJq2y"); - auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto transaction = Transaction(from, to, 42, recentBlockhash); Signature signature( "46SRiQGvtPb1iivDfnuC3dW1GzXkfQPTjdUyvFqF2sdPvFrsfx94fys2xpNKR6UiAj7RgKWdJG6mEfe85up6i1JT"); @@ -50,7 +50,7 @@ TEST(SolanaTransaction, TransferSerializeTransaction) { TEST(SolanaTransaction, TransferTransactionPayToSelf) { auto from = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); auto to = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); - auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto transaction = Transaction(from, to, 42, recentBlockhash); Signature signature( "3CFWDEK51noPJP4v2t8JZ3qj7kC7kLKyws9akfHMyuJnQ35EtzBptHqvaHfeswiLsvUSxzMVNoj4CuRxWtDD9zB1"); @@ -67,7 +67,7 @@ TEST(SolanaTransaction, TransferTransactionPayToSelf) { TEST(SolanaTransaction, TransferWithMemoAndReferenceTransaction) { const auto from = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); const auto to = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); - auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); const auto memo = "HelloSolana73"; std::vector
references = {Address("GaeTAQZyhVEocTC7iY8GztSyY5cBAJTkAUUA1kLFLMV")}; auto transaction = Transaction(from, to, 42, recentBlockhash, memo, references); @@ -83,7 +83,7 @@ TEST(SolanaTransaction, StakeSerializeTransactionV2) { auto signer = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); auto voteAddress = Address("4jpwTqt1qZoR7u6u639z2AngYFGN3nakvKhowcnRZDEC"); auto programId = Address("Stake11111111111111111111111111111111111111"); - auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto stakeAddress = StakeProgram::addressFromRecentBlockhash(signer, recentBlockhash, programId); auto message = LegacyMessage::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); auto transaction = Transaction(message); @@ -100,7 +100,7 @@ TEST(SolanaTransaction, StakeSerializeTransactionV1) { auto signer = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); auto voteAddress = Address("4jpwTqt1qZoR7u6u639z2AngYFGN3nakvKhowcnRZDEC"); auto programId = Address("Stake11111111111111111111111111111111111111"); - auto recentBlockhash = Base58::bitcoin.decode("11111111111111111111111111111111"); + auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto stakeAddress = StakeProgram::addressFromValidatorSeed(signer, voteAddress, programId); auto message = LegacyMessage::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); auto transaction = Transaction(message); @@ -117,7 +117,7 @@ TEST(SolanaTransaction, CreateTokenAccountTransaction) { auto signer = Address("B1iGmDJdvmxyUiYM8UEo2Uw2D58EmUrw4KyLYMmrhf8V"); auto token = Address("SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"); auto tokenAddress = Address("EDNd1ycsydWYwVmrYZvqYazFqwk1QjBgAUKFjBoz1jKP"); - auto recentBlockhash = Base58::bitcoin.decode("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); + auto recentBlockhash = Base58::decode("9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); auto message = LegacyMessage::createTokenCreateAccount(signer, signer, token, tokenAddress, recentBlockhash); EXPECT_EQ(message.header.numRequiredSignatures, 1); EXPECT_EQ(message.header.numReadOnlySignedAccounts, 0); @@ -130,7 +130,7 @@ TEST(SolanaTransaction, CreateTokenAccountTransaction) { EXPECT_EQ(message.accountKeys[4].string(), "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); EXPECT_EQ(message.accountKeys[5].string(), "SysvarRent111111111111111111111111111111111"); EXPECT_EQ(message.accountKeys[6].string(), "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); - EXPECT_EQ(Base58::bitcoin.encode(message.mRecentBlockHash), "9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); + EXPECT_EQ(Base58::encode(message.mRecentBlockHash), "9ipJh5xfyoyDaiq8trtrdqQeAhQbQkWy2eANizKvx75K"); ASSERT_EQ(message.instructions.size(), 1ul); EXPECT_EQ(message.instructions[0].programId.string(), "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); ASSERT_EQ(message.instructions[0].accounts.size(), 7ul); @@ -159,7 +159,7 @@ TEST(SolanaTransaction, TransferTokenTransaction_3vZ67C) { auto recipientTokenAddress = Address("3WUX9wASxyScbA7brDipioKfXS1XEYkQ4vo3Kej9bKei"); uint64_t amount = 4000; uint8_t decimals = 6; - auto recentBlockhash = Base58::bitcoin.decode("CNaHfvqePgGYMvtYi9RuUdVxDYttr1zs4TWrTXYabxZi"); + auto recentBlockhash = Base58::decode("CNaHfvqePgGYMvtYi9RuUdVxDYttr1zs4TWrTXYabxZi"); auto message = LegacyMessage::createTokenTransfer(signer, token, senderTokenAddress, recipientTokenAddress, amount, decimals, recentBlockhash); EXPECT_EQ(message.header.numRequiredSignatures, 1); EXPECT_EQ(message.header.numReadOnlySignedAccounts, 0); diff --git a/tests/chains/Tezos/SignerTests.cpp b/tests/chains/Tezos/SignerTests.cpp index eb024a36721..d11504003cc 100644 --- a/tests/chains/Tezos/SignerTests.cpp +++ b/tests/chains/Tezos/SignerTests.cpp @@ -78,7 +78,7 @@ TEST(TezosSigner, SignOperationList) { op_list.addOperation(delegateOperation); - auto decodedPrivateKey = Base58::bitcoin.decodeCheck("edsk4bMQMM6HYtMazF3m7mYhQ6KQ1WCEcBuRwh6DTtdnoqAvC3nPCc"); + auto decodedPrivateKey = Base58::decodeCheck("edsk4bMQMM6HYtMazF3m7mYhQ6KQ1WCEcBuRwh6DTtdnoqAvC3nPCc"); auto key = PrivateKey(Data(decodedPrivateKey.begin() + 4, decodedPrivateKey.end())); std::string expectedForgedBytesToSign = hex(op_list.forge(key)); diff --git a/tests/chains/Waves/TWAnySignerTests.cpp b/tests/chains/Waves/TWAnySignerTests.cpp index c814761a4f9..213fffd7771 100644 --- a/tests/chains/Waves/TWAnySignerTests.cpp +++ b/tests/chains/Waves/TWAnySignerTests.cpp @@ -15,7 +15,7 @@ namespace TW::Waves::tests { TEST(TWAnySignerWaves, Sign) { auto input = Proto::SigningInput(); - const auto privateKey = Base58::bitcoin.decode("83mqJpmgB5Mko1567sVAdqZxVKsT6jccXt3eFSi4G1zE"); + const auto privateKey = Base58::decode("83mqJpmgB5Mko1567sVAdqZxVKsT6jccXt3eFSi4G1zE"); input.set_timestamp(int64_t(1559146613)); input.set_private_key(privateKey.data(), privateKey.size()); From 4c40f20449c34835b74106a5fdc6e2fb3278e12b Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Wed, 22 Feb 2023 22:17:03 +0900 Subject: [PATCH 202/497] Update name for ThunderCore (#2946) --- .../blockchains/CoinAddressDerivationTests.kt | 2 +- .../core/app/blockchains/TestCoinType.kt | 2 +- docs/registry.md | 2 +- include/TrustWalletCore/TWCoinType.h | 2 +- registry.json | 2 +- swift/Tests/Blockchains/RippleTests.swift | 2 +- swift/Tests/CoinAddressDerivationTests.swift | 2 +- swift/Tests/CoinTypeTests.swift | 2 +- tests/chains/ThunderToken/TWCoinTypeTests.cpp | 20 +++++++++---------- tests/common/CoinAddressDerivationTests.cpp | 2 +- tests/interface/TWCoinTypeTests.cpp | 4 ++-- tests/interface/TWHRPTests.cpp | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index a5958c59d15..706f0745abe 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -53,7 +53,7 @@ class CoinAddressDerivationTests { POANETWORK -> assertEquals("0xe8a3e8bE17E172B6926130eAfB521e9D2849aca9", address) XRP -> assertEquals("rPwE3gChNKtZ1mhH3Ko8YFGqKmGRWLWXV3", address) TEZOS -> assertEquals("tz1acnY9VbMagps26Kj3RfoGRWD9nYG5qaRX", address) - THUNDERTOKEN -> assertEquals("0x4b92b3ED6d8b24575Bf5ce4C6a86ED261DA0C8d7", address) + THUNDERCORE -> assertEquals("0x4b92b3ED6d8b24575Bf5ce4C6a86ED261DA0C8d7", address) TOMOCHAIN -> assertEquals("0xC74b6D8897cBa9A4b659d43fEF73C9cA852cE424", address) TRON -> assertEquals("TQ5NMqJjhpQGK7YJbESKtNCo86PJ89ujio", address) VECHAIN -> assertEquals("0x1a553275dF34195eAf23942CB7328AcF9d48c160", address) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/TestCoinType.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/TestCoinType.kt index f8fc2f3a5bf..21349ebfa3c 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/TestCoinType.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/TestCoinType.kt @@ -21,7 +21,7 @@ class TestCoinType { assertEquals(CoinType.LITECOIN.value(), 2) assertEquals(CoinType.TRON.value(), 195) assertEquals(CoinType.ETHEREUM.value(), 60) - assertEquals(CoinType.THUNDERTOKEN.value(), 1001) + assertEquals(CoinType.THUNDERCORE.value(), 1001) assertEquals(CoinType.WANCHAIN.value(), 5718350) assertEquals(CoinType.CALLISTO.value(), 820) assertEquals(CoinType.ETHEREUMCLASSIC.value(), 61) diff --git a/docs/registry.md b/docs/registry.md index e1a73222d10..afe488db265 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -64,7 +64,7 @@ This list is generated from [./registry.json](../registry.json) | 931 | THORChain | RUNE | | | | 966 | Polygon | MATIC | | | | 996 | OKX Chain | OKT | | | -| 1001 | Thunder Token | TT | | | +| 1001 | ThunderCore | TT | | | | 1023 | Harmony | ONE | | | | 1024 | Ontology | ONT | | | | 1729 | Tezos | XTZ | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 0337ee4c6b0..879b64de7fd 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -68,7 +68,7 @@ enum TWCoinType { TWCoinTypeStellar = 148, TWCoinTypeTezos = 1729, TWCoinTypeTheta = 500, - TWCoinTypeThunderToken = 1001, + TWCoinTypeThunderCore = 1001, TWCoinTypeNEO = 888, TWCoinTypeTomoChain = 889, TWCoinTypeTron = 195, diff --git a/registry.json b/registry.json index 24f21c446ac..d592ba5c615 100644 --- a/registry.json +++ b/registry.json @@ -1574,7 +1574,7 @@ }, { "id": "thundertoken", - "name": "Thunder Token", + "name": "ThunderCore", "coinId": 1001, "symbol": "TT", "decimals": 18, diff --git a/swift/Tests/Blockchains/RippleTests.swift b/swift/Tests/Blockchains/RippleTests.swift index c2e96a65781..0582d8df579 100644 --- a/swift/Tests/Blockchains/RippleTests.swift +++ b/swift/Tests/Blockchains/RippleTests.swift @@ -55,7 +55,7 @@ class RippleTests: XCTestCase { $0.lastLedgerSequence = 32268269 $0.account = "rfxdLwsZnoespnTDDb1Xhvbc8EFNdztaoq" $0.privateKey = Data(hexString: "a5576c0f63da10e584568c8d134569ff44017b0a249eb70657127ae04f38cc77")! - $0.opPayment = operation + $0.opPayment = operation2 } let output2: RippleSigningOutput = AnySigner.sign(input: input2, coin: .xrp) XCTAssertEqual(output2.encoded, output.encoded) diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index d641e7150d6..3677452c53c 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -190,7 +190,7 @@ class CoinAddressDerivationTests: XCTestCase { case .theta: let expectedResult = "0x0d1fa20c218Fec2f2C55d52aB267940485fa5DA4" assertCoinDerivation(coin, expectedResult, derivedAddress, address) - case .thunderToken: + case .thunderCore: let expectedResult = "0x4b92b3ED6d8b24575Bf5ce4C6a86ED261DA0C8d7" assertCoinDerivation(coin, expectedResult, derivedAddress, address) case .tomoChain: diff --git a/swift/Tests/CoinTypeTests.swift b/swift/Tests/CoinTypeTests.swift index 353b85cf729..8884a0fe0eb 100644 --- a/swift/Tests/CoinTypeTests.swift +++ b/swift/Tests/CoinTypeTests.swift @@ -14,7 +14,7 @@ class CoinTypeTests: XCTestCase { XCTAssertEqual(CoinType.litecoin.rawValue, 2) XCTAssertEqual(CoinType.tron.rawValue, 195) XCTAssertEqual(CoinType.ethereum.rawValue, 60) - XCTAssertEqual(CoinType.thunderToken.rawValue, 1001) + XCTAssertEqual(CoinType.thunderCore.rawValue, 1001) XCTAssertEqual(CoinType.wanchain.rawValue, 5718350) XCTAssertEqual(CoinType.callisto.rawValue, 820) XCTAssertEqual(CoinType.ethereumClassic.rawValue, 61) diff --git a/tests/chains/ThunderToken/TWCoinTypeTests.cpp b/tests/chains/ThunderToken/TWCoinTypeTests.cpp index c001ea07218..1820f72d1ea 100644 --- a/tests/chains/ThunderToken/TWCoinTypeTests.cpp +++ b/tests/chains/ThunderToken/TWCoinTypeTests.cpp @@ -14,21 +14,21 @@ TEST(TWThunderTokenCoinType, TWCoinType) { - auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeThunderToken)); + auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeThunderCore)); auto txId = WRAPS(TWStringCreateWithUTF8Bytes("t123")); - auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeThunderToken, txId.get())); + auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeThunderCore, txId.get())); auto accId = WRAPS(TWStringCreateWithUTF8Bytes("a12")); - auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeThunderToken, accId.get())); - auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeThunderToken)); - auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeThunderToken)); + auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeThunderCore, accId.get())); + auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeThunderCore)); + auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeThunderCore)); - ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeThunderToken), 18); - ASSERT_EQ(TWBlockchainEthereum, TWCoinTypeBlockchain(TWCoinTypeThunderToken)); - ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeThunderToken)); - ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeThunderToken)); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeThunderCore), 18); + ASSERT_EQ(TWBlockchainEthereum, TWCoinTypeBlockchain(TWCoinTypeThunderCore)); + ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeThunderCore)); + ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeThunderCore)); assertStringsEqual(symbol, "TT"); assertStringsEqual(txUrl, "https://scan.thundercore.com/transactions/t123"); assertStringsEqual(accUrl, "https://scan.thundercore.com/address/a12"); assertStringsEqual(id, "thundertoken"); - assertStringsEqual(name, "Thunder Token"); + assertStringsEqual(name, "ThunderCore"); } diff --git a/tests/common/CoinAddressDerivationTests.cpp b/tests/common/CoinAddressDerivationTests.cpp index 3a506f452fd..b5bc432d8d4 100644 --- a/tests/common/CoinAddressDerivationTests.cpp +++ b/tests/common/CoinAddressDerivationTests.cpp @@ -65,7 +65,7 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeSmartChain: case TWCoinTypeSmartChainLegacy: case TWCoinTypeTheta: - case TWCoinTypeThunderToken: + case TWCoinTypeThunderCore: case TWCoinTypeTomoChain: case TWCoinTypeVeChain: case TWCoinTypeWanchain: diff --git a/tests/interface/TWCoinTypeTests.cpp b/tests/interface/TWCoinTypeTests.cpp index cb3ac95c1c9..d5c31585372 100644 --- a/tests/interface/TWCoinTypeTests.cpp +++ b/tests/interface/TWCoinTypeTests.cpp @@ -55,7 +55,7 @@ TEST(TWCoinType, TWPurpose) { ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeStellar)); ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeTezos)); ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeTheta)); - ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeThunderToken)); + ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeThunderCore)); ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeTomoChain)); ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeTron)); ASSERT_EQ(TWPurposeBIP44, TWCoinTypePurpose(TWCoinTypeVeChain)); @@ -127,7 +127,7 @@ TEST(TWCoinType, TWPublicKeyType) { ASSERT_EQ(TWPublicKeyTypeED25519, TWCoinTypePublicKeyType(TWCoinTypeStellar)); ASSERT_EQ(TWPublicKeyTypeED25519, TWCoinTypePublicKeyType(TWCoinTypeTezos)); ASSERT_EQ(TWPublicKeyTypeSECP256k1Extended, TWCoinTypePublicKeyType(TWCoinTypeTheta)); - ASSERT_EQ(TWPublicKeyTypeSECP256k1Extended, TWCoinTypePublicKeyType(TWCoinTypeThunderToken)); + ASSERT_EQ(TWPublicKeyTypeSECP256k1Extended, TWCoinTypePublicKeyType(TWCoinTypeThunderCore)); ASSERT_EQ(TWPublicKeyTypeSECP256k1Extended, TWCoinTypePublicKeyType(TWCoinTypeTomoChain)); ASSERT_EQ(TWPublicKeyTypeSECP256k1Extended, TWCoinTypePublicKeyType(TWCoinTypeTron)); ASSERT_EQ(TWPublicKeyTypeSECP256k1Extended, TWCoinTypePublicKeyType(TWCoinTypeVeChain)); diff --git a/tests/interface/TWHRPTests.cpp b/tests/interface/TWHRPTests.cpp index 7946c79c9e5..616938fca6a 100644 --- a/tests/interface/TWHRPTests.cpp +++ b/tests/interface/TWHRPTests.cpp @@ -112,7 +112,7 @@ TEST(TWHPR, HPRByCoinType) { ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeStellar)); ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeTezos)); ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeTheta)); - ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeThunderToken)); + ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeThunderCore)); ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeTomoChain)); ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeTron)); ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeVeChain)); From 714bfaca8b9fa800fa4e5bcc957fc8e5697fbd76 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Fri, 24 Feb 2023 23:22:03 +0100 Subject: [PATCH 203/497] [Tezos]: Blind signing support (#2956) * feat(tezos): blind signing support * refactoring encoded op name and type * Add manual step Co-authored-by: hewigovens <360470+hewigovens@users.noreply.github.com> --- src/Tezos/Signer.cpp | 16 ++++++++----- src/proto/Tezos.proto | 5 +++- swift/Tests/Blockchains/TezosTests.swift | 30 ++++++++++++++++++++++++ tests/chains/Tezos/TWAnySignerTests.cpp | 15 ++++++++++++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/Tezos/Signer.cpp b/src/Tezos/Signer.cpp index 248df7fd115..a8e8b4f0cfc 100644 --- a/src/Tezos/Signer.cpp +++ b/src/Tezos/Signer.cpp @@ -18,14 +18,18 @@ using namespace TW; namespace TW::Tezos { Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { - auto operationList = Tezos::OperationList(input.operation_list().branch()); - for (Proto::Operation operation : input.operation_list().operations()) { - operationList.addOperation(operation); - } - auto signer = Signer(); PrivateKey key = PrivateKey(Data(input.private_key().begin(), input.private_key().end())); - Data encoded = signer.signOperationList(key, operationList); + Data encoded; + if (input.encoded_operations().empty()) { + auto operationList = Tezos::OperationList(input.operation_list().branch()); + for (Proto::Operation operation : input.operation_list().operations()) { + operationList.addOperation(operation); + } + encoded = signer.signOperationList(key, operationList); + } else { + encoded = signer.signData(key, TW::data(input.encoded_operations())); + } auto output = Proto::SigningOutput(); output.set_encoded(encoded.data(), encoded.size()); diff --git a/src/proto/Tezos.proto b/src/proto/Tezos.proto index 7a56c4d2ab5..8732c2e1974 100644 --- a/src/proto/Tezos.proto +++ b/src/proto/Tezos.proto @@ -9,8 +9,11 @@ message SigningInput { // One or more operations OperationList operation_list = 1; + // Encoded operation bytes obtained with $RPC_URL/chains/main/blocks/head/helpers/forge/operations, operation_list will be ignored. + bytes encoded_operations = 2; + // The secret private key used for signing (32 bytes). - bytes private_key = 2; + bytes private_key = 3; } // Result containing the signed and encoded transaction. diff --git a/swift/Tests/Blockchains/TezosTests.swift b/swift/Tests/Blockchains/TezosTests.swift index 67a26a6c971..a6076a3beaa 100644 --- a/swift/Tests/Blockchains/TezosTests.swift +++ b/swift/Tests/Blockchains/TezosTests.swift @@ -161,4 +161,34 @@ class TezosTests: XCTestCase { XCTAssertEqual(output.encoded.hexString, expected) } + + public func testSignEncodedBytes() throws { + + let key = Data(hexString: "3caf5afaed067890cd850efd1555df351aa482badb4a541c29261f1acf261bf5")! + let bytes = Data(hexString: "64aa7792af40de41371a72b3342daa7bf3d2b5a84511e9074341fdd52148dd9d6c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542850f96c3a1079d780080ade2040155959998da7e79231e2be8ed8ff373ac1b1574b000ffff04737761700000009e070703060707020000000807070508030b000007070100000018323032332d30322d32345431333a34303a32322e3332385a07070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a7376617868484807070100000024747a315377326d4641557a626b6d37646b47434472626542734a54547456374a4438457907070080dac409070700bdf892a1a291e196aa0503066c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd0497c3a107f10f180001543aa1803f0bbe2099809ab067dfa8a4cbc1c26a00ffff07617070726f76650000002d070701000000244b5431516f64676b5974754e79664a726a72673854515a586d64544643616d373268533900006c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd0498c3a107f70f090001543aa1803f0bbe2099809ab067dfa8a4cbc1c26a00ffff07617070726f766500000036070701000000244b5431516f64676b5974754e79664a726a72673854515a586d64544643616d373268533900bdf892a1a291e196aa056c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542e71599c3a107fabb01400001b1f0d7affc39861f7f5c75f917f683d2e9f55e3100ffff04737761700000009a070700000707000007070001070700bdf892a1a291e196aa05070700a3f683c2a6d80a07070100000018323032332d30322d32345431333a34303a32322e3332385a070705090100000024747a31625443473754415535523736356f4458694c4d63385a4537546a7376617868484805090100000024747a315377326d4641557a626b6d37646b47434472626542734a54547456374a443845796c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd049ac3a107f50f1b000193d22b59c496c94504729be1c671ec1d1d7a9cf000ffff107570646174655f6f70657261746f72730000005f020000005a050507070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a73766178684848070701000000244b543147504a44546638475a73704363616e6147324b684d764775334e4a52717572617400006c00ad756cb46ba6f59efa8bd10ff544ba9d20d0954285109bc3a107a0820100000155959998da7e79231e2be8ed8ff373ac1b1574b000ffff0473776170000000a1070703060707020000000807070508030b000807070100000018323032332d30322d32345431333a34303a32322e3332385a07070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a7376617868484807070100000024747a315377326d4641557a626b6d37646b47434472626542734a54547456374a44384579070700a3f683c2a6d80a070700a4f096bfbe9df6f0e00603066c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd049cc3a107ed0f00000193d22b59c496c94504729be1c671ec1d1d7a9cf000ffff107570646174655f6f70657261746f72730000005f020000005a050807070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a73766178684848070701000000244b543147504a44546638475a73704363616e6147324b684d764775334e4a5271757261740000")! + let input = TezosSigningInput.with { + $0.privateKey = key + $0.encodedOperations = bytes + } + + let output: TezosSigningOutput = AnySigner.sign(input: input, coin: .tezos) + + let expected = "64aa7792af40de41371a72b3342daa7bf3d2b5a84511e9074341fdd52148dd9d6c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542850f96c3a1079d780080ade2040155959998da7e79231e2be8ed8ff373ac1b1574b000ffff04737761700000009e070703060707020000000807070508030b000007070100000018323032332d30322d32345431333a34303a32322e3332385a07070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a7376617868484807070100000024747a315377326d4641557a626b6d37646b47434472626542734a54547456374a4438457907070080dac409070700bdf892a1a291e196aa0503066c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd0497c3a107f10f180001543aa1803f0bbe2099809ab067dfa8a4cbc1c26a00ffff07617070726f76650000002d070701000000244b5431516f64676b5974754e79664a726a72673854515a586d64544643616d373268533900006c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd0498c3a107f70f090001543aa1803f0bbe2099809ab067dfa8a4cbc1c26a00ffff07617070726f766500000036070701000000244b5431516f64676b5974754e79664a726a72673854515a586d64544643616d373268533900bdf892a1a291e196aa056c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542e71599c3a107fabb01400001b1f0d7affc39861f7f5c75f917f683d2e9f55e3100ffff04737761700000009a070700000707000007070001070700bdf892a1a291e196aa05070700a3f683c2a6d80a07070100000018323032332d30322d32345431333a34303a32322e3332385a070705090100000024747a31625443473754415535523736356f4458694c4d63385a4537546a7376617868484805090100000024747a315377326d4641557a626b6d37646b47434472626542734a54547456374a443845796c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd049ac3a107f50f1b000193d22b59c496c94504729be1c671ec1d1d7a9cf000ffff107570646174655f6f70657261746f72730000005f020000005a050507070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a73766178684848070701000000244b543147504a44546638475a73704363616e6147324b684d764775334e4a52717572617400006c00ad756cb46ba6f59efa8bd10ff544ba9d20d0954285109bc3a107a0820100000155959998da7e79231e2be8ed8ff373ac1b1574b000ffff0473776170000000a1070703060707020000000807070508030b000807070100000018323032332d30322d32345431333a34303a32322e3332385a07070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a7376617868484807070100000024747a315377326d4641557a626b6d37646b47434472626542734a54547456374a44384579070700a3f683c2a6d80a070700a4f096bfbe9df6f0e00603066c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd049cc3a107ed0f00000193d22b59c496c94504729be1c671ec1d1d7a9cf000ffff107570646174655f6f70657261746f72730000005f020000005a050807070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a73766178684848070701000000244b543147504a44546638475a73704363616e6147324b684d764775334e4a5271757261740000e10077fc3068aaaf1c7779e1dc2c396b3b40d73ddda04648bf4b16ac2e747c89b461771488e80da3aa30fc18c90de99fd358bfb76683f3c3ec250b1ee09b6d07" + + XCTAssertEqual(output.encoded.hexString, expected) + + // How to do it without AnySigner + var watermark = Data([0x03]) + watermark.append(bytes) + + let hash = Hash.blake2b(data: watermark, size: 32) + let privateKey = PrivateKey(data: key)! + let signature = privateKey.sign(digest: hash, curve: .ed25519)! + + var signed = Data() + signed.append(bytes) + signed.append(signature) + + XCTAssertEqual(signed.hexString, expected) + } } diff --git a/tests/chains/Tezos/TWAnySignerTests.cpp b/tests/chains/Tezos/TWAnySignerTests.cpp index 89fac461677..92a080ba8d9 100644 --- a/tests/chains/Tezos/TWAnySignerTests.cpp +++ b/tests/chains/Tezos/TWAnySignerTests.cpp @@ -79,6 +79,21 @@ TEST(TWAnySignerTezos, SignFA2) { ASSERT_EQ(hex(output.encoded()), "1b1f9345dc9f77bd24b09034d1d2f9a28f02ac837f49db54b8d68341f53dc4b76c00fe2ce0cccc0214af521ad60c140c5589b4039247a08d0695d8b601a08d0600000136767f88850bae28bfb9f46b73c5e87ede4de12700ffff087472616e7366657200000066020000006107070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b5550020000003107070100000024747a31696f7a36326b447736476d35484170655174633150476d4e32775042744a4b555007070000000a552d24710d6c59383286700c6c2917b25a6c1fa8b587e593c289dd47704278796792f1e522c1623845ec991e292b0935445e6994850bd03f035a006c5ed93806"); } +TEST(TWAnySignerTezos, BlindSign) { + // Successfully broadcasted: https://ghostnet.tzkt.io/oobGgTkDNz9eqGVXiU4wShPZydkroCrmbKjoDcfSqhnM7GmcdEu/15229334 + auto key = parse_hex("3caf5afaed067890cd850efd1555df351aa482badb4a541c29261f1acf261bf5"); + auto bytes = parse_hex("64aa7792af40de41371a72b3342daa7bf3d2b5a84511e9074341fdd52148dd9d6c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542850f96c3a1079d780080ade2040155959998da7e79231e2be8ed8ff373ac1b1574b000ffff04737761700000009e070703060707020000000807070508030b000007070100000018323032332d30322d32345431333a34303a32322e3332385a07070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a7376617868484807070100000024747a315377326d4641557a626b6d37646b47434472626542734a54547456374a4438457907070080dac409070700bdf892a1a291e196aa0503066c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd0497c3a107f10f180001543aa1803f0bbe2099809ab067dfa8a4cbc1c26a00ffff07617070726f76650000002d070701000000244b5431516f64676b5974754e79664a726a72673854515a586d64544643616d373268533900006c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd0498c3a107f70f090001543aa1803f0bbe2099809ab067dfa8a4cbc1c26a00ffff07617070726f766500000036070701000000244b5431516f64676b5974754e79664a726a72673854515a586d64544643616d373268533900bdf892a1a291e196aa056c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542e71599c3a107fabb01400001b1f0d7affc39861f7f5c75f917f683d2e9f55e3100ffff04737761700000009a070700000707000007070001070700bdf892a1a291e196aa05070700a3f683c2a6d80a07070100000018323032332d30322d32345431333a34303a32322e3332385a070705090100000024747a31625443473754415535523736356f4458694c4d63385a4537546a7376617868484805090100000024747a315377326d4641557a626b6d37646b47434472626542734a54547456374a443845796c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd049ac3a107f50f1b000193d22b59c496c94504729be1c671ec1d1d7a9cf000ffff107570646174655f6f70657261746f72730000005f020000005a050507070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a73766178684848070701000000244b543147504a44546638475a73704363616e6147324b684d764775334e4a52717572617400006c00ad756cb46ba6f59efa8bd10ff544ba9d20d0954285109bc3a107a0820100000155959998da7e79231e2be8ed8ff373ac1b1574b000ffff0473776170000000a1070703060707020000000807070508030b000807070100000018323032332d30322d32345431333a34303a32322e3332385a07070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a7376617868484807070100000024747a315377326d4641557a626b6d37646b47434472626542734a54547456374a44384579070700a3f683c2a6d80a070700a4f096bfbe9df6f0e00603066c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd049cc3a107ed0f00000193d22b59c496c94504729be1c671ec1d1d7a9cf000ffff107570646174655f6f70657261746f72730000005f020000005a050807070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a73766178684848070701000000244b543147504a44546638475a73704363616e6147324b684d764775334e4a5271757261740000"); + + Proto::SigningInput input; + input.set_private_key(key.data(), key.size()); + input.set_encoded_operations(bytes.data(), bytes.size()); + + Proto::SigningOutput output; + ANY_SIGN(input, TWCoinTypeTezos); + + EXPECT_EQ(hex(output.encoded()), "64aa7792af40de41371a72b3342daa7bf3d2b5a84511e9074341fdd52148dd9d6c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542850f96c3a1079d780080ade2040155959998da7e79231e2be8ed8ff373ac1b1574b000ffff04737761700000009e070703060707020000000807070508030b000007070100000018323032332d30322d32345431333a34303a32322e3332385a07070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a7376617868484807070100000024747a315377326d4641557a626b6d37646b47434472626542734a54547456374a4438457907070080dac409070700bdf892a1a291e196aa0503066c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd0497c3a107f10f180001543aa1803f0bbe2099809ab067dfa8a4cbc1c26a00ffff07617070726f76650000002d070701000000244b5431516f64676b5974754e79664a726a72673854515a586d64544643616d373268533900006c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd0498c3a107f70f090001543aa1803f0bbe2099809ab067dfa8a4cbc1c26a00ffff07617070726f766500000036070701000000244b5431516f64676b5974754e79664a726a72673854515a586d64544643616d373268533900bdf892a1a291e196aa056c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542e71599c3a107fabb01400001b1f0d7affc39861f7f5c75f917f683d2e9f55e3100ffff04737761700000009a070700000707000007070001070700bdf892a1a291e196aa05070700a3f683c2a6d80a07070100000018323032332d30322d32345431333a34303a32322e3332385a070705090100000024747a31625443473754415535523736356f4458694c4d63385a4537546a7376617868484805090100000024747a315377326d4641557a626b6d37646b47434472626542734a54547456374a443845796c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd049ac3a107f50f1b000193d22b59c496c94504729be1c671ec1d1d7a9cf000ffff107570646174655f6f70657261746f72730000005f020000005a050507070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a73766178684848070701000000244b543147504a44546638475a73704363616e6147324b684d764775334e4a52717572617400006c00ad756cb46ba6f59efa8bd10ff544ba9d20d0954285109bc3a107a0820100000155959998da7e79231e2be8ed8ff373ac1b1574b000ffff0473776170000000a1070703060707020000000807070508030b000807070100000018323032332d30322d32345431333a34303a32322e3332385a07070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a7376617868484807070100000024747a315377326d4641557a626b6d37646b47434472626542734a54547456374a44384579070700a3f683c2a6d80a070700a4f096bfbe9df6f0e00603066c00ad756cb46ba6f59efa8bd10ff544ba9d20d09542cd049cc3a107ed0f00000193d22b59c496c94504729be1c671ec1d1d7a9cf000ffff107570646174655f6f70657261746f72730000005f020000005a050807070100000024747a31625443473754415535523736356f4458694c4d63385a4537546a73766178684848070701000000244b543147504a44546638475a73704363616e6147324b684d764775334e4a5271757261740000e10077fc3068aaaf1c7779e1dc2c396b3b40d73ddda04648bf4b16ac2e747c89b461771488e80da3aa30fc18c90de99fd358bfb76683f3c3ec250b1ee09b6d07"); +} + TEST(TWAnySignerTezos, Sign) { auto key = parse_hex("2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6f"); auto revealKey = parse_hex("311f002e899cdd9a52d96cb8be18ea2bbab867c505da2b44ce10906f511cff95"); From a077d3fb2312f495eae68c2bfddfd5b8762ed6e4 Mon Sep 17 00:00:00 2001 From: Maxim Pestryakov Date: Thu, 2 Mar 2023 13:39:00 +0800 Subject: [PATCH 204/497] [Kotlin] Fix JS types (#2965) --- codegen/bin/codegen | 1 + codegen/lib/code_generator.rb | 8 +- codegen/lib/kotlin_helper.rb | 81 +++++++++++++----- .../templates/kotlin/js_accessors_class.erb | 21 +++++ .../templates/kotlin/js_accessors_enum.erb | 34 ++++++++ .../templates/kotlin/js_accessors_struct.erb | 14 +++ codegen/lib/templates/kotlin/js_class.erb | 9 +- codegen/lib/templates/kotlin/js_enum.erb | 12 +-- codegen/lib/templates/kotlin_js_accessors.erb | 7 ++ include/TrustWalletCore/TWAccount.h | 15 ++-- jni/kotlin/AnySigner.c | 8 +- jni/kotlin/AnySigner.h | 8 +- .../convention.proto-generation.gradle.kts | 2 +- kotlin/gradle/libs.versions.toml | 6 +- kotlin/gradle/wrapper/gradle-wrapper.jar | Bin 61574 -> 61608 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- kotlin/gradlew | 4 +- kotlin/wallet-core-kotlin/build.gradle.kts | 2 - .../kotlin/com/trustwallet/core/AnySigner.kt | 15 +++- .../kotlin/com/trustwallet/core/AnySigner.kt | 23 ++--- .../kotlin/com/trustwallet/core/AnySigner.kt | 19 ++-- .../src/jsMain/kotlin/WalletCore.kt | 23 +++-- .../kotlin/com/trustwallet/core/AnySigner.kt | 23 +++-- .../kotlin/com/trustwallet/core/ByteArray.kt | 24 ++++++ .../com/trustwallet/core/JsAnySigner.kt | 20 +++++ .../core/{UInt8Array.kt => JsWalletCore.kt} | 14 ++- src/interface/TWAccount.cpp | 11 +-- 27 files changed, 288 insertions(+), 118 deletions(-) create mode 100644 codegen/lib/templates/kotlin/js_accessors_class.erb create mode 100644 codegen/lib/templates/kotlin/js_accessors_enum.erb create mode 100644 codegen/lib/templates/kotlin/js_accessors_struct.erb create mode 100644 codegen/lib/templates/kotlin_js_accessors.erb create mode 100644 kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/ByteArray.kt create mode 100644 kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsAnySigner.kt rename kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/{UInt8Array.kt => JsWalletCore.kt} (53%) diff --git a/codegen/bin/codegen b/codegen/bin/codegen index 10dfda8d9ff..5cd99179bb8 100755 --- a/codegen/bin/codegen +++ b/codegen/bin/codegen @@ -97,6 +97,7 @@ if options.kotlin generator.render_kotlin_android generator.render_kotlin_ios generator.render_kotlin_js + generator.render_kotlin_js_accessors generator.render_kotlin_jni_h generator.render_kotlin_jni_c end diff --git a/codegen/lib/code_generator.rb b/codegen/lib/code_generator.rb index d870418b222..0cac71f7870 100644 --- a/codegen/lib/code_generator.rb +++ b/codegen/lib/code_generator.rb @@ -49,7 +49,7 @@ def render_swift_enum_template(file:, header:, template:, output_subfolder:, ext end # Renders a template - def render_template(header:, template:, output_subfolder:, extension:) + def render_template(header:, template:, output_subfolder:, extension:, file_prefix: "") FileUtils.mkdir_p File.join(output_folder, output_subfolder) @entities.zip(files) do |entity, file| # Make current entity available to templates @@ -65,7 +65,7 @@ def render_template(header:, template:, output_subfolder:, extension:) code << "\n" unless header.nil? code << string - path = File.expand_path(File.join(output_folder, output_subfolder, "#{file}.#{extension}")) + path = File.expand_path(File.join(output_folder, output_subfolder, "#{file_prefix}#{file}.#{extension}")) File.write(path, code) end end @@ -121,6 +121,10 @@ def render_kotlin_js render_template(header: nil, template: 'kotlin_js.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/jsMain/generated/com/trustwallet/core', extension: 'kt') end + def render_kotlin_js_accessors + render_template(header: nil, template: 'kotlin_js_accessors.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/jsMain/generated/com/trustwallet/core', extension: 'kt', file_prefix: "Js") + end + def render_kotlin_jni_h render_template(header: 'copyright_header.erb', template: 'kotlin_jni_h.erb', output_subfolder: 'kotlin/wallet-core-kotlin/src/androidMain/cpp/generated', extension: 'h') end diff --git a/codegen/lib/kotlin_helper.rb b/codegen/lib/kotlin_helper.rb index 0d072ad3637..cc465817ea6 100644 --- a/codegen/lib/kotlin_helper.rb +++ b/codegen/lib/kotlin_helper.rb @@ -20,6 +20,14 @@ def self.parameters(params) names.join(', ') end + def self.js_parameters(params) + names = params.map do |param| + name = fix_name(param.name) + "#{name}: #{js_type(param.type)}" + end + names.join(', ') + end + def self.calling_parameters_ios(params) names = params.map do |param| name = fix_name(param.name) @@ -76,18 +84,24 @@ def self.convert_calling_type_ios(t) def self.convert_calling_type_js(t) case t.name when :data - "#{if t.is_nullable then '?' else '' end}.toUInt8Array()" + "#{if t.is_nullable then '?' else '' end}.asUInt8Array()" + when :uint8 + ".toByte()" + when :uint16 + ".toShort()" + when :uint32 + ".toInt()" when :uint64 - ".toUInt()" + ".toInt()" when :int64 ".toInt()" when :size - ".toUInt()" + ".toInt()" else if t.is_enum - "#{if t.is_nullable then '?' else '' end}._value" + "#{if t.is_nullable then '?' else '' end}.jsValue" elsif t.is_class - "#{if t.is_nullable then '?' else '' end}._value" + "#{if t.is_nullable then '?' else '' end}.jsValue" else '' end @@ -121,38 +135,38 @@ def self.convert_calling_return_type_js(t, expression = '') when :void expression when :data - "#{expression}.unsafeCast()#{nullable}.toByteArray()" + "#{expression}#{nullable}.asByteArray()" when :int - "#{expression}.unsafeCast().toInt()" + "#{expression}.toInt()" when :uint8 - "#{expression}.unsafeCast().toByte().toUByte()" + "#{expression}.toByte().toUByte()" when :uint16 - "#{expression}.unsafeCast().toShort().toUShort()" + "#{expression}.toShort().toUShort()" when :uint32 - "#{expression}.unsafeCast().toInt().toUInt()" + "#{expression}.toInt().toUInt()" when :uint64 - "#{expression}.unsafeCast().toLong().toULong()" + "#{expression}.toLong().toULong()" when :int8 - "#{expression}.unsafeCast().toByte()" + "#{expression}.toByte()" when :int16 - "#{expression}.unsafeCast().toShort()" + "#{expression}.toShort()" when :int32 - "#{expression}.unsafeCast().toInt()" + "#{expression}.toInt()" when :int64 - "#{expression}.unsafeCast().toLong()" + "#{expression}.toLong()" when :size - "#{expression}.unsafeCast().toLong().toULong()" + "#{expression}.toLong().toULong()" else if t.is_enum - "#{t.name}.fromValue(#{expression})#{if t.is_nullable then '' else '!!' end}" + "#{t.name}.fromValue(#{expression})" elsif t.is_class if t.is_nullable - "#{expression}.unsafeCast()?.let { #{t.name}(it, Unit) }" + "#{expression}?.let { #{t.name}(it) }" else - "#{t.name}(#{expression}, Unit)" + "#{t.name}(#{expression})" end else - "#{expression} as #{type(t)}" + expression end end end @@ -208,4 +222,31 @@ def self.return_type(t) end end + def self.js_type(t, is_constructor = false) + nullable = "#{if t.is_nullable && !is_constructor then '?' else '' end}" + case t.name + when :void + "" + when :bool + "Boolean#{nullable}" + when :int, :uint8, :int8, :uint16, :int16, :uint32, :int32, :uint64, :int64, :size + "Number#{nullable}" + when :data + "UInt8Array#{nullable}" + when :string + "String#{nullable}" + else + "Js#{t.name}#{nullable}" + end + end + + def self.js_return_type(t, is_constructor = false) + case t.name + when :void + "" + else + ": #{js_type(t, is_constructor)}" + end + end + end diff --git a/codegen/lib/templates/kotlin/js_accessors_class.erb b/codegen/lib/templates/kotlin/js_accessors_class.erb new file mode 100644 index 00000000000..9930f021865 --- /dev/null +++ b/codegen/lib/templates/kotlin/js_accessors_class.erb @@ -0,0 +1,21 @@ +<%= render('kotlin/package.erb') %> + +@JsModule("@trustwallet/wallet-core") +@JsName("<%= entity.name %>") +external class Js<%= entity.name %> { +<%- entity.properties.each do |property| -%> + fun <%= KotlinHelper.fix_name(WasmCppHelper.format_name(property.name)) %>()<%= KotlinHelper.js_return_type(property.return_type) %> +<%- end -%> +<% entity.methods.each do |method| -%> +<% next if method.name == "Delete" -%> + fun <%= KotlinHelper.fix_name(WasmCppHelper.format_name(method.name)) %>(<%= KotlinHelper.js_parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.js_return_type(method.return_type) %> +<% end -%> + companion object { +<% entity.static_methods.each do |method| -%> + fun <%= KotlinHelper.fix_name(WasmCppHelper.function_name(entity: entity, function: method)) %>(<%= KotlinHelper.js_parameters(method.parameters) %>)<%= KotlinHelper.js_return_type(method.return_type, method.name.start_with?("Create")) %> +<% end -%> + } +} + +inline val JsWalletCore.<%= entity.name %>: Js<%= entity.name %>.Companion + get() = asDynamic().<%= entity.name %>.unsafeCast.Companion>() diff --git a/codegen/lib/templates/kotlin/js_accessors_enum.erb b/codegen/lib/templates/kotlin/js_accessors_enum.erb new file mode 100644 index 00000000000..34e44a7b352 --- /dev/null +++ b/codegen/lib/templates/kotlin/js_accessors_enum.erb @@ -0,0 +1,34 @@ +<%= render('kotlin/package.erb') %> + +@JsModule("@trustwallet/wallet-core") +@JsName("<%= entity.name %>") +external class Js<%= entity.name %> { + val value: Number + companion object { +<% entity.cases.each do |c| -%> + val <%= KotlinHelper.fix_name(WasmCppHelper.format_name(c.name)) %>: Js<%= entity.name %> +<% end -%> + } +} + +inline val JsWalletCore.<%= entity.name %>: Js<%= entity.name %>.Companion + get() = asDynamic().<%= entity.name %>.unsafeCast.Companion>() + +<% if entity.properties.any? || entity.methods.any? -%> +@JsModule("@trustwallet/wallet-core") +@JsName("<%= entity.name %>Ext") +external object Js<%= entity.name %>Ext { +<%# Static method declarations -%> +<%- entity.properties.each do |property| -%> + fun <%= KotlinHelper.fix_name(WasmCppHelper.format_name(property.name)) %>(<%= KotlinHelper.js_parameters(property.parameters) %>)<%= KotlinHelper.js_return_type(property.return_type) %> +<%- end -%> +<% entity.methods.each do |method| -%> +<% next if method.name.start_with?('Create') -%> + fun <%= KotlinHelper.fix_name(WasmCppHelper.function_name(entity: entity, function: method)) %>(<%= KotlinHelper.js_parameters(method.parameters) %>)<%= KotlinHelper.js_return_type(method.return_type) %> +<% end -%> +} + +inline val JsWalletCore.<%= entity.name %>Ext: Js<%= entity.name %>Ext + get() = asDynamic().<%= entity.name %>Ext.unsafeCastExt>() + +<% end -%> \ No newline at end of file diff --git a/codegen/lib/templates/kotlin/js_accessors_struct.erb b/codegen/lib/templates/kotlin/js_accessors_struct.erb new file mode 100644 index 00000000000..671f438c880 --- /dev/null +++ b/codegen/lib/templates/kotlin/js_accessors_struct.erb @@ -0,0 +1,14 @@ +<%= render('kotlin/package.erb') %> + +@JsModule("@trustwallet/wallet-core") +@JsName("<%= entity.name %>") +external object Js<%= entity.name %> { +<%# Static method declarations -%> +<% entity.static_methods.each do |method| -%> +<% next if method.name.start_with?('Create') -%> + fun <%= KotlinHelper.fix_name(WasmCppHelper.function_name(entity: entity, function: method)) %>(<%= KotlinHelper.js_parameters(method.parameters) %>)<%= KotlinHelper.js_return_type(method.return_type) %> +<% end -%> +} + +inline val JsWalletCore.<%= entity.name %>: Js<%= entity.name %> + get() = asDynamic().<%= entity.name %>.unsafeCast>() diff --git a/codegen/lib/templates/kotlin/js_class.erb b/codegen/lib/templates/kotlin/js_class.erb index 187cbbd940b..5f6ad4809d7 100644 --- a/codegen/lib/templates/kotlin/js_class.erb +++ b/codegen/lib/templates/kotlin/js_class.erb @@ -4,26 +4,25 @@ <% methods = entity.methods.select { |method| not method.name.start_with?('Delete') } -%> <% static_methods = entity.static_methods.select { |method| not method.name.start_with?('Create') } -%> actual class <%= entity.name %> constructor( - val _value: dynamic, - unit: Unit, // Hack + val jsValue: Js<%= entity.name %>, ) { <%# Constructors -%> <%- constructors.each do |constructor| -%> actual constructor(<%= KotlinHelper.parameters(constructor.parameters) %>) : - this(WalletCore.Instance.<%= entity.name %>.<%= WasmCppHelper.function_name(entity: entity, function: constructor) %>(<%= KotlinHelper.calling_parameters_js(constructor.parameters) %>), Unit) + this(WalletCore.Instance.<%= entity.name %>.<%= WasmCppHelper.function_name(entity: entity, function: constructor) %>(<%= KotlinHelper.calling_parameters_js(constructor.parameters) %>)) <% end -%> <%# Property declarations -%> <% entity.properties.each do |property| -%> actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> - get() = <%= KotlinHelper.convert_calling_return_type_js(property.return_type, "_value.#{WasmCppHelper.function_name(entity: entity, function: property)}()") %> + get() = <%= KotlinHelper.convert_calling_return_type_js(property.return_type, "jsValue.#{WasmCppHelper.function_name(entity: entity, function: property)}()") %> <% end -%> <%# Method declarations -%> <% methods.each do |method| -%> actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> = - <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "_value.#{WasmCppHelper.function_name(entity: entity, function: method)}(#{KotlinHelper.calling_parameters_js(method.parameters.drop(1))})") %> + <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "jsValue.#{WasmCppHelper.function_name(entity: entity, function: method)}(#{KotlinHelper.calling_parameters_js(method.parameters.drop(1))})") %> <% end -%> <% if entity.static_properties.any? || static_methods.any? -%> diff --git a/codegen/lib/templates/kotlin/js_enum.erb b/codegen/lib/templates/kotlin/js_enum.erb index 4c5895d77ac..4ce79c684fc 100644 --- a/codegen/lib/templates/kotlin/js_enum.erb +++ b/codegen/lib/templates/kotlin/js_enum.erb @@ -1,7 +1,7 @@ <%= render('kotlin/package.erb') %> actual enum class <%= entity.name %>( - internal val _value: dynamic, + val jsValue: Js<%= entity.name %>, ) { <%# Cases -%> <% entity.cases.each_with_index do |c, i| -%> @@ -12,21 +12,21 @@ actual enum class <%= entity.name %>( <%- entity.properties.each do |property| -%> actual val <%= KotlinHelper.format_name(property.name) %><%= KotlinHelper.return_type(property.return_type) %> - get() = <%= KotlinHelper.convert_calling_return_type_js(property.return_type, "WalletCore.Instance.#{entity.name}Ext.#{WasmCppHelper.function_name(entity: entity, function: property)}(_value)") %> + get() = <%= KotlinHelper.convert_calling_return_type_js(property.return_type, "WalletCore.Instance.#{entity.name}Ext.#{WasmCppHelper.function_name(entity: entity, function: property)}(jsValue)") %> <%- end -%> <%# Method declarations -%> <%- entity.methods.each do |method| -%> <%- next if method.name.start_with?('Delete') -%> actual fun <%= KotlinHelper.format_name(method.name) %>(<%= KotlinHelper.parameters(method.parameters.drop(1)) %>)<%= KotlinHelper.return_type(method.return_type) %> = - <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "WalletCore.Instance.#{entity.name}Ext.#{WasmCppHelper.function_name(entity: entity, function: method)}(_value#{', ' if not method.parameters.one?}#{KotlinHelper.calling_parameters_js(method.parameters.drop(1))})") %> + <%= KotlinHelper.convert_calling_return_type_js(method.return_type, "WalletCore.Instance.#{entity.name}Ext.#{WasmCppHelper.function_name(entity: entity, function: method)}(jsValue#{', ' if not method.parameters.one?}#{KotlinHelper.calling_parameters_js(method.parameters.drop(1))})") %> <%- end -%> <%# Value -%> <% if entity.cases.any? { |e| !e.value.nil? } -%> - internal companion object { - internal fun fromValue(value: dynamic): <%= entity.name %>? = - values().firstOrNull { it._value == value } + companion object { + fun fromValue(jsValue: Js<%= entity.name %>): <%= entity.name %> = + values().first { it.jsValue.value == jsValue.value } } <% end -%> } diff --git a/codegen/lib/templates/kotlin_js_accessors.erb b/codegen/lib/templates/kotlin_js_accessors.erb new file mode 100644 index 00000000000..63dda74b3b2 --- /dev/null +++ b/codegen/lib/templates/kotlin_js_accessors.erb @@ -0,0 +1,7 @@ +<%- if entity.is_a?(EnumDecl) -%> +<%= render('kotlin/js_accessors_enum.erb') -%> +<%- elsif entity.is_struct -%> +<%= render('kotlin/js_accessors_struct.erb') -%> +<%- else -%> +<%= render('kotlin/js_accessors_class.erb') -%> +<%- end -%> diff --git a/include/TrustWalletCore/TWAccount.h b/include/TrustWalletCore/TWAccount.h index c5d6f5e33ce..20a11cf7d6f 100644 --- a/include/TrustWalletCore/TWAccount.h +++ b/include/TrustWalletCore/TWAccount.h @@ -28,7 +28,8 @@ struct TWAccount; /// \param extendedPublicKey Base58 encoded extended public key. /// \return A new Account. TW_EXPORT_STATIC_METHOD -struct TWAccount* _Nonnull TWAccountCreate(TWString* _Nonnull address, enum TWCoinType coin, +struct TWAccount* _Nonnull TWAccountCreate(TWString* _Nonnull address, + enum TWCoinType coin, enum TWDerivation derivation, TWString* _Nonnull derivationPath, TWString* _Nonnull publicKey, @@ -45,6 +46,12 @@ void TWAccountDelete(struct TWAccount *_Nonnull account); TW_EXPORT_PROPERTY TWString *_Nonnull TWAccountAddress(struct TWAccount *_Nonnull account); +/// Return CoinType enum of an account. +/// +/// \param account Account to get the coin type of. +TW_EXPORT_PROPERTY +enum TWCoinType TWAccountCoin(struct TWAccount* _Nonnull account); + /// Returns the derivation enum of an account. /// /// \param account Account to get the derivation enum of. @@ -69,10 +76,4 @@ TWString* _Nonnull TWAccountPublicKey(struct TWAccount* _Nonnull account); TW_EXPORT_PROPERTY TWString* _Nonnull TWAccountExtendedPublicKey(struct TWAccount* _Nonnull account); -/// Return CoinType enum of an account. -/// -/// \param account Account to get the coin type of. -TW_EXPORT_PROPERTY -enum TWCoinType TWAccountCoin(struct TWAccount* _Nonnull account); - TW_EXTERN_C_END diff --git a/jni/kotlin/AnySigner.c b/jni/kotlin/AnySigner.c index 8e0c9f389f8..57c215eb34c 100644 --- a/jni/kotlin/AnySigner.c +++ b/jni/kotlin/AnySigner.c @@ -11,7 +11,7 @@ #include "AnySigner.h" #include "TWJNI.h" -jbyteArray JNICALL Java_com_trustwallet_core_AnySignerKt_signImpl(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin) { +jbyteArray JNICALL Java_com_trustwallet_core_AnySigner_sign(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin) { jclass coinClass = (*env)->GetObjectClass(env, coin); jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I"); uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID); @@ -23,14 +23,14 @@ jbyteArray JNICALL Java_com_trustwallet_core_AnySignerKt_signImpl(JNIEnv *env, j return resultData; } -jboolean JNICALL Java_com_trustwallet_core_AnySignerKt_supportsJsonImpl(JNIEnv *env, jclass thisClass, jobject coin) { +jboolean JNICALL Java_com_trustwallet_core_AnySigner_supportsJson(JNIEnv *env, jclass thisClass, jobject coin) { jclass coinClass = (*env)->GetObjectClass(env, coin); jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I"); uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID); return TWAnySignerSupportsJSON(coinValue); } -jstring JNICALL Java_com_trustwallet_core_AnySignerKt_signJsonImpl(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jobject coin) { +jstring JNICALL Java_com_trustwallet_core_AnySigner_signJson(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jobject coin) { jclass coinClass = (*env)->GetObjectClass(env, coin); jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I"); uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID); @@ -43,7 +43,7 @@ jstring JNICALL Java_com_trustwallet_core_AnySignerKt_signJsonImpl(JNIEnv *env, return TWStringJString(result, env); } -jbyteArray JNICALL Java_com_trustwallet_core_AnySignerKt_planImpl(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin) { +jbyteArray JNICALL Java_com_trustwallet_core_AnySigner_plan(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin) { jclass coinClass = (*env)->GetObjectClass(env, coin); jmethodID coinValueMethodID = (*env)->GetMethodID(env, coinClass, "value", "()I"); uint32_t coinValue = (*env)->CallIntMethod(env, coin, coinValueMethodID); diff --git a/jni/kotlin/AnySigner.h b/jni/kotlin/AnySigner.h index 18f98104f62..05742d57122 100644 --- a/jni/kotlin/AnySigner.h +++ b/jni/kotlin/AnySigner.h @@ -13,16 +13,16 @@ TW_EXTERN_C_BEGIN JNIEXPORT -jbyteArray JNICALL Java_com_trustwallet_core_AnySignerKt_signImpl(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin); +jbyteArray JNICALL Java_com_trustwallet_core_AnySigner_sign(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin); JNIEXPORT -jboolean JNICALL Java_com_trustwallet_core_AnySignerKt_supportsJsonImpl(JNIEnv *env, jclass thisClass, jobject coin); +jboolean JNICALL Java_com_trustwallet_core_AnySigner_supportsJson(JNIEnv *env, jclass thisClass, jobject coin); JNIEXPORT -jstring JNICALL Java_com_trustwallet_core_AnySignerKt_signJsonImpl(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jobject coin); +jstring JNICALL Java_com_trustwallet_core_AnySigner_signJson(JNIEnv *env, jclass thisClass, jstring json, jbyteArray key, jobject coin); JNIEXPORT -jbyteArray JNICALL Java_com_trustwallet_core_AnySignerKt_planImpl(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin); +jbyteArray JNICALL Java_com_trustwallet_core_AnySigner_plan(JNIEnv *env, jclass thisClass, jbyteArray input, jobject coin); TW_EXTERN_C_END diff --git a/kotlin/build-logic/src/main/kotlin/convention.proto-generation.gradle.kts b/kotlin/build-logic/src/main/kotlin/convention.proto-generation.gradle.kts index 7775d61e4ed..112de933e3a 100644 --- a/kotlin/build-logic/src/main/kotlin/convention.proto-generation.gradle.kts +++ b/kotlin/build-logic/src/main/kotlin/convention.proto-generation.gradle.kts @@ -18,7 +18,7 @@ val copyProtoTask = task("copyProtos") { .listFiles { file -> file.extension == "proto" } .orEmpty() .forEach { file -> - val packageName = file.nameWithoutExtension.toLowerCase() + val packageName = file.nameWithoutExtension.lowercase() file .readText() .replaceFirst( diff --git a/kotlin/gradle/libs.versions.toml b/kotlin/gradle/libs.versions.toml index 012e8c6ba34..701f94e473b 100644 --- a/kotlin/gradle/libs.versions.toml +++ b/kotlin/gradle/libs.versions.toml @@ -1,13 +1,13 @@ [versions] -android-sdk-tools = "33.0.1" +android-sdk-tools = "33.0.2" android-sdk-min = "24" android-sdk-compile = "33" android-cmake = "3.22.1" android-ndk = "25.2.9519653" kotlin = "1.8.10" -agp = "7.4.1" -wire = "4.4.3" +agp = "7.4.2" +wire = "4.5.1" [libraries] wire-runtime = { module = "com.squareup.wire:wire-runtime", version.ref = "wire" } diff --git a/kotlin/gradle/wrapper/gradle-wrapper.jar b/kotlin/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa754578e88a3dae77fce6e3dea56edbf..ccebba7710deaf9f98673a68957ea02138b60d0a 100644 GIT binary patch delta 5094 zcmZu#c|6qH|DG9RA4`noBZNWrC2N)tSqjO%%aX0^O4dPAB*iC6_9R<`apl^#h-_oY z)(k_0v8Fxp{fyi9-uwN%e)GpU&v~BrS>~KG^PF=MNmQjIDr&QHR7f-kM{%U_u*1=5 zGC}ae5(^Rrg9QY8$x^}oiJ0d2O9YW{J~$dD1ovlvh&0B4L)!4S=z;Hac>K{#9q9cKq;>>BtKo1!+gw`yqE zSK8x^jC|B!qmSW#uyb@T^CkB9qRd{N3V-rEi}AEgoU_J27lw_0X`}c0&m9JhxM;RK z54_gdZ(u?R5`B3}NeVal2NTHqlktM`2eTF28%6BZCWW$-shf0l-BOVSm)hU58MTPy zDcY-5777j;ccU!Yba8wH=X6OdPJ8O5Kp^3gUNo>!b=xb6T2F&LiC2eBJj8KuLPW!4 zw3V^NnAKZm^D?tmliCvzi>UtoDH%V#%SM0d*NS+m%4}qO<)M1E{OpQ(v&ZNc`vdi| zEGlVi$Dgxy1p6+k0qGLQt(JwxZxLCZ4>wJ=sb0v%Ki?*+!ic_2exumn{%Co|| z-axdK#RUC;P|vqbe?L`K!j;sUo=uuR_#ZkRvBf%Txo6{OL&I(?dz?47Z(DcX3KTw> zGY%A=kX;fBkq$F^sX|-)1Qkg##+n-Ci{qJVPj@P?l_1Y`nD^v>fZ3HMX%(4p-TlD(>yWwJij!6Jw}l7h>CIm@Ou5B@$Wy`Ky*814%Mdi1GfG1zDG9NogaoVHHr4gannv4?w6g&10!j=lKM zFW;@=Z0}vAPAxA=R4)|`J??*$|Fh`5=ks*V7TapX`+=4n*{aXxRhh-EGX_Xrzjb4r zn0vO7Cc~wtyeM_8{**~9y7>+}1JV8Buhg%*hy|PUc#!vw#W(HFTL|BpM)U0>JxG6S zLnqn1!0++RyyJ>5VU<4mDv8>Q#{EtgS3mj7Hx}Zkr0tz1}h8Kn6q`MiwC z{Y#;D!-ndlImST(C@(*i5f0U(jD29G7g#nkiPX zki6M$QYX_fNH=E4_eg9*FFZ3wF9YAKC}CP89Kl(GNS(Ag994)0$OL4-fj_1EdR}ARB#-vP_$bWF`Qk58+ z4Jq*-YkcmCuo9U%oxGeYe7Be=?n}pX+x>ob(8oPLDUPiIryT8v*N4@0{s_VYALi;lzj19ivLJKaXt7~UfU|mu9zjbhPnIhG2`uI34urWWA9IO{ z_1zJ)lwSs{qt3*UnD}3qB^kcRZ?``>IDn>qp8L96bRaZH)Zl`!neewt(wjSk1i#zf zb8_{x_{WRBm9+0CF4+nE)NRe6K8d|wOWN)&-3jCDiK5mj>77=s+TonlH5j`nb@rB5 z5NX?Z1dk`E#$BF{`(D>zISrMo4&}^wmUIyYL-$PWmEEfEn-U0tx_vy$H6|+ zi{ytv2@JXBsot|%I5s74>W1K{-cvj0BYdNiRJz*&jrV9>ZXYZhEMULcM=fCmxkN&l zEoi=)b)Vazc5TQC&Q$oEZETy@!`Gnj`qoXl7mcwdY@3a-!SpS2Mau|uK#++@>H8QC zr2ld8;<_8We%@E?S=E?=e9c$BL^9X?bj*4W;<+B&OOe+3{<`6~*fC(=`TO>o^A(Y! zA`Qc1ky?*6xjVfR?ugE~oY`Gtzhw^{Z@E6vZ`mMRAp>Odpa!m zzWmtjT|Lj^qiZMfj%%un-o$Eu>*v12qF{$kCKai^?DF=$^tfyV%m9;W@pm-BZn_6b z{jsXY3!U`%9hzk6n7YyHY%48NhjI6jjuUn?Xfxe0`ARD_Q+T_QBZ{ zUK@!63_Wr`%9q_rh`N4=J=m;v>T{Y=ZLKN^m?(KZQ2J%|3`hV0iogMHJ} zY6&-nXirq$Yhh*CHY&Qf*b@@>LPTMf z(cMorwW?M11RN{H#~ApKT)F!;R#fBHahZGhmy>Sox`rk>>q&Y)RG$-QwH$_TWk^hS zTq2TC+D-cB21|$g4D=@T`-ATtJ?C=aXS4Q}^`~XjiIRszCB^cvW0OHe5;e~9D%D10 zl4yP4O=s-~HbL7*4>#W52eiG7*^Hi)?@-#*7C^X5@kGwK+paI>_a2qxtW zU=xV7>QQROWQqVfPcJ$4GSx`Y23Z&qnS?N;%mjHL*EVg3pBT{V7bQUI60jtBTS?i~ zycZ4xqJ<*3FSC6_^*6f)N|sgB5Bep(^%)$=0cczl>j&n~KR!7WC|3;Zoh_^GuOzRP zo2Hxf50w9?_4Qe368fZ0=J|fR*jO_EwFB1I^g~i)roB|KWKf49-)!N%Ggb%w=kB8)(+_%kE~G!(73aF=yCmM3Cfb9lV$G!b zoDIxqY{dH>`SILGHEJwq%rwh46_i`wkZS-NY95qdNE)O*y^+k#JlTEij8NT(Y_J!W zFd+YFoZB|auOz~A@A{V*c)o7E(a=wHvb@8g5PnVJ&7D+Fp8ABV z5`&LD-<$jPy{-y*V^SqM)9!#_Pj2-x{m$z+9Z*o|JTBGgXYYVM;g|VbitDUfnVn$o zO)6?CZcDklDoODzj+ti@i#WcqPoZ!|IPB98LW!$-p+a4xBVM@%GEGZKmNjQMhh)zv z7D){Gpe-Dv=~>c9f|1vANF&boD=Nb1Dv>4~eD636Lldh?#zD5{6JlcR_b*C_Enw&~ z5l2(w(`{+01xb1FCRfD2ap$u(h1U1B6e&8tQrnC}Cy0GR=i^Uue26Rc6Dx}!4#K*0 zaxt`a+px7-Z!^(U1WN2#kdN#OeR|2z+C@b@w+L67VEi&ZpAdg+8`HJT=wIMJqibhT ztb3PFzsq&7jzQuod3xp7uL?h-7rYao&0MiT_Bux;U*N#ebGv92o(jM2?`1!N2W_M* zeo9$%hEtIy;=`8z1c|kL&ZPn0y`N)i$Y1R9>K!el{moiy)014448YC#9=K zwO3weN|8!`5bU_#f(+ZrVd*9`7Uw?!q?yo&7sk&DJ;#-^tcCtqt5*A(V;&LdHq7Hg zI6sC@!ly9p$^@v&XDsgIuv;9#w^!C1n5+10-tEw~ZdO1kqMDYyDl!5__o}f3hYe2M zCeO)~m&&=JZn%cVH3HzPlcE`9^@``2u+!Y}Remn)DLMHc-h5A9ATgs;7F7=u2=vBlDRbjeYvyNby=TvpI{5nb2@J_YTEEEj4q<@zaGSC_i&xxD!6)d zG{1??({Ma<=Wd4JL%bnEXoBOU_0bbNy3p%mFrMW>#c zzPEvryBevZVUvT^2P&Zobk#9j>vSIW_t?AHy>(^x-Bx~(mvNYb_%$ZFg(s5~oka+Kp(GU68I$h(Vq|fZ zC_u1FM|S)=ldt#5q>&p4r%%p)*7|Rf0}B#-FwHDTo*|P6HB_rz%R;{==hpl#xTt@VLdSrrf~g^ z`IA8ZV1b`UazYpnkn28h&U)$(gdZ*f{n`&kH%Oy54&Z;ebjlh4x?JmnjFAALu}EG} zfGmQ$5vEMJMH`a=+*src#dWK&N1^LFxK9Sa#q_rja$JWra09we<2oL9Q9Sx)?kZFW z$jhOFGE~VcihYlkaZv8?uA7v$*}?2h6i%Qmgc4n~3E(O_`YCRGy~}`NFaj@(?Wz;GS_?T+RqU{S)eD1j$1Gr;C^m z7zDK=xaJ^6``=#Y-2ssNfdRqh0ntJrutGV5Nv&WI%3k1wmD5n+0aRe{0k^!>LFReN zx1g*E>nbyx03KU~UT6->+rG%(owLF=beJxK&a0F;ie1GZ^eKg-VEZb&=s&ajKS#6w zjvC6J#?b|U_(%@uq$c#Q@V_me0S1%)pKz9--{EKwyM}_gOj*Og-NEWLDF_oFtPjG; zXCZ7%#=s}RKr&_5RFN@=H(015AGl4XRN9Bc51`;WWt%vzQvzexDI2BZ@xP~^2$I&7 zA(ndsgLsmA*su8p-~IS q+ZJUZM}`4#Zi@l2F-#HCw*??ha2ta#9s8?H3%YId(*zJG6aF78h1yF1 delta 5107 zcmY*d1zc0@|J{HQlai7V5+f#EN-H%&UP4MFm6QgFfuJK4DG4u#ARsbQL4i>MB1q|w zmWd#pqd~BR-yN@ieE-|$^W1aKIZtf&-p_fyw{(Uwc7_sWYDh^12cY!qXvcPQ!qF;q@b0nYU7 zP&ht}K7j%}P%%|ffm;4F0^i3P0R`a!2wm89L5P3Kfu;tTZJre<{N5}AzsH+E3DS`Q zJLIl`LRMf`JOTBLf(;IV(9(h{(}dXK!cPoSLm(o@fz8vRz}6fOw%3}3VYOsCczLF` za2RTsCWa2sS-uw(6|HLJg)Xf@S8#|+(Z5Y)ER+v+8;btfB3&9sWH6<=U}0)o-jIts zsi?Nko;No&JyZI%@1G&zsG5kKo^Zd7rk_9VIUao9;fC~nv(T0F&Af0&Rp`?x94EIS zUBPyBe5R5#okNiB1Xe--q4|hPyGzhJ?Lurt#Ci09BQ+}rlHpBhm;EmfLw{EbCz)sg zgseAE#f$met1jo;`Z6ihk?O1be3aa$IGV69{nzagziA!M*~E5lMc(Sp+NGm2IUjmn zql((DU9QP~Tn1pt6L`}|$Na-v(P+Zg&?6bAN@2u%KiB*Gmf}Z)R zMENRJgjKMqVbMpzPO{`!J~2Jyu7&xXnTDW?V?IJgy+-35q1)-J8T**?@_-2H`%X+6f5 zIRv`uLp&*?g7L~6+3O*saXT~gWsmhF*FNKw4X$29ePKi02G*)ysenhHv{u9-y?_do ztT(Cu04pk>51n}zu~=wgToY5Cx|MTlNw}GR>+`|6CAhQn=bh@S<7N)`w};;KTywDU z=QWO@RBj$WKOXSgCWg{BD`xl&DS!G}`Mm3$)=%3jzO_C+s+mfTFH5JL>}*(JKs@MqX|o2b#ZBX5P;p7;c)$F1y4HwvJ?KA938$rd)gn_U^CcUtmdaBW57 zlPph>Fz&L`cSScFjcj+7Jif3vxb20Ag~FPstm?9#OrD$e?Y~#1osDB0CFZ9Mu&%iE zSj~wZpFqu6!k%BT)}$F@Z%(d-Pqy07`N8ch2F7z^=S-!r-@j{#&{SM@a8O$P#SySx zZLD_z=I300OCA1YmKV0^lo@>^)THfZvW}s<$^w^#^Ce=kO5ymAnk>H7pK!+NJ-+F7 z1Bb6Y=r)0nZ+hRXUyD+BKAyecZxb+$JTHK5k(nWv*5%2a+u*GDt|rpReYQ}vft zXrIt#!kGO85o^~|9Oc-M5A!S@9Q)O$$&g8u>1=ew?T35h8B{-Z_S78oe=E(-YZhBPe@Y1sUt63A-Cdv>D1nIT~=Rub6$?8g>meFb7Ic@w^%@RN2z72oPZ#Ta%b(P1|&6I z61iO<8hT*)p19Bgd0JgXP{^c{P2~K@^DIXv=dF(u|DFfqD^dMIl8-x)xKIpJRZru@ zDxicyYJG}mh}=1Dfg%B$#H`CiAxPTj^;f4KRMZHUz-_x6)lEq!^mu%72*PI=t$6{Uql#dqm4 zClgaN63!&?v*enz4k1sbaM+yCqUf+i9rw$(YrY%ir1+%cWRB<;r}$8si!6QcNAk~J zk3?dejBaC`>=T<=y=>QVt*4kL>SwYwn$(4ES793qaH)>n(axyV3R5jdXDh#e-N0K- zuUgk|N^|3*D1!Wlz-!M*b}Zc5=;K6I+>1N$&Q%)&8LWUiTYi&aQIj(luA< zN5R<8Y8L#*i0xBio$jWcaiZ4S2w3#R@CGemesy~akKP)2GojQF6!$}!_RdUJPBevX zG#~uz%Yirb0@1wgQ;ayb=qD}6{=QXxjuZQ@@kxbN!QWhtEvuhS2yAZe8fZy6*4Inr zdSyR9Dec4HrE|I=z-U;IlH;_h#7e^Hq}gaJ<-z^}{*s!m^66wu2=(*EM0UaV*&u1q zJrq!K23TO8a(ecSQFdD$y+`xu)Xk36Z*;1i{hS=H2E<8<5yHuHG~22-S+Jq|3HMAw z%qBz3auT=M!=5F|Wqke|I^E8pmJ-}>_DwX5w%d3MSdC>xW%$ocm8w8HRdZ|^#cEt1 zM*I7S6sLQq;;Mecet(Q()+?s+&MeVLOvx}(MkvytkvLHl7h*N0AT1#AqC&(he(^%przH`KqA$z_dAvJJb409@F)fYwD$JW_{_Oie8!@VdJE zU>D$@B?LawAf5$;`AZ1E!krn=aAC%4+YQrzL!59yl1;|T2)u=RBYA8lk0Ek&gS!Rb zt0&hVuyhSa0}rpZGjTA>Gz}>Uv*4)F zf7S%D2nfA7x?gPEXZWk8DZimQs#xi0?So_k`2zb!UVQEAcbvjPLK9v>J~!awnxGpq zEh$EPOc4q&jywmglnC&D)1-P0DH!@)x;uJwMHdhPh>ZLWDw+p1pf52{X2dk{_|UOmakJa4MHu?CY`6Hhv!!d7=aNwiB5z zb*Wlq1zf^3iDlPf)b_SzI*{JCx2jN;*s~ra8NeB!PghqP!0po-ZL?0Jk;2~*~sCQ<%wU`mRImd)~!23RS?XJu|{u( ztFPy3*F=ZhJmBugTv48WX)4U*pNmm~4oD4}$*-92&<)n=R)5lT z-VpbEDk>(C1hoo#-H_u0`#%L6L$ zln(}h2*Cl(5(JtVM{YZ26@Fwmp;?Qt}9$_F%`?+-JHbC;bPZj8PLq9 zWo-KFw!i&r8WuA-!3F_m9!24Z(RhalAUR~_H#Ln=$%b5GY z)oB)zO%J5TY}&BXq^7#M>euVL%01Tzj4$6^ZOjT*7@zr~q@6GEjGi)nbwzSL`TiLN z{DVG~I$w@%^#tD{>1Ap@%=XogG_^Hvy_xiRn4yy?LKsC+ zU!S79X8orh&D%>1S`x2iyi&(iG&r#YT{}~iy(FIOo8?MZU#eo*c*(RjAGj@uDi zARJur)-*{n0PgW~&mFeg`MJ?(Kr;NUom)jh?ozZtyywN9bea6ikQlh}953Oul~N%4 z@Sx!@>?l1e7V*@HZMJx!gMo0TeXdU~#W6^n?YVQJ$)nuFRkvKbfwv_s*2g(!wPO|@ zvuXF=2MiPIX)A7x!|BthSa$GB%ECnuZe_Scx&AlnC z!~6C_SF24#@^VMIw)a-7{00}}Cr5NImPbW8OTIHoo6@NcxLVTna8<<;uy~YaaeMnd z;k_ynYc_8jQn9vW_W8QLkgaHtmwGC}wRcgZ^I^GPbz{lW)p#YYoinez1MjkY%6LBd z+Vr>j&^!?b-*Vk>8I!28o`r3w&^Lal8@=50zV4&9V9oXI{^r8;JmVeos&wf?O!;_o zk))^k*1fvYw9?WrS!sG2TcX`hH@Y3mF&@{i05;_AV{>Umi8{uZP_0W5_1V2yHU<)E z+qviK*7SJtnL;76{WK!?Pv$-!w$08<%8Qy|sB|P%GiV1<+dHw*sj!C~SjsB6+1L@so+Q~n# z+Uc5+Uz+mGmkR@>H7D*c?mm8WQz;3VOpktU_DeBi>3#@z zmLe;3gP<7KPy>~k47nEeT?G?7e2g6316Xdb_y+ja5C9Ayg6QTNr~&Kbs(1>7zp|f@le;9B z1e(+Ga%jPWR7oc}=XcB4$z?YD)l;%#U;}~gZzGViI=fwu9OAPCCK!0w>Ay^#$b49k zT&|M?JaIyRT<;@*t_jp1ifWPvL;{maf6o0T#X!#9YX;0Q;LTQ0}0tg^_Ru4pkSr4#P zmnW|D0`A#Ie6pEfBDv39=jN2;kiUoT6I&kChsbI!jMuY6zuZql5!&i%5!c zjsHlXtjT;NV?jAb`%vy)JOK_j1rponLqc>(2qgYlLPEs>|0QV<=Pw~C`fLFKJJitt zyC6003{rxCsmtGKjhB%W2W~*%vKH8l$pZoOFT*K@uL9%CD^3rh=ZtuTU1 zJpf4|%n^yjh#dKSSCJI8;YU*CD!8Wv20*e5`-fya^75@ADLU^RdHDg3Bk3k6)dGi7 z!!z;|O1h$8q!vO*w6 I6Xdi10eY*&F8}}l diff --git a/kotlin/gradle/wrapper/gradle-wrapper.properties b/kotlin/gradle/wrapper/gradle-wrapper.properties index 2b22d057a07..6ec1567a0f8 100644 --- a/kotlin/gradle/wrapper/gradle-wrapper.properties +++ b/kotlin/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/kotlin/gradlew b/kotlin/gradlew index 65dcd68d65c..79a61d421cc 100755 --- a/kotlin/gradlew +++ b/kotlin/gradlew @@ -144,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac diff --git a/kotlin/wallet-core-kotlin/build.gradle.kts b/kotlin/wallet-core-kotlin/build.gradle.kts index 780048b49fa..e82797fed7a 100644 --- a/kotlin/wallet-core-kotlin/build.gradle.kts +++ b/kotlin/wallet-core-kotlin/build.gradle.kts @@ -38,8 +38,6 @@ kotlin { } val androidMain by getting { - kotlin.srcDir(projectDir.resolve("../../jni/cpp")) - kotlin.srcDir(projectDir.resolve("../../jni/kotlin")) kotlin.srcDir(projectDir.resolve("src/androidMain/generated")) } val commonMain by getting { diff --git a/kotlin/wallet-core-kotlin/src/androidMain/kotlin/com/trustwallet/core/AnySigner.kt b/kotlin/wallet-core-kotlin/src/androidMain/kotlin/com/trustwallet/core/AnySigner.kt index 4daa57c663b..374d66218b9 100644 --- a/kotlin/wallet-core-kotlin/src/androidMain/kotlin/com/trustwallet/core/AnySigner.kt +++ b/kotlin/wallet-core-kotlin/src/androidMain/kotlin/com/trustwallet/core/AnySigner.kt @@ -6,10 +6,17 @@ package com.trustwallet.core -actual external fun signImpl(input: ByteArray, coin: CoinType): ByteArray +actual object AnySigner { -actual external fun supportsJsonImpl(coin: CoinType): Boolean + @JvmStatic + actual external fun sign(input: ByteArray, coin: CoinType): ByteArray -actual external fun signJsonImpl(json: String, key: ByteArray, coin: CoinType): String + @JvmStatic + actual external fun supportsJson(coin: CoinType): Boolean -actual external fun planImpl(input: ByteArray, coin: CoinType): ByteArray + @JvmStatic + actual external fun signJson(json: String, key: ByteArray, coin: CoinType): String + + @JvmStatic + actual external fun plan(input: ByteArray, coin: CoinType): ByteArray +} diff --git a/kotlin/wallet-core-kotlin/src/commonMain/kotlin/com/trustwallet/core/AnySigner.kt b/kotlin/wallet-core-kotlin/src/commonMain/kotlin/com/trustwallet/core/AnySigner.kt index df9455e9943..85e195c229e 100644 --- a/kotlin/wallet-core-kotlin/src/commonMain/kotlin/com/trustwallet/core/AnySigner.kt +++ b/kotlin/wallet-core-kotlin/src/commonMain/kotlin/com/trustwallet/core/AnySigner.kt @@ -9,24 +9,19 @@ package com.trustwallet.core import com.squareup.wire.Message import com.squareup.wire.ProtoAdapter -object AnySigner { +expect object AnySigner { - fun > sign(input: Message<*, *>, coin: CoinType, adapter: ProtoAdapter): T = - adapter.decode(signImpl(input.encode(), coin)) + fun sign(input: ByteArray, coin: CoinType): ByteArray - fun supportsJson(coin: CoinType): Boolean = supportsJsonImpl(coin) + fun supportsJson(coin: CoinType): Boolean - fun signJson(json: String, key: ByteArray, coin: CoinType): String = - signJsonImpl(json, key, coin) + fun signJson(json: String, key: ByteArray, coin: CoinType): String - fun > plan(input: Message<*, *>, coin: CoinType, adapter: ProtoAdapter): T = - adapter.decode(planImpl(input.encode(), coin)) + fun plan(input: ByteArray, coin: CoinType): ByteArray } -internal expect fun signImpl(input: ByteArray, coin: CoinType): ByteArray +fun > AnySigner.sign(input: Message<*, *>, coin: CoinType, adapter: ProtoAdapter): T = + adapter.decode(sign(input.encode(), coin)) -internal expect fun supportsJsonImpl(coin: CoinType): Boolean - -internal expect fun signJsonImpl(json: String, key: ByteArray, coin: CoinType): String - -internal expect fun planImpl(input: ByteArray, coin: CoinType): ByteArray +fun > AnySigner.plan(input: Message<*, *>, coin: CoinType, adapter: ProtoAdapter): T = + adapter.decode(plan(input.encode(), coin)) diff --git a/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/AnySigner.kt b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/AnySigner.kt index ad6aa3e3888..fd1cb8ed651 100644 --- a/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/AnySigner.kt +++ b/kotlin/wallet-core-kotlin/src/iosMain/kotlin/com/trustwallet/core/AnySigner.kt @@ -6,14 +6,17 @@ package com.trustwallet.core -actual fun signImpl(input: ByteArray, coin: CoinType): ByteArray = - TWAnySignerSign(input.toTwData(), coin.value)!!.readTwBytes()!! +actual object AnySigner { -actual fun supportsJsonImpl(coin: CoinType): Boolean = - TWAnySignerSupportsJSON(coin.value) + actual fun sign(input: ByteArray, coin: CoinType): ByteArray = + TWAnySignerSign(input.toTwData(), coin.value)!!.readTwBytes()!! -actual fun signJsonImpl(json: String, key: ByteArray, coin: CoinType): String = - TWAnySignerSignJSON(json.toTwString(), key.toTwData(), coin.value).fromTwString()!! + actual fun supportsJson(coin: CoinType): Boolean = + TWAnySignerSupportsJSON(coin.value) -actual fun planImpl(input: ByteArray, coin: CoinType): ByteArray = - TWAnySignerPlan(input.toTwData(), coin.value)?.readTwBytes()!! + actual fun signJson(json: String, key: ByteArray, coin: CoinType): String = + TWAnySignerSignJSON(json.toTwString(), key.toTwData(), coin.value).fromTwString()!! + + actual fun plan(input: ByteArray, coin: CoinType): ByteArray = + TWAnySignerPlan(input.toTwData(), coin.value)?.readTwBytes()!! +} diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/WalletCore.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/WalletCore.kt index 61bdabba2bb..e71a5458a55 100644 --- a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/WalletCore.kt +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/WalletCore.kt @@ -4,24 +4,29 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. +import com.trustwallet.core.* import kotlin.js.Promise @JsExport @JsName("WalletCoreKotlin") object WalletCore { - internal var Instance: dynamic = null + internal lateinit var Instance: JsWalletCore - fun init(): Promise = - WalletCoreExports.initWasm() - .then { walletCore: dynamic -> - Instance = walletCore - walletCore - } + fun init(): Promise = + if (::Instance.isInitialized) { + Promise.resolve(Instance) + } else { + WalletCoreExports.initWasm() + .then { walletCore -> + Instance = walletCore + walletCore + } + } } @JsModule("@trustwallet/wallet-core") @JsNonModule -internal external object WalletCoreExports { - fun initWasm(): Promise +private external object WalletCoreExports { + fun initWasm(): Promise } diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/AnySigner.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/AnySigner.kt index 7f4260201c7..b9e28700f97 100644 --- a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/AnySigner.kt +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/AnySigner.kt @@ -8,18 +8,17 @@ package com.trustwallet.core import WalletCore -internal actual fun signImpl(input: ByteArray, coin: CoinType): ByteArray = - WalletCore.Instance.AnySigner.sign(input.toUInt8Array(), coin._value) - .unsafeCast() - .toByteArray() +actual object AnySigner { -internal actual fun supportsJsonImpl(coin: CoinType): Boolean = - WalletCore.Instance.AnySigner.supportsJSON(coin._value) as Boolean + actual fun sign(input: ByteArray, coin: CoinType): ByteArray = + WalletCore.Instance.AnySigner.sign(input.asUInt8Array(), coin.jsValue).asByteArray() -internal actual fun signJsonImpl(json: String, key: ByteArray, coin: CoinType): String = - TODO() + actual fun supportsJson(coin: CoinType): Boolean = + WalletCore.Instance.AnySigner.supportsJSON(coin.jsValue) -internal actual fun planImpl(input: ByteArray, coin: CoinType): ByteArray = - WalletCore.Instance.AnySigner.plan(input.toUInt8Array(), coin._value) - .unsafeCast() - .toByteArray() + actual fun signJson(json: String, key: ByteArray, coin: CoinType): String = + TODO() + + actual fun plan(input: ByteArray, coin: CoinType): ByteArray = + WalletCore.Instance.AnySigner.plan(input.asUInt8Array(), coin.jsValue).asByteArray() +} diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/ByteArray.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/ByteArray.kt new file mode 100644 index 00000000000..615d8c38db9 --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/ByteArray.kt @@ -0,0 +1,24 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core + +import org.khronos.webgl.Int8Array +import org.khronos.webgl.Uint8Array + +internal typealias UInt8Array = Uint8Array + +fun Int8Array.asByteArray(): ByteArray = + unsafeCast() + +fun Uint8Array.asByteArray(): ByteArray = + Int8Array(buffer, byteOffset, length).asByteArray() + +fun ByteArray.asInt8Array(): Int8Array = + unsafeCast() + +fun ByteArray.asUInt8Array(): Uint8Array = + asInt8Array().let { Uint8Array(it.buffer, it.byteOffset, it.length) } diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsAnySigner.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsAnySigner.kt new file mode 100644 index 00000000000..f387eccbe7d --- /dev/null +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsAnySigner.kt @@ -0,0 +1,20 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +package com.trustwallet.core + +@JsModule("@trustwallet/wallet-core") +@JsName("AnySigner") +external class JsAnySigner { + companion object { + fun sign(data: UInt8Array, coin: JsCoinType): UInt8Array + fun plan(data: UInt8Array, coin: JsCoinType): UInt8Array + fun supportsJSON(coin: JsCoinType): Boolean + } +} + +inline val JsWalletCore.AnySigner: JsAnySigner.Companion + get() = asDynamic().AnySigner.unsafeCast() diff --git a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/UInt8Array.kt b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsWalletCore.kt similarity index 53% rename from kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/UInt8Array.kt rename to kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsWalletCore.kt index 001d22c0912..f2d75c7c361 100644 --- a/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/UInt8Array.kt +++ b/kotlin/wallet-core-kotlin/src/jsMain/kotlin/com/trustwallet/core/JsWalletCore.kt @@ -4,14 +4,10 @@ // terms governing use, modification, and redistribution, is contained in the // file LICENSE at the root of the source code distribution tree. -package com.trustwallet.core - -import org.khronos.webgl.get +@file:Suppress("PropertyName") -internal typealias UInt8Array = org.khronos.webgl.Uint8Array - -internal fun UInt8Array.toByteArray(): ByteArray = - ByteArray(length, ::get) +package com.trustwallet.core -internal fun ByteArray.toUInt8Array(): UInt8Array = - UInt8Array(toTypedArray()) +@JsModule("@trustwallet/wallet-core") +@JsName("WalletCore") +external interface JsWalletCore diff --git a/src/interface/TWAccount.cpp b/src/interface/TWAccount.cpp index 73a624738c7..1759273d9a3 100644 --- a/src/interface/TWAccount.cpp +++ b/src/interface/TWAccount.cpp @@ -10,7 +10,8 @@ using namespace TW; -struct TWAccount* _Nonnull TWAccountCreate(TWString* _Nonnull address, enum TWCoinType coin, +struct TWAccount* _Nonnull TWAccountCreate(TWString* _Nonnull address, + enum TWCoinType coin, enum TWDerivation derivation, TWString* _Nonnull derivationPath, TWString* _Nonnull publicKey, @@ -33,6 +34,10 @@ TWString* _Nonnull TWAccountAddress(struct TWAccount* _Nonnull account) { return TWStringCreateWithUTF8Bytes(account->impl.address.c_str()); } +enum TWCoinType TWAccountCoin(struct TWAccount* _Nonnull account) { + return account->impl.coin; +} + enum TWDerivation TWAccountDerivation(struct TWAccount* _Nonnull account) { return account->impl.derivation; } @@ -48,7 +53,3 @@ TWString* _Nonnull TWAccountPublicKey(struct TWAccount* _Nonnull account) { TWString* _Nonnull TWAccountExtendedPublicKey(struct TWAccount* _Nonnull account) { return TWStringCreateWithUTF8Bytes(account->impl.extendedPublicKey.c_str()); } - -enum TWCoinType TWAccountCoin(struct TWAccount* _Nonnull account) { - return account->impl.coin; -} From c33d64d1562dc00fd4c0aed69ab60d8114dd9a4a Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 2 Mar 2023 15:26:55 +0100 Subject: [PATCH 205/497] [Tezos]: Message Signer (#2962) --- .../tezos/TestTezosMessageSigner.kt | 42 +++++++++++++ .../TrustWalletCore/TWTezosMessageSigner.h | 53 ++++++++++++++++ src/Tezos/MessageSigner.cpp | 55 +++++++++++++++++ src/Tezos/MessageSigner.h | 40 ++++++++++++ src/interface/TWTezosMessageSigner.cpp | 31 ++++++++++ swift/Tests/Blockchains/TezosTests.swift | 21 +++++++ tests/chains/Tezos/MessageSignerTests.cpp | 61 +++++++++++++++++++ 7 files changed, 303 insertions(+) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tezos/TestTezosMessageSigner.kt create mode 100644 include/TrustWalletCore/TWTezosMessageSigner.h create mode 100644 src/Tezos/MessageSigner.cpp create mode 100644 src/Tezos/MessageSigner.h create mode 100644 src/interface/TWTezosMessageSigner.cpp create mode 100644 tests/chains/Tezos/MessageSignerTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tezos/TestTezosMessageSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tezos/TestTezosMessageSigner.kt new file mode 100644 index 00000000000..57b06f83714 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/tezos/TestTezosMessageSigner.kt @@ -0,0 +1,42 @@ +package com.trustwallet.core.app.blockchains.tezos + +import com.trustwallet.core.app.utils.Numeric +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import wallet.core.jni.CoinType +import wallet.core.jni.TezosMessageSigner +import wallet.core.jni.PrivateKey +import java.util.regex.Pattern + +class TestTezosMessageSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testMessageSignerSignAndVerify() { + val data = Numeric.hexStringToByteArray("91b4fb8d7348db2e7de2693f58ce1cceb966fa960739adac1d9dba2cbaa0940a") + val privateKey = PrivateKey(data) + val msg = "05010000004254657a6f73205369676e6564204d6573736167653a207465737455726c20323032332d30322d30385431303a33363a31382e3435345a2048656c6c6f20576f726c64" + val signature = TezosMessageSigner.signMessage(privateKey, msg) + assertEquals("edsigu3se2fcEJUCm1aqxjzbHdf7Wsugr4mLaA9YM2UVZ9Yy5meGv87VqHN3mmDeRwApTj1JKDaYjqmLZifSFdWCqBoghqaowwJ", signature) + val pubKey = privateKey.getPublicKey(CoinType.TEZOS) + assertTrue(TezosMessageSigner.verifyMessage(pubKey, msg, signature)) + } + + @Test + fun testMessageSignerInputToPayload() { + val payload = TezosMessageSigner.inputToPayload("Tezos Signed Message: testUrl 2023-02-08T10:36:18.454Z Hello World") + val expected = "05010000004254657a6f73205369676e6564204d6573736167653a207465737455726c20323032332d30322d30385431303a33363a31382e3435345a2048656c6c6f20576f726c64" + assertEquals(expected, payload) + } + + @Test + fun testMessageSignerFormatMessage() { + val formatedMsg = TezosMessageSigner.formatMessage("Hello World", "testUrl") + val regex = Pattern.compile("Tezos Signed Message: \\S+ \\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z .+") + assertTrue(regex.matcher(formatedMsg).matches()) + } +} diff --git a/include/TrustWalletCore/TWTezosMessageSigner.h b/include/TrustWalletCore/TWTezosMessageSigner.h new file mode 100644 index 00000000000..bcb99bf8a85 --- /dev/null +++ b/include/TrustWalletCore/TWTezosMessageSigner.h @@ -0,0 +1,53 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "TWBase.h" +#include "TWData.h" +#include "TWString.h" +#include "TWPrivateKey.h" +#include "TWPublicKey.h" + +TW_EXTERN_C_BEGIN + +/// Tezos message signing, verification and utilities. +TW_EXPORT_STRUCT +struct TWTezosMessageSigner; + +/// Implement format input as described in https://tezostaquito.io/docs/signing/ +/// +/// \param message message to format e.g: Hello, World +/// \param dAppUrl the app url, e.g: testUrl +/// \returns the formatted message as a string +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWTezosMessageSignerFormatMessage(TWString* _Nonnull message, TWString* _Nonnull url); + +/// Implement input to payload as described in: https://tezostaquito.io/docs/signing/ +/// +/// \param message formatted message to be turned into an hex payload +/// \return the hexpayload of the formated message as a hex string +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWTezosMessageSignerInputToPayload(TWString* _Nonnull message); + +/// Sign a message as described in https://tezostaquito.io/docs/signing/ +/// +/// \param privateKey: the private key used for signing +/// \param message: A custom message payload (hex) which is input to the signing. +/// \returns the signature, Hex-encoded. On invalid input empty string is returned. Returned object needs to be deleted after use. +TW_EXPORT_STATIC_METHOD +TWString* _Nonnull TWTezosMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message); + +/// Verify signature for a message as described in https://tezostaquito.io/docs/signing/ +/// +/// \param pubKey: pubKey that will verify the message from the signature +/// \param message: the message signed as a payload (hex) +/// \param signature: in Base58-encoded form. +/// \returns false on any invalid input (does not throw), true if the message can be verified from the signature +TW_EXPORT_STATIC_METHOD +bool TWTezosMessageSignerVerifyMessage(const struct TWPublicKey* _Nonnull pubKey, TWString* _Nonnull message, TWString* _Nonnull signature); + +TW_EXTERN_C_END diff --git a/src/Tezos/MessageSigner.cpp b/src/Tezos/MessageSigner.cpp new file mode 100644 index 00000000000..34e9432b132 --- /dev/null +++ b/src/Tezos/MessageSigner.cpp @@ -0,0 +1,55 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include +#include +#include +#include + +#include "Base58.h" +#include "HexCoding.h" +#include "Tezos/MessageSigner.h" + +namespace TW::Tezos { + +static const Data gEdSigPrefix{9, 245, 205, 134, 18}; +static const std::string gMsgPrefix{"Tezos Signed Message:"}; + +std::string MessageSigner::inputToPayload(const std::string& input) { + using namespace std::string_literals; + auto bytes = data(input); + size_t bytesLength = bytes.size(); + std::string addPadding = std::string(8 - std::to_string(bytesLength).size(), '0') + hex(uint64_t(bytesLength)); + std::string paddedBytesLength = addPadding.substr(addPadding.size() - 8); + std::string payloadBytes = "05"s + "01"s + paddedBytesLength + hex(bytes); + return payloadBytes; +} + +std::string MessageSigner::formatMessage(const std::string& message, const std::string& dAppUrl) { + auto now = std::chrono::system_clock::now(); + auto now_time = std::chrono::system_clock::to_time_t(now); + auto now_ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; + std::ostringstream oss; + oss << gMsgPrefix << " " << dAppUrl << " "; + oss << std::put_time(std::gmtime(&now_time), "%FT%T.") << std::setw(3) << std::setfill('0') << now_ms.count() << "Z"; + oss << " " << message; + return oss.str(); +} + +std::string MessageSigner::signMessage(const PrivateKey& privateKey, const std::string& message) { + auto signature = privateKey.sign(Hash::blake2b(parse_hex(message), 32), TWCurveED25519); + return Base58::encodeCheck(concat(gEdSigPrefix, signature)); +} + +bool MessageSigner::verifyMessage(const PublicKey& publicKey, const std::string& message, const std::string& signature) noexcept { + auto decoded = Base58::decodeCheck(signature); + auto rawSignature = subData(decoded, gEdSigPrefix.size()); + auto msg = Hash::blake2b(parse_hex(message), 32); + return publicKey.verify(rawSignature, msg); +} + +} // namespace TW::Tezos diff --git a/src/Tezos/MessageSigner.h b/src/Tezos/MessageSigner.h new file mode 100644 index 00000000000..7ef7d6b3ed5 --- /dev/null +++ b/src/Tezos/MessageSigner.h @@ -0,0 +1,40 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#pragma once + +#include "PrivateKey.h" +#include "Data.h" + +namespace TW::Tezos { + class MessageSigner { + public: + /// implement format input as described in https://tezostaquito.io/docs/signing/ + /// \param message message to format e.g: Hello, World + /// \param dAppUrl the app url, e.g: testUrl + /// \return the formatted message as a string + static std::string formatMessage(const std::string& message, const std::string& dAppUrl); + + /// implement input to payload as described in: https://tezostaquito.io/docs/signing/ + /// + /// \param input formatted input to be turned into an hex payload + /// \return the hexpayload of the formated input as a hex string + static std::string inputToPayload(const std::string& input); + + /// implement signing as described in https://tezostaquito.io/docs/signing/ + /// \param privateKey the private key to sign with + /// \param message message to sign + /// \return base58 signed message + static std::string signMessage(const PrivateKey& privateKey, const std::string& message); + + /// implement verification as described in https://tezostaquito.io/docs/signing/ + /// \param publicKey publickey to verify the signed message + /// \param message message to be verified as a string + /// \param signature signature to verify the message against + /// \return true if the message match the signature, false otherwise + static bool verifyMessage(const PublicKey& publicKey, const std::string& message, const std::string& signature) noexcept;; + }; +} diff --git a/src/interface/TWTezosMessageSigner.cpp b/src/interface/TWTezosMessageSigner.cpp new file mode 100644 index 00000000000..91b3352ec7f --- /dev/null +++ b/src/interface/TWTezosMessageSigner.cpp @@ -0,0 +1,31 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include "Tezos/MessageSigner.h" + +bool TWTezosMessageSignerVerifyMessage(const struct TWPublicKey* _Nonnull publicKey, TWString* _Nonnull message, TWString* _Nonnull signature) { + return TW::Tezos::MessageSigner::verifyMessage(publicKey->impl, TWStringUTF8Bytes(message), TWStringUTF8Bytes(signature)); +} + +TWString* _Nonnull TWTezosMessageSignerSignMessage(const struct TWPrivateKey* _Nonnull privateKey, TWString* _Nonnull message) { + try { + const auto signature = TW::Tezos::MessageSigner::signMessage(privateKey->impl, TWStringUTF8Bytes(message)); + return TWStringCreateWithUTF8Bytes(signature.c_str()); + } catch (...) { + return TWStringCreateWithUTF8Bytes(""); + } +} + +TWString* TWTezosMessageSignerFormatMessage(TWString* _Nonnull message, TWString* _Nonnull url) { + const auto formatedMessage = TW::Tezos::MessageSigner::formatMessage(TWStringUTF8Bytes(message), TWStringUTF8Bytes(url)); + return TWStringCreateWithUTF8Bytes(formatedMessage.c_str()); +} + +TWString* TWTezosMessageSignerInputToPayload(TWString* message) { + const auto payload = TW::Tezos::MessageSigner::inputToPayload(TWStringUTF8Bytes(message)); + return TWStringCreateWithUTF8Bytes(payload.c_str()); +} diff --git a/swift/Tests/Blockchains/TezosTests.swift b/swift/Tests/Blockchains/TezosTests.swift index a6076a3beaa..df36e377712 100644 --- a/swift/Tests/Blockchains/TezosTests.swift +++ b/swift/Tests/Blockchains/TezosTests.swift @@ -113,6 +113,27 @@ class TezosTests: XCTestCase { XCTAssertEqual(output.encoded.hexString, expected) } + + public func testMessageSignerSignAndVerify() { + let privateKey = PrivateKey(data: Data(hexString: "91b4fb8d7348db2e7de2693f58ce1cceb966fa960739adac1d9dba2cbaa0940a")!)! + let msg = "05010000004254657a6f73205369676e6564204d6573736167653a207465737455726c20323032332d30322d30385431303a33363a31382e3435345a2048656c6c6f20576f726c64" + let signature = TezosMessageSigner.signMessage(privateKey: privateKey, message: msg) + XCTAssertEqual(signature, "edsigu3se2fcEJUCm1aqxjzbHdf7Wsugr4mLaA9YM2UVZ9Yy5meGv87VqHN3mmDeRwApTj1JKDaYjqmLZifSFdWCqBoghqaowwJ") + let pubKey = privateKey.getPublicKey(coinType: .tezos) + XCTAssertTrue(TezosMessageSigner.verifyMessage(pubKey: pubKey, message: msg, signature: signature)) + } + + public func testMessageSignerInputToPayload() { + let payload = TezosMessageSigner.inputToPayload(message: "Tezos Signed Message: testUrl 2023-02-08T10:36:18.454Z Hello World"); + let expected = "05010000004254657a6f73205369676e6564204d6573736167653a207465737455726c20323032332d30322d30385431303a33363a31382e3435345a2048656c6c6f20576f726c64"; + XCTAssertEqual(payload, expected); + } + + public func testMessageSignerFormatMessage() { + let formatedMsg = TezosMessageSigner.formatMessage(message: "Hello World", url: "testUrl") + let regex = try! NSRegularExpression(pattern: "Tezos Signed Message: \\S+ \\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z .+") + XCTAssertTrue(regex.firstMatch(in: formatedMsg, range: NSRange(location: 0, length: formatedMsg.utf16.count)) != nil) + } public func testSigning() { let privateKeyData = Data(hexString: "c6377a4cc490dc913fc3f0d9cf67d293a32df4547c46cb7e9e33c3b7b97c64d8")! diff --git a/tests/chains/Tezos/MessageSignerTests.cpp b/tests/chains/Tezos/MessageSignerTests.cpp new file mode 100644 index 00000000000..4fc6faa70c8 --- /dev/null +++ b/tests/chains/Tezos/MessageSignerTests.cpp @@ -0,0 +1,61 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +#include +#include + +#include "HexCoding.h" +#include "TestUtilities.h" +#include +#include + +namespace TW::Tezos::tests { +TEST(TezosMessageSigner, inputToPayload) { + auto payload = Tezos::MessageSigner::inputToPayload("Tezos Signed Message: testUrl 2023-02-08T10:36:18.454Z Hello World"); + ASSERT_EQ(payload, "05010000004254657a6f73205369676e6564204d6573736167653a207465737455726c20323032332d30322d30385431303a33363a31382e3435345a2048656c6c6f20576f726c64"); +} + +TEST(TezosMessageSigner, formatMessage) { + auto formatMessage = Tezos::MessageSigner::formatMessage("Hello World", "testUrl"); + std::regex regex("Tezos Signed Message: \\S+ \\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z .+"); + ASSERT_TRUE(std::regex_match(formatMessage, regex)); +} + +TEST(TezosMessageSigner, SignMessage) { + auto payload = Tezos::MessageSigner::inputToPayload("Tezos Signed Message: testUrl 2023-02-08T10:36:18.454Z Hello World"); + PrivateKey privKey(parse_hex("91b4fb8d7348db2e7de2693f58ce1cceb966fa960739adac1d9dba2cbaa0940a")); + auto result = Tezos::MessageSigner::signMessage(privKey, payload); + auto expected = "edsigu3se2fcEJUCm1aqxjzbHdf7Wsugr4mLaA9YM2UVZ9Yy5meGv87VqHN3mmDeRwApTj1JKDaYjqmLZifSFdWCqBoghqaowwJ"; + ASSERT_EQ(result, expected); + ASSERT_TRUE(Tezos::MessageSigner::verifyMessage(privKey.getPublicKey(TWPublicKeyTypeED25519), payload, result)); +} + +TEST(TWTezosMessageSigner, formatMessage) { + const auto message = STRING("Hello World"); + const auto dappUrl = STRING("testUrl"); + auto formattedMsg = WRAPS(TWTezosMessageSignerFormatMessage(message.get(), dappUrl.get())); + std::regex regex("Tezos Signed Message: \\S+ \\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z .+"); + ASSERT_TRUE(std::regex_match(std::string(TWStringUTF8Bytes(formattedMsg.get())), regex)); +} + +TEST(TWTezosMessageSigner, inputToPayload) { + const auto message = STRING("Tezos Signed Message: testUrl 2023-02-08T10:36:18.454Z Hello World"); + const auto expected = "05010000004254657a6f73205369676e6564204d6573736167653a207465737455726c20323032332d30322d30385431303a33363a31382e3435345a2048656c6c6f20576f726c64"; + auto payload = WRAPS(TWTezosMessageSignerInputToPayload(message.get())); + ASSERT_EQ(std::string(TWStringUTF8Bytes(payload.get())), expected); +} + +TEST(TWTezosMessageSigner, SignAndVerify) { + const auto privKeyData = "91b4fb8d7348db2e7de2693f58ce1cceb966fa960739adac1d9dba2cbaa0940a"; + const auto privateKey = WRAP(TWPrivateKey, TWPrivateKeyCreateWithData(DATA(privKeyData).get())); + const auto message = STRING("05010000004254657a6f73205369676e6564204d6573736167653a207465737455726c20323032332d30322d30385431303a33363a31382e3435345a2048656c6c6f20576f726c64"); + + const auto pubKey = WRAP(TWPublicKey, TWPrivateKeyGetPublicKey(privateKey.get(), TWCoinTypeTezos)); + const auto signature = WRAPS(TWTezosMessageSignerSignMessage(privateKey.get(), message.get())); + EXPECT_EQ(std::string(TWStringUTF8Bytes(signature.get())), "edsigu3se2fcEJUCm1aqxjzbHdf7Wsugr4mLaA9YM2UVZ9Yy5meGv87VqHN3mmDeRwApTj1JKDaYjqmLZifSFdWCqBoghqaowwJ"); + EXPECT_TRUE(TWTezosMessageSignerVerifyMessage(pubKey.get(), message.get(), signature.get())); +} +} // namespace TW::Tezos::tests From 6564c8a31746bea8c54da03d4a490cb6886fcc09 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 2 Mar 2023 15:27:10 +0100 Subject: [PATCH 206/497] [Solana]: Refactor, Optimizations (#2949) --- src/Solana/AccountMeta.h | 2 +- src/Solana/Address.cpp | 5 ++-- src/Solana/CompiledInstruction.h | 5 ++-- src/Solana/Entry.cpp | 4 +-- src/Solana/Entry.h | 4 +-- src/Solana/Program.cpp | 2 +- src/Solana/Program.h | 2 +- src/Solana/Signature.cpp | 13 --------- src/Solana/Signature.h | 30 --------------------- src/Solana/Signer.cpp | 17 +++++------- src/Solana/Transaction.cpp | 7 +++-- src/Solana/Transaction.h | 9 +++---- src/Solana/VersionedTransaction.cpp | 7 +++-- src/Solana/VersionedTransaction.h | 7 +++-- tests/chains/Solana/SignerTests.cpp | 34 ++++++++++++------------ tests/chains/Solana/TransactionTests.cpp | 15 +++++------ 16 files changed, 55 insertions(+), 108 deletions(-) delete mode 100644 src/Solana/Signature.cpp delete mode 100644 src/Solana/Signature.h diff --git a/src/Solana/AccountMeta.h b/src/Solana/AccountMeta.h index c5545603fde..a8f935a907a 100644 --- a/src/Solana/AccountMeta.h +++ b/src/Solana/AccountMeta.h @@ -14,7 +14,7 @@ struct AccountMeta { Address account; bool isSigner; bool isReadOnly; - AccountMeta(const Address& address, bool isSigner, bool isReadOnly): account(address), isSigner(isSigner), isReadOnly(isReadOnly) {} + AccountMeta(const Address& address, bool isSigner, bool isReadOnly) noexcept : account(address), isSigner(isSigner), isReadOnly(isReadOnly) {} }; } diff --git a/src/Solana/Address.cpp b/src/Solana/Address.cpp index b1df361aaab..25b6699e41c 100644 --- a/src/Solana/Address.cpp +++ b/src/Solana/Address.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -52,8 +52,7 @@ std::string Address::string() const { } Data Address::vector() const { - Data vec(std::begin(bytes), std::end(bytes)); - return vec; + return Data(begin(bytes), end(bytes)); } Address Address::defaultTokenAddress(const Address& tokenMintAddress) { diff --git a/src/Solana/CompiledInstruction.h b/src/Solana/CompiledInstruction.h index 1507886f185..913791ec3fc 100644 --- a/src/Solana/CompiledInstruction.h +++ b/src/Solana/CompiledInstruction.h @@ -26,8 +26,9 @@ struct CompiledInstruction { /// Supplied address vector is expected to contain all addresses and programId from the instruction; they are replaced by index into the address vector. CompiledInstruction(const Instruction& instruction, const std::vector
& addresses): addresses(addresses) { programIdIndex = findAccount(instruction.programId); - for (auto& account: instruction.accounts) { - accounts.push_back(findAccount(account.account)); + accounts.reserve(instruction.accounts.size()); + for (auto&& account: instruction.accounts) { + accounts.emplace_back(findAccount(account.account)); } data = instruction.data; } diff --git a/src/Solana/Entry.cpp b/src/Solana/Entry.cpp index 9ce90b67609..09df76df7f3 100644 --- a/src/Solana/Entry.cpp +++ b/src/Solana/Entry.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -14,8 +14,6 @@ using namespace std; namespace TW::Solana { -// Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. - bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, [[maybe_unused]] const PrefixVariant& addressPrefix) const { return Address::isValid(address); } diff --git a/src/Solana/Entry.h b/src/Solana/Entry.h index 3812f579ad9..81d7ed64446 100644 --- a/src/Solana/Entry.h +++ b/src/Solana/Entry.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -6,7 +6,7 @@ #pragma once -#include "../CoinEntry.h" +#include "CoinEntry.h" namespace TW::Solana { diff --git a/src/Solana/Program.cpp b/src/Solana/Program.cpp index f9f196bb209..1605aebba97 100644 --- a/src/Solana/Program.cpp +++ b/src/Solana/Program.cpp @@ -1,4 +1,4 @@ -// Copyright © 2017-2022 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Solana/Program.h b/src/Solana/Program.h index e2880c3c173..c91be4cb80c 100644 --- a/src/Solana/Program.h +++ b/src/Solana/Program.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2020 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the diff --git a/src/Solana/Signature.cpp b/src/Solana/Signature.cpp deleted file mode 100644 index e054ac0f8c2..00000000000 --- a/src/Solana/Signature.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright © 2017-2023 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -#include "Solana/Signature.h" - -namespace TW::Solana { - bool Signature::operator==(const Signature& v) const { - return bytes == v.bytes; - } -} diff --git a/src/Solana/Signature.h b/src/Solana/Signature.h deleted file mode 100644 index 3a1983cbaa9..00000000000 --- a/src/Solana/Signature.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright © 2017-2023 Trust Wallet. -// -// This file is part of Trust. The full Trust copyright notice, including -// terms governing use, modification, and redistribution, is contained in the -// file LICENSE at the root of the source code distribution tree. - -#pragma once - -#include -#include - -#include "Base58.h" - -namespace TW::Solana { -class Signature { -public: - static const size_t size = 64; - /// Signature data - std::array bytes; - - Signature(const std::string& string) { - const auto data = Base58::decode(string); - std::copy(data.begin(), data.end(), this->bytes.begin()); - } - Signature(const std::array& bytes) { this->bytes = bytes; } - Signature(const Data& bytes) { std::copy(bytes.begin(), bytes.end(), this->bytes.begin()); } - - bool operator==(const Signature& v) const; -}; -} diff --git a/src/Solana/Signer.cpp b/src/Solana/Signer.cpp index bab36a4cd76..a2359b6006c 100644 --- a/src/Solana/Signer.cpp +++ b/src/Solana/Signer.cpp @@ -21,8 +21,7 @@ void Signer::sign(const std::vector& privateKeys, VersionedTransacti auto address = Address(privateKey.getPublicKey(TWPublicKeyTypeED25519)); auto index = transaction.getAccountIndex(address); auto message = transaction.messageData(); - auto signature = Signature(privateKey.sign(message, TWCurveED25519)); - transaction.signatures[index] = signature; + transaction.signatures[index] = privateKey.sign(message, TWCurveED25519); } } @@ -194,16 +193,14 @@ void Signer::signUpdateBlockhash(const std::vector& privateKeys, // This method does not confirm that PrivateKey order matches that encoded in the messageData // That order must be correct for the Transaction to succeed on Solana Data Signer::signRawMessage(const std::vector& privateKeys, const Data messageData) { - std::vector signatures; - for (auto privateKey : privateKeys) { - auto signature = Signature(privateKey.sign(messageData, TWCurveED25519)); - signatures.push_back(signature); + std::vector signatures; + for (auto &&privateKey : privateKeys) { + signatures.emplace_back(privateKey.sign(messageData, TWCurveED25519)); } Data buffer; - append(buffer, shortVecLength(signatures)); - for (auto signature : signatures) { - Data signature_vec(signature.bytes.begin(), signature.bytes.end()); - append(buffer, signature_vec); + append(buffer, shortVecLength(signatures)); + for (auto &&signature : signatures) { + append(buffer, signature); } append(buffer, messageData); diff --git a/src/Solana/Transaction.cpp b/src/Solana/Transaction.cpp index 313f8cc60ac..52ee014c09e 100644 --- a/src/Solana/Transaction.cpp +++ b/src/Solana/Transaction.cpp @@ -17,10 +17,9 @@ namespace TW::Solana { std::string Transaction::serialize() const { Data buffer; - append(buffer, shortVecLength(this->signatures)); - for (auto signature : this->signatures) { - Data signature_vec(signature.bytes.begin(), signature.bytes.end()); - append(buffer, signature_vec); + append(buffer, shortVecLength(this->signatures)); + for (auto &&signature : this->signatures) { + append(buffer, signature); } append(buffer, this->messageData()); diff --git a/src/Solana/Transaction.h b/src/Solana/Transaction.h index 65d24a3bfb0..0608382986b 100644 --- a/src/Solana/Transaction.h +++ b/src/Solana/Transaction.h @@ -1,4 +1,4 @@ -// Copyright © 2017-2022 Trust Wallet. +// Copyright © 2017-2023 Trust Wallet. // // This file is part of Trust. The full Trust copyright notice, including // terms governing use, modification, and redistribution, is contained in the @@ -8,7 +8,6 @@ #include "Solana/Address.h" #include "Solana/LegacyMessage.h" -#include "Solana/Signature.h" #include "Data.h" #include "BinaryCoding.h" @@ -20,18 +19,18 @@ namespace TW::Solana { class Transaction { public: // Signatures - std::vector signatures; + std::vector signatures; // The message to sign LegacyMessage message; Transaction(const LegacyMessage& message) : message(message) { - this->signatures.resize(message.header.numRequiredSignatures, Signature(defaultSignature)); + this->signatures.resize(message.header.numRequiredSignatures, defaultSignature); } // Default basic transfer transaction Transaction(const Address& from, const Address& to, uint64_t value, Data recentBlockhash, std::string memo = "", std::vector
references = {}) : message(LegacyMessage::createTransfer(from, to, value, recentBlockhash, memo, references)) { - this->signatures.resize(1, Signature(defaultSignature)); + this->signatures.resize(1, defaultSignature); } public: diff --git a/src/Solana/VersionedTransaction.cpp b/src/Solana/VersionedTransaction.cpp index 439add21b80..c8ff5b1ff7a 100644 --- a/src/Solana/VersionedTransaction.cpp +++ b/src/Solana/VersionedTransaction.cpp @@ -12,10 +12,9 @@ namespace TW::Solana { std::string VersionedTransaction::serialize() const { Data buffer; - append(buffer, shortVecLength(this->signatures)); - for (auto signature : this->signatures) { - Data signature_vec(signature.bytes.begin(), signature.bytes.end()); - append(buffer, signature_vec); + append(buffer, shortVecLength(this->signatures)); + for (auto &&signature : this->signatures) { + append(buffer, signature); } append(buffer, this->messageData()); diff --git a/src/Solana/VersionedTransaction.h b/src/Solana/VersionedTransaction.h index 02af2d377be..01460c79ee1 100644 --- a/src/Solana/VersionedTransaction.h +++ b/src/Solana/VersionedTransaction.h @@ -8,7 +8,6 @@ #include "Solana/Address.h" #include "Solana/VersionedMessage.h" -#include "Solana/Signature.h" #include "Data.h" #include "BinaryCoding.h" @@ -20,18 +19,18 @@ namespace TW::Solana { class VersionedTransaction { public: // Signatures - std::vector signatures; + std::vector signatures; // The message to sign VersionedMessage message; VersionedTransaction(const VersionedMessage& message) : message(message) { - this->signatures.resize(header(message).numRequiredSignatures, Signature(defaultSignature)); + this->signatures.resize(header(message).numRequiredSignatures, defaultSignature); } // Default basic transfer transaction VersionedTransaction(const Address& from, const Address& to, uint64_t value, Data recentBlockhash, std::string memo = "", std::vector
references = {}) : message(VersionedMessage(LegacyMessage::createTransfer(from, to, value, recentBlockhash, memo, references))) { - this->signatures.resize(1, Signature(defaultSignature)); + this->signatures.resize(1, defaultSignature); } public: diff --git a/tests/chains/Solana/SignerTests.cpp b/tests/chains/Solana/SignerTests.cpp index 96bc64a332d..5b828ad7b4a 100644 --- a/tests/chains/Solana/SignerTests.cpp +++ b/tests/chains/Solana/SignerTests.cpp @@ -99,8 +99,8 @@ TEST(SolanaSigner, SingleSignTransaction) { signerKeys.push_back(privateKey); Signer::sign(signerKeys, transaction); - std::vector expectedSignatures; - Signature expectedSignature( + std::vector expectedSignatures; + auto expectedSignature = Base58::decode( "5T6uZBHnHFd8uWErDBTFRVkbKuhbcm94K5MJ2beTYDruzqv4FjS7EMKvC94ZfxNAiWUXZ6bZxS3WXUbhJwYNPWn"); expectedSignatures.push_back(expectedSignature); ASSERT_EQ(transaction.signatures, expectedSignatures); @@ -139,8 +139,8 @@ TEST(SolanaSigner, SignTransactionToSelf) { signerKeys.push_back(privateKey); Signer::sign(signerKeys, transaction); - std::vector expectedSignatures; - Signature expectedSignature( + std::vector expectedSignatures; + auto expectedSignature = Base58::decode( "3CFWDEK51noPJP4v2t8JZ3qj7kC7kLKyws9akfHMyuJnQ35EtzBptHqvaHfeswiLsvUSxzMVNoj4CuRxWtDD9zB1"); expectedSignatures.push_back(expectedSignature); ASSERT_EQ(transaction.signatures, expectedSignatures); @@ -193,11 +193,11 @@ TEST(SolanaSigner, MultipleSignTransaction) { signerKeys.push_back(privateKey0); Signer::sign(signerKeys, transaction); - std::vector expectedSignatures; - Signature expectedSignature0( + std::vector expectedSignatures; + auto expectedSignature0 = Base58::decode( "37beWPhNMfWUz75Tb24TX3PCS89FZscbCgwwLpFnzVfZYPqDpAWruvqzc9eeQYft35H23Vm9Tv1dPwEKWT3vAVPb"); expectedSignatures.push_back(expectedSignature0); - Signature expectedSignature1( + auto expectedSignature1 = Base58::decode( "5NxQshVaAXtQ8YVdcBtCanT62KbxnRfhubjGndFvetgn9AiaoLVZvRGutR5D7FJebRxq8bd6nQXn59LFzavEUrdQ"); expectedSignatures.push_back(expectedSignature1); ASSERT_EQ(transaction.signatures, expectedSignatures); @@ -230,8 +230,8 @@ TEST(SolanaSigner, SignUpdateBlockhash) { auto newBlockhash = Base58::decode("GgBaCs3NCBuZN12kCJgAW63ydqohFkHEdfdEXBPzLHq"); Signer::signUpdateBlockhash(signerKeys, transaction, newBlockhash); - std::vector expectedSignatures; - Signature expectedSignature( + std::vector expectedSignatures; + auto expectedSignature = Base58::decode( "5AFhXjvGdENXCAe9MPvUA2qjoL4XtZwZKG7kK2HmZf1ibpxjx5kzogHZjN39uYB9J33UFJN15KhSggBZhzyNQmta"); expectedSignatures.push_back(expectedSignature); ASSERT_EQ(transaction.signatures, expectedSignatures); @@ -289,8 +289,8 @@ TEST(SolanaSigner, SignDelegateStakeV2) { signerKeys.push_back(privateKeySigner); Signer::sign(signerKeys, transaction); - std::vector expectedSignatures; - Signature expectedSignature("58iogHzSJZmvTxi71W8k2yZXSPVfGAgtgqrk1RaBtfVFewU9yiJCkvSF1Hhjyax5DuexzR7ryWZDAWKQ73pyqvMs"); + std::vector expectedSignatures; + auto expectedSignature = Base58::decode("58iogHzSJZmvTxi71W8k2yZXSPVfGAgtgqrk1RaBtfVFewU9yiJCkvSF1Hhjyax5DuexzR7ryWZDAWKQ73pyqvMs"); expectedSignatures.push_back(expectedSignature); EXPECT_EQ(transaction.signatures, expectedSignatures); @@ -317,8 +317,8 @@ TEST(SolanaSigner, SignDelegateStakeV1) { signerKeys.push_back(privateKeySigner); Signer::sign(signerKeys, transaction); - std::vector expectedSignatures; - Signature expectedSignature("gDPbnakbktrASmnUwKGpmftvQRbcyAvxyAyVXq3oVLfAdTPDqY8hhLPHTgidEZGWcmiaXnEyKg2GQLkkAh3JYr3"); + std::vector expectedSignatures; + auto expectedSignature = Base58::decode("gDPbnakbktrASmnUwKGpmftvQRbcyAvxyAyVXq3oVLfAdTPDqY8hhLPHTgidEZGWcmiaXnEyKg2GQLkkAh3JYr3"); expectedSignatures.push_back(expectedSignature); EXPECT_EQ(transaction.signatures, expectedSignatures); @@ -344,8 +344,8 @@ TEST(SolanaSigner, SignCreateTokenAccount) { signerKeys.push_back(privateKeySigner); Signer::sign(signerKeys, transaction); - std::vector expectedSignatures; - Signature expectedSignature("3doYbPs5rES3TeDSrntqUvMgXCDE2ViJX2SFhLtiptVNkqPuixXs1SwU5LUZ3KwHnCzDUth6BRr3vU3gqnuUgRvQ"); + std::vector expectedSignatures; + auto expectedSignature = Base58::decode("3doYbPs5rES3TeDSrntqUvMgXCDE2ViJX2SFhLtiptVNkqPuixXs1SwU5LUZ3KwHnCzDUth6BRr3vU3gqnuUgRvQ"); expectedSignatures.push_back(expectedSignature); EXPECT_EQ(transaction.signatures, expectedSignatures); @@ -402,8 +402,8 @@ TEST(SolanaSigner, SignTransferToken_3vZ67C) { signerKeys.push_back(privateKeySigner); Signer::sign(signerKeys, transaction); - std::vector expectedSignatures; - Signature expectedSignature("3vZ67CGoRYkuT76TtpP2VrtTPBfnvG2xj6mUTvvux46qbnpThgQDgm27nC3yQVUZrABFjT9Qo7vA74tCjtV5P9Xg"); + std::vector expectedSignatures; + auto expectedSignature = Base58::decode("3vZ67CGoRYkuT76TtpP2VrtTPBfnvG2xj6mUTvvux46qbnpThgQDgm27nC3yQVUZrABFjT9Qo7vA74tCjtV5P9Xg"); expectedSignatures.push_back(expectedSignature); EXPECT_EQ(transaction.signatures, expectedSignatures); diff --git a/tests/chains/Solana/TransactionTests.cpp b/tests/chains/Solana/TransactionTests.cpp index 25bed86af71..d62e5e04368 100644 --- a/tests/chains/Solana/TransactionTests.cpp +++ b/tests/chains/Solana/TransactionTests.cpp @@ -34,8 +34,7 @@ TEST(SolanaTransaction, TransferSerializeTransaction) { auto to = Address("4iSnyfDKaejniaPc2pBBckwQqV3mDS93go15NdxWJq2y"); auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto transaction = Transaction(from, to, 42, recentBlockhash); - Signature signature( - "46SRiQGvtPb1iivDfnuC3dW1GzXkfQPTjdUyvFqF2sdPvFrsfx94fys2xpNKR6UiAj7RgKWdJG6mEfe85up6i1JT"); + auto signature = Base58::decode("46SRiQGvtPb1iivDfnuC3dW1GzXkfQPTjdUyvFqF2sdPvFrsfx94fys2xpNKR6UiAj7RgKWdJG6mEfe85up6i1JT"); transaction.signatures.clear(); transaction.signatures.push_back(signature); @@ -52,7 +51,7 @@ TEST(SolanaTransaction, TransferTransactionPayToSelf) { auto to = Address("zVSpQnbBZ7dyUWzXhrUQRsTYYNzoAdJWHsHSqhPj3Xu"); auto recentBlockhash = Base58::decode("11111111111111111111111111111111"); auto transaction = Transaction(from, to, 42, recentBlockhash); - Signature signature( + auto signature = Base58::decode( "3CFWDEK51noPJP4v2t8JZ3qj7kC7kLKyws9akfHMyuJnQ35EtzBptHqvaHfeswiLsvUSxzMVNoj4CuRxWtDD9zB1"); transaction.signatures.clear(); transaction.signatures.push_back(signature); @@ -71,7 +70,7 @@ TEST(SolanaTransaction, TransferWithMemoAndReferenceTransaction) { const auto memo = "HelloSolana73"; std::vector
references = {Address("GaeTAQZyhVEocTC7iY8GztSyY5cBAJTkAUUA1kLFLMV")}; auto transaction = Transaction(from, to, 42, recentBlockhash, memo, references); - const Signature signature("3CFWDEK51noPJP4v2t8JZ3qj7kC7kLKyws9akfHMyuJnQ35EtzBptHqvaHfeswiLsvUSxzMVNoj4CuRxWtDD9zB1"); + auto signature = Base58::decode("3CFWDEK51noPJP4v2t8JZ3qj7kC7kLKyws9akfHMyuJnQ35EtzBptHqvaHfeswiLsvUSxzMVNoj4CuRxWtDD9zB1"); transaction.signatures.clear(); transaction.signatures.push_back(signature); @@ -87,7 +86,7 @@ TEST(SolanaTransaction, StakeSerializeTransactionV2) { auto stakeAddress = StakeProgram::addressFromRecentBlockhash(signer, recentBlockhash, programId); auto message = LegacyMessage::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); auto transaction = Transaction(message); - Signature signature( + auto signature = Base58::decode( "2GXRrZMMWTaY8ycwFTLFojAVZ1EepFqnVGW7b5bBuuKPiVrpaPXMAwyYsSmYc2okCa1MuJjNguu1emSJRtZxVdwt"); transaction.signatures.clear(); transaction.signatures.push_back(signature); @@ -104,7 +103,7 @@ TEST(SolanaTransaction, StakeSerializeTransactionV1) { auto stakeAddress = StakeProgram::addressFromValidatorSeed(signer, voteAddress, programId); auto message = LegacyMessage::createStake(signer, stakeAddress, voteAddress, 42, recentBlockhash); auto transaction = Transaction(message); - Signature signature( + auto signature = Base58::decode( "2GXRrZMMWTaY8ycwFTLFojAVZ1EepFqnVGW7b5bBuuKPiVrpaPXMAwyYsSmYc2okCa1MuJjNguu1emSJRtZxVdwt"); transaction.signatures.clear(); transaction.signatures.push_back(signature); @@ -143,7 +142,7 @@ TEST(SolanaTransaction, CreateTokenAccountTransaction) { EXPECT_EQ(message.instructions[0].accounts[6].account.string(), "SysvarRent111111111111111111111111111111111"); auto transaction = Transaction(message); transaction.signatures.clear(); - Signature signature("3doYbPs5rES3TeDSrntqUvMgXCDE2ViJX2SFhLtiptVNkqPuixXs1SwU5LUZ3KwHnCzDUth6BRr3vU3gqnuUgRvQ"); + auto signature = Base58::decode("3doYbPs5rES3TeDSrntqUvMgXCDE2ViJX2SFhLtiptVNkqPuixXs1SwU5LUZ3KwHnCzDUth6BRr3vU3gqnuUgRvQ"); transaction.signatures.push_back(signature); auto expectedString = @@ -170,7 +169,7 @@ TEST(SolanaTransaction, TransferTokenTransaction_3vZ67C) { ASSERT_EQ(message.instructions[0].accounts.size(), 4ul); auto transaction = Transaction(message); transaction.signatures.clear(); - Signature signature("3vZ67CGoRYkuT76TtpP2VrtTPBfnvG2xj6mUTvvux46qbnpThgQDgm27nC3yQVUZrABFjT9Qo7vA74tCjtV5P9Xg"); + auto signature = Base58::decode("3vZ67CGoRYkuT76TtpP2VrtTPBfnvG2xj6mUTvvux46qbnpThgQDgm27nC3yQVUZrABFjT9Qo7vA74tCjtV5P9Xg"); transaction.signatures.push_back(signature); auto expectedString = From 55f1225168fe4edc83dae17e745f518aec5f3c63 Mon Sep 17 00:00:00 2001 From: Sztergbaum Roman Date: Thu, 2 Mar 2023 15:27:43 +0100 Subject: [PATCH 207/497] [Tron]: Staking V2 (#2932) --- src/Tron/Protobuf/TronInternal.proto | 38 +++++- src/Tron/Serialization.cpp | 72 ++++++++++++ src/Tron/Signer.cpp | 104 ++++++++++++++++- src/proto/Tron.proto | 61 ++++++++++ tests/chains/Tron/SignerTests.cpp | 166 +++++++++++++++++++++++++++ 5 files changed, 439 insertions(+), 2 deletions(-) diff --git a/src/Tron/Protobuf/TronInternal.proto b/src/Tron/Protobuf/TronInternal.proto index 88bc5675912..f2be7207561 100644 --- a/src/Tron/Protobuf/TronInternal.proto +++ b/src/Tron/Protobuf/TronInternal.proto @@ -17,6 +17,11 @@ message Transaction { WithdrawBalanceContract = 13; UnfreezeAssetContract = 14; TriggerSmartContract = 31; + FreezeBalanceV2Contract = 54; + UnfreezeBalanceV2Contract = 55; + WithdrawExpireUnfreezeContract = 56; + DelegateResourceContract = 57; + UnDelegateResourceContract = 58; } ContractType type = 1; google.protobuf.Any parameter = 2; @@ -78,6 +83,12 @@ message FreezeBalanceContract { bytes receiver_address = 15; } +message FreezeBalanceV2Contract { + bytes owner_address = 1; + int64 frozen_balance = 2; + ResourceCode resource = 3; +} + message UnfreezeBalanceContract { bytes owner_address = 1; @@ -85,6 +96,31 @@ message UnfreezeBalanceContract { bytes receiver_address = 15; } +message UnfreezeBalanceV2Contract { + bytes owner_address = 1; + int64 unfreeze_balance = 2; + ResourceCode resource = 3; +} + +message WithdrawExpireUnfreezeContract { + bytes owner_address = 1; +} + +message DelegateResourceContract { + bytes owner_address = 1; + ResourceCode resource = 2; + int64 balance = 3; + bytes receiver_address = 4; + bool lock = 5; +} + +message UnDelegateResourceContract { + bytes owner_address = 1; + ResourceCode resource = 2; + int64 balance = 3; + bytes receiver_address = 4; +} + message UnfreezeAssetContract { bytes owner_address = 1; } @@ -117,4 +153,4 @@ message TriggerSmartContract { bytes data = 4; int64 call_token_value = 5; int64 token_id = 6; -} \ No newline at end of file +} diff --git a/src/Tron/Serialization.cpp b/src/Tron/Serialization.cpp index 36bfe251f69..270ffb22481 100644 --- a/src/Tron/Serialization.cpp +++ b/src/Tron/Serialization.cpp @@ -93,6 +93,14 @@ json valueJSON(const protocol::FreezeBalanceContract& contract) { return valueJSON; } +json valueJSON(const protocol::FreezeBalanceV2Contract& contract) { + json valueJSON; + valueJSON["owner_address"] = hex(contract.owner_address()); + valueJSON["frozen_balance"] = contract.frozen_balance(); + valueJSON["resource"] = protocol::ResourceCode_Name(contract.resource()); + return valueJSON; +} + json valueJSON(const protocol::UnfreezeBalanceContract& contract) { json valueJSON; valueJSON["owner_address"] = hex(contract.owner_address()); @@ -102,6 +110,40 @@ json valueJSON(const protocol::UnfreezeBalanceContract& contract) { return valueJSON; } +json valueJSON(const protocol::UnfreezeBalanceV2Contract& contract) { + json valueJSON; + valueJSON["owner_address"] = hex(contract.owner_address()); + valueJSON["resource"] = protocol::ResourceCode_Name(contract.resource()); + valueJSON["unfreeze_balance"] = contract.unfreeze_balance(); + + return valueJSON; +} + +json valueJSON(const protocol::DelegateResourceContract& contract) { + json valueJSON; + valueJSON["owner_address"] = hex(contract.owner_address()); + valueJSON["receiver_address"] = hex(contract.receiver_address()); + valueJSON["resource"] = protocol::ResourceCode_Name(contract.resource()); + valueJSON["balance"] = contract.balance(); + valueJSON["lock"] = contract.lock(); + return valueJSON; +} + +json valueJSON(const protocol::UnDelegateResourceContract& contract) { + json valueJSON; + valueJSON["owner_address"] = hex(contract.owner_address()); + valueJSON["receiver_address"] = hex(contract.receiver_address()); + valueJSON["resource"] = protocol::ResourceCode_Name(contract.resource()); + valueJSON["balance"] = contract.balance(); + return valueJSON; +} + +json valueJSON(const protocol::WithdrawExpireUnfreezeContract& contract) { + json valueJSON; + valueJSON["owner_address"] = hex(contract.owner_address()); + return valueJSON; +} + json valueJSON(const protocol::WithdrawBalanceContract& contract) { json valueJSON; valueJSON["owner_address"] = hex(contract.owner_address()); @@ -169,12 +211,42 @@ json parameterJSON(const google::protobuf::Any& parameter, const protocol::Trans paramJSON["value"] = valueJSON(contract); break; } + case protocol::Transaction::Contract::FreezeBalanceV2Contract: { + protocol::FreezeBalanceV2Contract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } case protocol::Transaction::Contract::UnfreezeBalanceContract: { protocol::UnfreezeBalanceContract contract; parameter.UnpackTo(&contract); paramJSON["value"] = valueJSON(contract); break; } + case protocol::Transaction::Contract::UnfreezeBalanceV2Contract: { + protocol::UnfreezeBalanceV2Contract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } + case protocol::Transaction::Contract::WithdrawExpireUnfreezeContract: { + protocol::WithdrawExpireUnfreezeContract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } + case protocol::Transaction::Contract::DelegateResourceContract: { + protocol::DelegateResourceContract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } + case protocol::Transaction::Contract::UnDelegateResourceContract: { + protocol::UnDelegateResourceContract contract; + parameter.UnpackTo(&contract); + paramJSON["value"] = valueJSON(contract); + break; + } case protocol::Transaction::Contract::WithdrawBalanceContract: { protocol::WithdrawBalanceContract contract; parameter.UnpackTo(&contract); diff --git a/src/Tron/Signer.cpp b/src/Tron/Signer.cpp index b3278891aea..e2b4a987399 100644 --- a/src/Tron/Signer.cpp +++ b/src/Tron/Signer.cpp @@ -70,6 +70,20 @@ protocol::FreezeBalanceContract to_internal(const Proto::FreezeBalanceContract& return internal; } +protocol::FreezeBalanceV2Contract to_internal(const Proto::FreezeBalanceV2Contract& freezeContract) { + auto internal = protocol::FreezeBalanceV2Contract(); + auto resource = protocol::ResourceCode(); + const auto ownerAddress = Base58::decodeCheck(freezeContract.owner_address()); + + protocol::ResourceCode_Parse(freezeContract.resource(), &resource); + + internal.set_resource(resource); + internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); + internal.set_frozen_balance(freezeContract.frozen_balance()); + + return internal; +} + protocol::UnfreezeBalanceContract to_internal(const Proto::UnfreezeBalanceContract& unfreezeContract) { auto internal = protocol::UnfreezeBalanceContract(); auto resource = protocol::ResourceCode(); @@ -85,6 +99,60 @@ protocol::UnfreezeBalanceContract to_internal(const Proto::UnfreezeBalanceContra return internal; } +protocol::UnfreezeBalanceV2Contract to_internal(const Proto::UnfreezeBalanceV2Contract& unfreezeContract) { + auto internal = protocol::UnfreezeBalanceV2Contract(); + auto resource = protocol::ResourceCode(); + const auto ownerAddress = Base58::decodeCheck(unfreezeContract.owner_address()); + + protocol::ResourceCode_Parse(unfreezeContract.resource(), &resource); + + internal.set_resource(resource); + internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); + internal.set_unfreeze_balance(unfreezeContract.unfreeze_balance()); + + return internal; +} + +protocol::DelegateResourceContract to_internal(const Proto::DelegateResourceContract& delegateContract) { + auto internal = protocol::DelegateResourceContract(); + auto resource = protocol::ResourceCode(); + const auto ownerAddress = Base58::decodeCheck(delegateContract.owner_address()); + const auto receiverAddress = Base58::decodeCheck(delegateContract.receiver_address()); + + protocol::ResourceCode_Parse(delegateContract.resource(), &resource); + + internal.set_resource(resource); + internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); + internal.set_receiver_address(receiverAddress.data(), receiverAddress.size()); + internal.set_balance(delegateContract.balance()); + internal.set_lock(delegateContract.lock()); + + return internal; +} + +protocol::UnDelegateResourceContract to_internal(const Proto::UnDelegateResourceContract& undelegateContract) { + auto internal = protocol::UnDelegateResourceContract(); + auto resource = protocol::ResourceCode(); + const auto ownerAddress = Base58::decodeCheck(undelegateContract.owner_address()); + const auto receiverAddress = Base58::decodeCheck(undelegateContract.receiver_address()); + + protocol::ResourceCode_Parse(undelegateContract.resource(), &resource); + + internal.set_resource(resource); + internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); + internal.set_receiver_address(receiverAddress.data(), receiverAddress.size()); + internal.set_balance(undelegateContract.balance()); + + return internal; +} + +protocol::WithdrawExpireUnfreezeContract to_internal(const Proto::WithdrawExpireUnfreezeContract& withdrawExpireUnfreezeContract) { + auto internal = protocol::WithdrawExpireUnfreezeContract(); + const auto ownerAddress = Base58::decodeCheck(withdrawExpireUnfreezeContract.owner_address()); + internal.set_owner_address(ownerAddress.data(), ownerAddress.size()); + return internal; +} + protocol::UnfreezeAssetContract to_internal(const Proto::UnfreezeAssetContract& unfreezeContract) { auto internal = protocol::UnfreezeAssetContract(); const auto ownerAddress = Base58::decodeCheck(unfreezeContract.owner_address()); @@ -229,14 +297,48 @@ Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept { google::protobuf::Any any; any.PackFrom(freeze_balance); *contract->mutable_parameter() = any; + } else if (input.transaction().has_freeze_balance_v2()) { + auto* contract = internal.mutable_raw_data()->add_contract(); + contract->set_type(protocol::Transaction_Contract_ContractType_FreezeBalanceV2Contract); + auto freeze_balance = to_internal(input.transaction().freeze_balance_v2()); + google::protobuf::Any any; + any.PackFrom(freeze_balance); + *contract->mutable_parameter() = any; } else if (input.transaction().has_unfreeze_balance()) { auto* contract = internal.mutable_raw_data()->add_contract(); contract->set_type(protocol::Transaction_Contract_ContractType_UnfreezeBalanceContract); - auto unfreeze_balance = to_internal(input.transaction().unfreeze_balance()); google::protobuf::Any any; any.PackFrom(unfreeze_balance); *contract->mutable_parameter() = any; + } else if (input.transaction().has_unfreeze_balance_v2()) { + auto* contract = internal.mutable_raw_data()->add_contract(); + contract->set_type(protocol::Transaction_Contract_ContractType_UnfreezeBalanceV2Contract); + auto unfreeze_balance = to_internal(input.transaction().unfreeze_balance_v2()); + google::protobuf::Any any; + any.PackFrom(unfreeze_balance); + *contract->mutable_parameter() = any; + } else if (input.transaction().has_withdraw_expire_unfreeze()) { + auto* contract = internal.mutable_raw_data()->add_contract(); + contract->set_type(protocol::Transaction_Contract_ContractType_WithdrawExpireUnfreezeContract); + auto withdraw_expire_unfreeze = to_internal(input.transaction().withdraw_expire_unfreeze()); + google::protobuf::Any any; + any.PackFrom(withdraw_expire_unfreeze); + *contract->mutable_parameter() = any; + } else if (input.transaction().has_delegate_resource()) { + auto* contract = internal.mutable_raw_data()->add_contract(); + contract->set_type(protocol::Transaction_Contract_ContractType_DelegateResourceContract); + auto delegate_resource = to_internal(input.transaction().delegate_resource()); + google::protobuf::Any any; + any.PackFrom(delegate_resource); + *contract->mutable_parameter() = any; + } else if (input.transaction().has_undelegate_resource()) { + auto* contract = internal.mutable_raw_data()->add_contract(); + contract->set_type(protocol::Transaction_Contract_ContractType_UnDelegateResourceContract); + auto undelegate_resource = to_internal(input.transaction().undelegate_resource()); + google::protobuf::Any any; + any.PackFrom(undelegate_resource); + *contract->mutable_parameter() = any; } else if (input.transaction().has_unfreeze_asset()) { auto* contract = internal.mutable_raw_data()->add_contract(); contract->set_type(protocol::Transaction_Contract_ContractType_UnfreezeAssetContract); diff --git a/src/proto/Tron.proto b/src/proto/Tron.proto index 7ed7ce37723..63b9dcd0825 100644 --- a/src/proto/Tron.proto +++ b/src/proto/Tron.proto @@ -63,6 +63,62 @@ message FreezeBalanceContract { string receiver_address = 15; } +// stake TRX to obtain TRON Power (voting rights) and bandwidth or energy. +message FreezeBalanceV2Contract { + // Address of transaction initiator, data type is string + string owner_address = 1; + + // Amount of TRX to be staked, unit is sun, data type is uint256 + int64 frozen_balance = 2; + + // Resource type, "BANDWIDTH" or "ENERGY", data type is string + string resource = 3; +} + +// Unstake TRX to release bandwidth and energy and at the same time TRON Power will be reduced and all corresponding votes will be canceled. +message UnfreezeBalanceV2Contract { + // Address of transaction initiator, data type is string + string owner_address = 1; + // Amount of TRX to be unstaked, unit is sun, data type is uint256 + int64 unfreeze_balance = 2; + // Resource type, "BANDWIDTH" or "ENERGY", data type is string + string resource = 3; +} + +// withdraw unfrozen balance +message WithdrawExpireUnfreezeContract { + // Address of transaction initiator, data type is string + string owner_address = 1; +} + +// delegate resource +message DelegateResourceContract { + // Address of transaction initiator, data type is string + string owner_address = 1; + // Resource type, "BANDWIDTH" or "ENERGY", data type is string + string resource = 2; + // Amount of TRX staked for resource to be delegated, unit is sun, data type is uint256 + int64 balance = 3; + // Receiver address of resource to be delegated to + string receiver_address = 4; + // Whether it is locked, if it is set to true, the delegated resources cannot be undelegated within 3 days. + // When the lock time is not over, if the owner delegates the same resources using the lock to the same address, + // the lock time will be reset to 3 days + bool lock = 5; +} + +// undelegate resource +message UnDelegateResourceContract { + // Address of transaction initiator, data type is string + string owner_address = 1; + // Resource type, "BANDWIDTH" or "ENERGY", data type is string + string resource = 2; + // Amount of TRX staked for resource to be undelegated, unit is sun, data type is uint256 + int64 balance = 3; + // Receiver address of resource to be delegated to, data type is string + string receiver_address = 4; +} + // Unfreeze balance message UnfreezeBalanceContract { // Sender address @@ -185,6 +241,11 @@ message Transaction { VoteWitnessContract vote_witness = 17; TriggerSmartContract trigger_smart_contract = 18; TransferTRC20Contract transfer_trc20_contract = 19; + FreezeBalanceV2Contract freeze_balance_v2 = 20; + UnfreezeBalanceV2Contract unfreeze_balance_v2 = 21; + WithdrawExpireUnfreezeContract withdraw_expire_unfreeze = 23; + DelegateResourceContract delegate_resource = 24; + UnDelegateResourceContract undelegate_resource = 25; } } diff --git a/tests/chains/Tron/SignerTests.cpp b/tests/chains/Tron/SignerTests.cpp index 69dc5c37cb5..bd7246d46d8 100644 --- a/tests/chains/Tron/SignerTests.cpp +++ b/tests/chains/Tron/SignerTests.cpp @@ -5,6 +5,7 @@ // file LICENSE at the root of the source code distribution tree. #include "Bitcoin/Address.h" +#include "Tron/Address.h" #include "HexCoding.h" #include "PrivateKey.h" #include "uint256.h" @@ -80,6 +81,171 @@ TEST(TronSigner, SignTransfer) { ASSERT_EQ(hex(output.signature()), "ede769f6df28aefe6a846be169958c155e23e7e5c9621d2e8dce1719b4d952b63e8a8bf9f00e41204ac1bf69b1a663dacdf764367e48e4a5afcd6b055a747fb200"); } +TEST(TronSigner, SignFreezeBalanceV2) { + // Successfully broadcasted https://nile.tronscan.org/#/transaction/3a46321487ce1fd115da38b3431006ea529f65ef2507f19233f5a23c05abd01d + auto input = Proto::SigningInput(); + auto& transaction = *input.mutable_transaction(); + + auto& freeze = *transaction.mutable_freeze_balance_v2(); + freeze.set_owner_address("TWWb9EjUWai17YEVB7FR8hreupYJKG9sMR"); + freeze.set_frozen_balance(10000000); + freeze.set_resource("ENERGY"); + + transaction.set_timestamp(1676983541337); + transaction.set_expiration(1676983599000); + + auto& blockHeader = *transaction.mutable_block_header(); + blockHeader.set_timestamp(1676983485000); + const auto txTrieRoot = parse_hex("9b54db7f84bd19bbad9ff1fccef894c1aade6879450e9e9e2accec751eaa1f52"); + blockHeader.set_tx_trie_root(txTrieRoot.data(), txTrieRoot.size()); + const auto parentHash = parse_hex("00000000020cd4c13a67497a3a433a3105bc5a73a041ee3da98407d5a2a2bf1b"); + blockHeader.set_parent_hash(parentHash.data(), parentHash.size()); + blockHeader.set_number(34395330); + const auto witnessAddress = parse_hex("4150d3765e4e670727ebac9d5b598f74b75a3d54a7"); + blockHeader.set_witness_address(witnessAddress.data(), witnessAddress.size()); + blockHeader.set_version(26); + + const auto privateKey = PrivateKey(parse_hex("75065f100e38d3f3b4c5c4235834ba8216de62272a4f03532c44b31a5734360a")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + + const auto output = Signer::sign(input); + + ASSERT_EQ(hex(output.id()), "3a46321487ce1fd115da38b3431006ea529f65ef2507f19233f5a23c05abd01d"); + ASSERT_EQ(hex(output.signature()), "d4b539a389f6721b4e9d0eb9f39b62a539069060e1af2a118f06b81737ad9cdb49d5b4fda85f10603012f8de3996da2a1234c21d74ac6ea5e60217d3c10b630900"); +} + +TEST(TronSigner, WithdrawExpireUnfreezeContract) { + // Successfully broadcasted https://nile.tronscan.org/#/transaction/65ff34192eebda9ba7013771ff2da1010615e348b70c046647f41afe865f00eb + auto input = Proto::SigningInput(); + auto& transaction = *input.mutable_transaction(); + + auto& freeze = *transaction.mutable_withdraw_expire_unfreeze(); + freeze.set_owner_address("TWWb9EjUWai17YEVB7FR8hreupYJKG9sMR"); + + transaction.set_timestamp(1677574466457); + transaction.set_expiration(1677574524000); + + auto& blockHeader = *transaction.mutable_block_header(); + blockHeader.set_timestamp(1677574410000); + const auto txTrieRoot = parse_hex("0000000000000000000000000000000000000000000000000000000000000000"); + blockHeader.set_tx_trie_root(txTrieRoot.data(), txTrieRoot.size()); + const auto parentHash = parse_hex("00000000020fce45738ef00be07c350c03d027851308bc19d61c32312c673d3d"); + blockHeader.set_parent_hash(parentHash.data(), parentHash.size()); + blockHeader.set_number(34590278); + const auto witnessAddress = parse_hex("41e7860196ad5b5718c1d6326babab039b70b8c1cd"); + blockHeader.set_witness_address(witnessAddress.data(), witnessAddress.size()); + blockHeader.set_version(27); + + const auto privateKey = PrivateKey(parse_hex("75065f100e38d3f3b4c5c4235834ba8216de62272a4f03532c44b31a5734360a")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + + const auto output = Signer::sign(input); + + ASSERT_EQ(hex(output.id()), "65ff34192eebda9ba7013771ff2da1010615e348b70c046647f41afe865f00eb"); + ASSERT_EQ(hex(output.signature()), "ef0361248c118b8afae9c4c8e6dfad1e63eec4fb6c182ae369fa3bbecc2ac29a292838949ad74300b2b7322a110ffd4458224e283181cf6d64df0324b068bb0001"); +} + +TEST(TronSigner, SignUnFreezeBalanceV2) { + // Successfully broadcasted https://nile.tronscan.org/#/transaction/3070adc1743e6fdd20e04a749cc2af691ca26d2ce70e40cc0886be03595f9eeb + auto input = Proto::SigningInput(); + auto& transaction = *input.mutable_transaction(); + + auto& freeze = *transaction.mutable_unfreeze_balance_v2(); + freeze.set_owner_address("TWWb9EjUWai17YEVB7FR8hreupYJKG9sMR"); + freeze.set_unfreeze_balance(510000000); + freeze.set_resource("ENERGY"); + + transaction.set_timestamp(1676992267490); + transaction.set_expiration(1676992326000); + + auto& blockHeader = *transaction.mutable_block_header(); + blockHeader.set_timestamp(1676992212000); + const auto txTrieRoot = parse_hex("4b1edc58d14a5c60c083365d8b77771ba626394b445c7a7b8b5d67330bb6c92d"); + blockHeader.set_tx_trie_root(txTrieRoot.data(), txTrieRoot.size()); + const auto parentHash = parse_hex("00000000020ce000354fbb346d676de268b3f83124381f8496835afe88da4a01"); + blockHeader.set_parent_hash(parentHash.data(), parentHash.size()); + blockHeader.set_number(34398209); + const auto witnessAddress = parse_hex("4194a21bec5d0e1dde2151475f72ed158a87eb4817"); + blockHeader.set_witness_address(witnessAddress.data(), witnessAddress.size()); + blockHeader.set_version(26); + + const auto privateKey = PrivateKey(parse_hex("75065f100e38d3f3b4c5c4235834ba8216de62272a4f03532c44b31a5734360a")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + + const auto output = Signer::sign(input); + + ASSERT_EQ(hex(output.id()), "3070adc1743e6fdd20e04a749cc2af691ca26d2ce70e40cc0886be03595f9eeb"); + ASSERT_EQ(hex(output.signature()), "10bc05c47102f1db1a3a4c0b4a6aba028d5a35dda4e505563c3f0ccf95a562cf18b53f7f7053c485299cfc599a432d1f0ee5554a56cd5981ccfff31d79b9868b00"); +} + +TEST(TronSigner, DelegateResourceContract) { + // Successfully broadcasted https://nile.tronscan.org/#/transaction/ceabcd0f105854c13aae12ba35c0766945713c29cee540be1239bb0f1f0cde2c + auto input = Proto::SigningInput(); + auto& transaction = *input.mutable_transaction(); + + auto& freeze = *transaction.mutable_delegate_resource(); + freeze.set_owner_address("TWWb9EjUWai17YEVB7FR8hreupYJKG9sMR"); + freeze.set_receiver_address("TPFfHr1CWfTcS9eugQXQmvqHNGufnjxjXP"); + freeze.set_balance(68000000); + freeze.set_resource("ENERGY"); + + transaction.set_timestamp(1676991607274); + transaction.set_expiration(1676991660000); + + auto& blockHeader = *transaction.mutable_block_header(); + blockHeader.set_timestamp(1676991546000); + const auto txTrieRoot = parse_hex("0000000000000000000000000000000000000000000000000000000000000000"); + blockHeader.set_tx_trie_root(txTrieRoot.data(), txTrieRoot.size()); + const auto parentHash = parse_hex("00000000020cdf260ff2357d814141106c375c101913c933c2b5c31a390db7fc"); + blockHeader.set_parent_hash(parentHash.data(), parentHash.size()); + blockHeader.set_number(34397991); + const auto witnessAddress = parse_hex("417d3601dbd9d033b034c154868acc2904d9c45565"); + blockHeader.set_witness_address(witnessAddress.data(), witnessAddress.size()); + blockHeader.set_version(26); + + const auto privateKey = PrivateKey(parse_hex("75065f100e38d3f3b4c5c4235834ba8216de62272a4f03532c44b31a5734360a")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + + const auto output = Signer::sign(input); + + ASSERT_EQ(hex(output.id()), "ceabcd0f105854c13aae12ba35c0766945713c29cee540be1239bb0f1f0cde2c"); + ASSERT_EQ(hex(output.signature()), "664500a76466497a442cecc0e9282a9234483f047c12a997b6206d7f6a9030c70b700c879d7948c4cbdfe339c2c81a29dea18e00e9916504196c1b20cf045ca300"); +} + +TEST(TronSigner, UnDelegateResourceContract) { + // Successfully broadcasted https://nile.tronscan.org/#/transaction/3609519cc700cf2446b5e048864abc4b45e2ba6b7f9f8890d471ba2876599d3b + auto input = Proto::SigningInput(); + auto& transaction = *input.mutable_transaction(); + + auto& freeze = *transaction.mutable_undelegate_resource(); + freeze.set_owner_address("TWWb9EjUWai17YEVB7FR8hreupYJKG9sMR"); + freeze.set_receiver_address("TPFfHr1CWfTcS9eugQXQmvqHNGufnjxjXP"); + freeze.set_balance(68000000); + freeze.set_resource("ENERGY"); + + transaction.set_timestamp(1676992063012); + transaction.set_expiration(1676992122000); + + auto& blockHeader = *transaction.mutable_block_header(); + blockHeader.set_timestamp(1676992008000); + const auto txTrieRoot = parse_hex("85a47017a4380e92d09bac0f8991031e8de13b8b65767a6f5372d3f0992eabcd"); + blockHeader.set_tx_trie_root(txTrieRoot.data(), txTrieRoot.size()); + const auto parentHash = parse_hex("00000000020cdfbe4d7f36fcbb3d96dd634987b897eaf885001dd62fd92eb263"); + blockHeader.set_parent_hash(parentHash.data(), parentHash.size()); + blockHeader.set_number(34398143); + const auto witnessAddress = parse_hex("4196409f85790883057edf03286d08e4aa608c0d0a"); + blockHeader.set_witness_address(witnessAddress.data(), witnessAddress.size()); + blockHeader.set_version(26); + + const auto privateKey = PrivateKey(parse_hex("75065f100e38d3f3b4c5c4235834ba8216de62272a4f03532c44b31a5734360a")); + input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size()); + + const auto output = Signer::sign(input); + + ASSERT_EQ(hex(output.id()), "3609519cc700cf2446b5e048864abc4b45e2ba6b7f9f8890d471ba2876599d3b"); + ASSERT_EQ(hex(output.signature()), "b08e32a704d5a366df499d283d407c428dd50e60665f54ecf967226b75bec37157e6bc23312af07fad9dd3551cd668ce027cc280932fd4772af89d6f0fecf11900"); +} + TEST(TronSigner, SignFreezeBalance) { auto input = Proto::SigningInput(); auto& transaction = *input.mutable_transaction(); From 366f65cd610238d460769d3efb98ce7dafca856c Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 2 Mar 2023 23:28:43 +0900 Subject: [PATCH 208/497] Add Kotlin Multiplatform sample (#2960) --- .github/workflows/kotlin-ci.yml | 7 + README.md | 7 +- samples/kmp/.gitignore | 10 + samples/kmp/androidApp/build.gradle.kts | 49 +++ .../androidApp/src/main/AndroidManifest.xml | 17 + .../example/kmpsample/android/MainActivity.kt | 40 ++ .../kmpsample/android/MyApplicationTheme.kt | 55 +++ .../androidApp/src/main/res/values/styles.xml | 3 + samples/kmp/build.gradle.kts | 11 + samples/kmp/gradle.properties | 13 + samples/kmp/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + samples/kmp/gradlew | 185 ++++++++ samples/kmp/gradlew.bat | 89 ++++ samples/kmp/iosApp/Podfile | 5 + samples/kmp/iosApp/Podfile.lock | 31 ++ .../iosApp/iosApp.xcodeproj/project.pbxproj | 399 ++++++++++++++++++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 98 +++++ .../iosApp/Assets.xcassets/Contents.json | 6 + samples/kmp/iosApp/iosApp/ContentView.swift | 16 + samples/kmp/iosApp/iosApp/Info.plist | 48 +++ .../Preview Assets.xcassets/Contents.json | 6 + samples/kmp/iosApp/iosApp/iOSApp.swift | 10 + samples/kmp/settings.gradle.kts | 37 ++ samples/kmp/shared/build.gradle.kts | 76 ++++ samples/kmp/shared/shared.podspec | 39 ++ .../kotlin/com/example/kmpsample/Platform.kt | 10 + .../kotlin/com/example/kmpsample/Platform.kt | 7 + .../kotlin/com/example/kmpsample/Sample.kt | 17 + .../kotlin/com/example/kmpsample/Platform.kt | 9 + 33 files changed, 1334 insertions(+), 1 deletion(-) create mode 100644 samples/kmp/.gitignore create mode 100644 samples/kmp/androidApp/build.gradle.kts create mode 100644 samples/kmp/androidApp/src/main/AndroidManifest.xml create mode 100644 samples/kmp/androidApp/src/main/java/com/example/kmpsample/android/MainActivity.kt create mode 100644 samples/kmp/androidApp/src/main/java/com/example/kmpsample/android/MyApplicationTheme.kt create mode 100644 samples/kmp/androidApp/src/main/res/values/styles.xml create mode 100644 samples/kmp/build.gradle.kts create mode 100644 samples/kmp/gradle.properties create mode 100644 samples/kmp/gradle/wrapper/gradle-wrapper.jar create mode 100644 samples/kmp/gradle/wrapper/gradle-wrapper.properties create mode 100755 samples/kmp/gradlew create mode 100644 samples/kmp/gradlew.bat create mode 100644 samples/kmp/iosApp/Podfile create mode 100644 samples/kmp/iosApp/Podfile.lock create mode 100644 samples/kmp/iosApp/iosApp.xcodeproj/project.pbxproj create mode 100644 samples/kmp/iosApp/iosApp.xcworkspace/contents.xcworkspacedata create mode 100644 samples/kmp/iosApp/iosApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 samples/kmp/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 samples/kmp/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 samples/kmp/iosApp/iosApp/Assets.xcassets/Contents.json create mode 100644 samples/kmp/iosApp/iosApp/ContentView.swift create mode 100644 samples/kmp/iosApp/iosApp/Info.plist create mode 100644 samples/kmp/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json create mode 100644 samples/kmp/iosApp/iosApp/iOSApp.swift create mode 100644 samples/kmp/settings.gradle.kts create mode 100644 samples/kmp/shared/build.gradle.kts create mode 100644 samples/kmp/shared/shared.podspec create mode 100644 samples/kmp/shared/src/androidMain/kotlin/com/example/kmpsample/Platform.kt create mode 100644 samples/kmp/shared/src/commonMain/kotlin/com/example/kmpsample/Platform.kt create mode 100644 samples/kmp/shared/src/commonMain/kotlin/com/example/kmpsample/Sample.kt create mode 100644 samples/kmp/shared/src/iosMain/kotlin/com/example/kmpsample/Platform.kt diff --git a/.github/workflows/kotlin-ci.yml b/.github/workflows/kotlin-ci.yml index 3e88aa6aa45..6522f2224d3 100644 --- a/.github/workflows/kotlin-ci.yml +++ b/.github/workflows/kotlin-ci.yml @@ -46,3 +46,10 @@ jobs: - name: Build Kotlin Multiplatform run: tools/kotlin-build + + - name: Build KMP Sample + run: ./gradlew assemble + working-directory: samples/kmp + env: + GITHUB_USER: ${{ github.actor }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 2b39eab1cdc..91c36caa788 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,9 @@ Swift for iOS and Java (Kotlin) for Android. ![Android CI](https://github.com/trustwallet/wallet-core/workflows/Android%20CI/badge.svg) ![Linux CI](https://github.com/trustwallet/wallet-core/workflows/Linux%20CI/badge.svg) ![Wasm CI](https://github.com/trustwallet/wallet-core/workflows/Wasm%20CI/badge.svg) +![Kotlin CI](https://github.com/trustwallet/wallet-core/workflows/Kotlin%20CI/badge.svg) ![Docker CI](https://github.com/trustwallet/wallet-core/workflows/Docker%20CI/badge.svg) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=TrustWallet_wallet-core&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=TrustWallet_wallet-core) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/trustwallet/wallet-core) ![GitHub](https://img.shields.io/github/license/TrustWallet/wallet-core.svg) @@ -62,7 +64,7 @@ Or add remote url + `master` branch, it points to recent (not always latest) bin .package(name: "WalletCore", url: "https://github.com/trustwallet/wallet-core", .branchItem("master")), ``` -Then add libraries to target's `dependencies`: +Then add libraries to target's `dependencies`: ```swift .product(name: "WalletCore", package: "WalletCore"), @@ -87,6 +89,9 @@ npm install @trustwallet/wallet-core Please check out the [Go integration sample](https://github.com/trustwallet/wallet-core/tree/master/samples/go). +## Kotlin Multipleplatform (beta) + +Please check out the [Kotlin Multiplatform sample](https://github.com/trustwallet/wallet-core/tree/master/samples/kmp) # Projects diff --git a/samples/kmp/.gitignore b/samples/kmp/.gitignore new file mode 100644 index 00000000000..e510fa99de5 --- /dev/null +++ b/samples/kmp/.gitignore @@ -0,0 +1,10 @@ +*.iml +.gradle +.idea +.DS_Store +build +captures +.externalNativeBuild +.cxx +local.properties +xcuserdata \ No newline at end of file diff --git a/samples/kmp/androidApp/build.gradle.kts b/samples/kmp/androidApp/build.gradle.kts new file mode 100644 index 00000000000..24d6a52c14b --- /dev/null +++ b/samples/kmp/androidApp/build.gradle.kts @@ -0,0 +1,49 @@ +plugins { + id("com.android.application") + kotlin("android") +} + +android { + namespace = "com.example.kmpsample.android" + compileSdk = 33 + defaultConfig { + applicationId = "com.example.kmpsample.android" + minSdk = 24 + targetSdk = 33 + versionCode = 1 + versionName = "1.0" + } + buildFeatures { + compose = true + } + composeOptions { + kotlinCompilerExtensionVersion = "1.4.0" + } + packagingOptions { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } + buildTypes { + getByName("release") { + isMinifyEnabled = false + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + implementation(project(":shared")) + implementation("androidx.compose.ui:ui:1.3.1") + implementation("androidx.compose.ui:ui-tooling:1.3.1") + implementation("androidx.compose.ui:ui-tooling-preview:1.3.1") + implementation("androidx.compose.foundation:foundation:1.3.1") + implementation("androidx.compose.material:material:1.3.1") + implementation("androidx.activity:activity-compose:1.6.1") +} \ No newline at end of file diff --git a/samples/kmp/androidApp/src/main/AndroidManifest.xml b/samples/kmp/androidApp/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..22d1facc822 --- /dev/null +++ b/samples/kmp/androidApp/src/main/AndroidManifest.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/kmp/androidApp/src/main/java/com/example/kmpsample/android/MainActivity.kt b/samples/kmp/androidApp/src/main/java/com/example/kmpsample/android/MainActivity.kt new file mode 100644 index 00000000000..1ab49166253 --- /dev/null +++ b/samples/kmp/androidApp/src/main/java/com/example/kmpsample/android/MainActivity.kt @@ -0,0 +1,40 @@ +package com.example.kmpsample.android + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.example.kmpsample.Sample + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + MyApplicationTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colors.background + ) { + GreetingView(Sample().greet()) + } + } + } + } +} + +@Composable +fun GreetingView(text: String) { + Text(text = text) +} + +@Preview +@Composable +fun DefaultPreview() { + MyApplicationTheme { + GreetingView("Hello, Android!") + } +} diff --git a/samples/kmp/androidApp/src/main/java/com/example/kmpsample/android/MyApplicationTheme.kt b/samples/kmp/androidApp/src/main/java/com/example/kmpsample/android/MyApplicationTheme.kt new file mode 100644 index 00000000000..a0929dcde96 --- /dev/null +++ b/samples/kmp/androidApp/src/main/java/com/example/kmpsample/android/MyApplicationTheme.kt @@ -0,0 +1,55 @@ +package com.example.kmpsample.android + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Shapes +import androidx.compose.material.Typography +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun MyApplicationTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + val colors = if (darkTheme) { + darkColors( + primary = Color(0xFFBB86FC), + primaryVariant = Color(0xFF3700B3), + secondary = Color(0xFF03DAC5) + ) + } else { + lightColors( + primary = Color(0xFF6200EE), + primaryVariant = Color(0xFF3700B3), + secondary = Color(0xFF03DAC5) + ) + } + val typography = Typography( + body1 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp + ) + ) + val shapes = Shapes( + small = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(4.dp), + large = RoundedCornerShape(0.dp) + ) + + MaterialTheme( + colors = colors, + typography = typography, + shapes = shapes, + content = content + ) +} diff --git a/samples/kmp/androidApp/src/main/res/values/styles.xml b/samples/kmp/androidApp/src/main/res/values/styles.xml new file mode 100644 index 00000000000..6b4fa3d08e0 --- /dev/null +++ b/samples/kmp/androidApp/src/main/res/values/styles.xml @@ -0,0 +1,3 @@ + +